Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 1169)
@@ -182,5 +182,5 @@
 
     /**
-     * Remove the specified layer from the map. If it is the last layer, 
+     * Remove the specified layer from the map. If it is the last layer,
      * remove the map as well.
      */
@@ -219,5 +219,5 @@
 
     /**
-     * Load all plugins specified in preferences. If the parameter is 
+     * Load all plugins specified in preferences. If the parameter is
      * <code>true</code>, all early plugins are loaded (before constructor).
      */
@@ -281,8 +281,8 @@
                 Main.pref.put("pluginmanager.lastupdate",Long.toString(tim));
             } else if (d > maxTime) {
-                JOptionPane.showMessageDialog(Main.parent, 
-                   "<html>" + 
+                JOptionPane.showMessageDialog(Main.parent,
+                   "<html>" +
                    tr("Last plugin update more than {0} days ago.", d) +
-                   "<br><em>" + 
+                   "<br><em>" +
                    tr("(You can change the number of days after which this warning appears<br>by setting the config option 'pluginmanager.warntime'.)") +
                    "</html>");
@@ -512,6 +512,6 @@
         } else if (os.toLowerCase().startsWith("windows")) {
             platform = new PlatformHookWindows();
-        } else if (os.equals("Linux") || os.equals("Solaris") || 
-            os.equals("SunOS") || os.equals("AIX") || 
+        } else if (os.equals("Linux") || os.equals("Solaris") ||
+            os.equals("SunOS") || os.equals("AIX") ||
             os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) {
             platform = new PlatformHookUnixoid();
Index: trunk/src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 1169)
@@ -51,8 +51,8 @@
 public class AboutAction extends JosmAction {
 
-	private static final String version;
-
-	private final static JTextArea revision;
-	private static String time;
+    private static final String version;
+
+    private final static JTextArea revision;
+    private static String time;
 
     static {
@@ -60,5 +60,5 @@
         if(u == null) {
             try {
-                u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString() 
+                u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString()
                         + "!/META-INF/MANIFEST.MF");
             } catch (MalformedURLException e) {
@@ -66,23 +66,23 @@
             }
         }
-		revision = loadFile(u);
-
-		Pattern versionPattern = Pattern.compile(".*?(?:Revision|Main-Version): ([0-9]*(?: SVN)?).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
-		Matcher match = versionPattern.matcher(revision.getText());
-		version = match.matches() ? match.group(1) : tr("UNKNOWN");
-
-		Pattern timePattern = Pattern.compile(".*?(?:Last Changed Date|Main-Date): ([^\n]*).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
-		match = timePattern.matcher(revision.getText());
-		time = match.matches() ? match.group(1) : tr("UNKNOWN");
-	}
-
-	/**
-	 * Return string describing version.
-	 * Note that the strinc contains the version number plus an optional suffix of " SVN" to indicate an unofficial development build.
-	 * @return version string
-	 */
-	static public String getVersionString() {
-		return version;
-	}
+        revision = loadFile(u);
+
+        Pattern versionPattern = Pattern.compile(".*?(?:Revision|Main-Version): ([0-9]*(?: SVN)?).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
+        Matcher match = versionPattern.matcher(revision.getText());
+        version = match.matches() ? match.group(1) : tr("UNKNOWN");
+
+        Pattern timePattern = Pattern.compile(".*?(?:Last Changed Date|Main-Date): ([^\n]*).*", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
+        match = timePattern.matcher(revision.getText());
+        time = match.matches() ? match.group(1) : tr("UNKNOWN");
+    }
+
+    /**
+     * Return string describing version.
+     * Note that the strinc contains the version number plus an optional suffix of " SVN" to indicate an unofficial development build.
+     * @return version string
+     */
+    static public String getVersionString() {
+        return version;
+    }
 
     /**
@@ -99,5 +99,5 @@
         return myVersion;
     }
-	
+
     /**
      * check whether the version is a development build out of SVN.
@@ -107,119 +107,119 @@
         return version.endsWith(" SVN");
     }
-	
-	public AboutAction() {
-		super(tr("About"), "about", tr("Display the about screen."), Shortcut.registerShortcut("system:about", tr("About"), KeyEvent.VK_F1, Shortcut.GROUP_DIRECT, Shortcut.SHIFT_DEFAULT), true);
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		JTabbedPane about = new JTabbedPane();
-
-		JTextArea readme = loadFile(Main.class.getResource("/README"));
-		JTextArea contribution = loadFile(Main.class.getResource("/CONTRIBUTION"));
-
-		JPanel info = new JPanel(new GridBagLayout());
-		info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol().fill(GBC.HORIZONTAL));
-		info.add(new JLabel(tr("last change at {0}",time)), GBC.eol().fill(GBC.HORIZONTAL));
-		info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol().fill(GBC.HORIZONTAL));
-		info.add(GBC.glue(0,10), GBC.eol());
-		info.add(new JLabel(tr("Homepage")), GBC.std().insets(0,0,10,0));
-		info.add(new UrlLabel("http://josm.openstreetmap.de"), GBC.eol().fill(GBC.HORIZONTAL));
-		info.add(new JLabel(tr("Bug Reports")), GBC.std().insets(0,0,10,0));
-		info.add(new UrlLabel("http://josm.openstreetmap.de/newticket"), GBC.eol().fill(GBC.HORIZONTAL));
-		info.add(new JLabel(tr("News about JOSM")), GBC.std().insets(0,0,10,0));
-		info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL));
-
-		about.addTab(tr("Info"), info);
-		about.addTab(tr("Readme"), createScrollPane(readme));
-		about.addTab(tr("Revision"), createScrollPane(revision));
-		about.addTab(tr("Contribution"), createScrollPane(contribution));
-
-		JPanel pluginTab = new JPanel(new GridBagLayout());
-		for (final PluginProxy p : Main.plugins) {
-			String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : "");
-			pluginTab.add(new JLabel(name), GBC.std());
-			pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-			pluginTab.add(new JButton(new AbstractAction(tr("Information")){
-				public void actionPerformed(ActionEvent event) {
-					StringBuilder b = new StringBuilder();
-					for (Entry<String,String> e : p.info.attr.entrySet()) {
-						b.append(e.getKey());
-						b.append(": ");
-						b.append(e.getValue());
-						b.append("\n");
-					}
-					JTextArea a = new JTextArea(10,40);
-					a.setEditable(false);
-					a.setText(b.toString());
-					JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a));
-				}
-			}), GBC.eol());
-			JLabel label = new JLabel("<html><i>"+(p.info.description==null?tr("no description available"):p.info.description)+"</i></html>");
-			label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
-			label.setMaximumSize(new Dimension(450,1000));
-			pluginTab.add(label, GBC.eop().fill(GBC.HORIZONTAL));
-		}
-		about.addTab(tr("Plugins"), new JScrollPane(pluginTab));
-
-		about.setPreferredSize(new Dimension(500,300));
-
-		JOptionPane.showMessageDialog(Main.parent, about, tr("About JOSM..."),
-				JOptionPane.INFORMATION_MESSAGE, ImageProvider.get("logo"));
-	}
-
-	private JScrollPane createScrollPane(JTextArea area) {
-		area.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-		area.setOpaque(false);
-		JScrollPane sp = new JScrollPane(area);
-		sp.setBorder(null);
-		sp.setOpaque(false);
-		return sp;
-	}
-
-	/**
-	 * Retrieve the latest JOSM version from the JOSM homepage.
-	 * @return An string with the latest version or "UNKNOWN" in case
-	 * 		of problems (e.g. no internet connection).
-	 */
-	public static String checkLatestVersion() {
-		String latest;
-		try {
-			InputStream s = new URL("http://josm.openstreetmap.de/current").openStream();
-			latest = new BufferedReader(new InputStreamReader(s)).readLine();
-			s.close();
-		} catch (IOException x) {
-			x.printStackTrace();
-			return tr("UNKNOWN");
-		}
-		return latest;
-	}
-
-	/**
-	 * Load the specified resource into an TextArea and return it.
-	 * @param resource The resource url to load
-	 * @return	An read-only text area with the content of "resource"
-	 */
-	private static JTextArea loadFile(URL resource) {
-		JTextArea area = new JTextArea(tr("File could not be found."));
-		area.setEditable(false);
-		Font font = Font.getFont("monospaced");
-		if (font != null)
-			area.setFont(font);
-		if (resource == null)
-			return area;
-		BufferedReader in;
-		try {
-			in = new BufferedReader(new InputStreamReader(resource.openStream()));
-			StringBuilder sb = new StringBuilder();
-			for (String line = in.readLine(); line != null; line = in.readLine()) {
-				sb.append(line);
-				sb.append('\n');
-			}
-			area.setText(sb.toString());
-			area.setCaretPosition(0);
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return area;
-	}
+
+    public AboutAction() {
+        super(tr("About"), "about", tr("Display the about screen."), Shortcut.registerShortcut("system:about", tr("About"), KeyEvent.VK_F1, Shortcut.GROUP_DIRECT, Shortcut.SHIFT_DEFAULT), true);
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        JTabbedPane about = new JTabbedPane();
+
+        JTextArea readme = loadFile(Main.class.getResource("/README"));
+        JTextArea contribution = loadFile(Main.class.getResource("/CONTRIBUTION"));
+
+        JPanel info = new JPanel(new GridBagLayout());
+        info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol().fill(GBC.HORIZONTAL));
+        info.add(new JLabel(tr("last change at {0}",time)), GBC.eol().fill(GBC.HORIZONTAL));
+        info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol().fill(GBC.HORIZONTAL));
+        info.add(GBC.glue(0,10), GBC.eol());
+        info.add(new JLabel(tr("Homepage")), GBC.std().insets(0,0,10,0));
+        info.add(new UrlLabel("http://josm.openstreetmap.de"), GBC.eol().fill(GBC.HORIZONTAL));
+        info.add(new JLabel(tr("Bug Reports")), GBC.std().insets(0,0,10,0));
+        info.add(new UrlLabel("http://josm.openstreetmap.de/newticket"), GBC.eol().fill(GBC.HORIZONTAL));
+        info.add(new JLabel(tr("News about JOSM")), GBC.std().insets(0,0,10,0));
+        info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL));
+
+        about.addTab(tr("Info"), info);
+        about.addTab(tr("Readme"), createScrollPane(readme));
+        about.addTab(tr("Revision"), createScrollPane(revision));
+        about.addTab(tr("Contribution"), createScrollPane(contribution));
+
+        JPanel pluginTab = new JPanel(new GridBagLayout());
+        for (final PluginProxy p : Main.plugins) {
+            String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : "");
+            pluginTab.add(new JLabel(name), GBC.std());
+            pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
+            pluginTab.add(new JButton(new AbstractAction(tr("Information")){
+                public void actionPerformed(ActionEvent event) {
+                    StringBuilder b = new StringBuilder();
+                    for (Entry<String,String> e : p.info.attr.entrySet()) {
+                        b.append(e.getKey());
+                        b.append(": ");
+                        b.append(e.getValue());
+                        b.append("\n");
+                    }
+                    JTextArea a = new JTextArea(10,40);
+                    a.setEditable(false);
+                    a.setText(b.toString());
+                    JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a));
+                }
+            }), GBC.eol());
+            JLabel label = new JLabel("<html><i>"+(p.info.description==null?tr("no description available"):p.info.description)+"</i></html>");
+            label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
+            label.setMaximumSize(new Dimension(450,1000));
+            pluginTab.add(label, GBC.eop().fill(GBC.HORIZONTAL));
+        }
+        about.addTab(tr("Plugins"), new JScrollPane(pluginTab));
+
+        about.setPreferredSize(new Dimension(500,300));
+
+        JOptionPane.showMessageDialog(Main.parent, about, tr("About JOSM..."),
+                JOptionPane.INFORMATION_MESSAGE, ImageProvider.get("logo"));
+    }
+
+    private JScrollPane createScrollPane(JTextArea area) {
+        area.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        area.setOpaque(false);
+        JScrollPane sp = new JScrollPane(area);
+        sp.setBorder(null);
+        sp.setOpaque(false);
+        return sp;
+    }
+
+    /**
+     * Retrieve the latest JOSM version from the JOSM homepage.
+     * @return An string with the latest version or "UNKNOWN" in case
+     *      of problems (e.g. no internet connection).
+     */
+    public static String checkLatestVersion() {
+        String latest;
+        try {
+            InputStream s = new URL("http://josm.openstreetmap.de/current").openStream();
+            latest = new BufferedReader(new InputStreamReader(s)).readLine();
+            s.close();
+        } catch (IOException x) {
+            x.printStackTrace();
+            return tr("UNKNOWN");
+        }
+        return latest;
+    }
+
+    /**
+     * Load the specified resource into an TextArea and return it.
+     * @param resource The resource url to load
+     * @return  An read-only text area with the content of "resource"
+     */
+    private static JTextArea loadFile(URL resource) {
+        JTextArea area = new JTextArea(tr("File could not be found."));
+        area.setEditable(false);
+        Font font = Font.getFont("monospaced");
+        if (font != null)
+            area.setFont(font);
+        if (resource == null)
+            return area;
+        BufferedReader in;
+        try {
+            in = new BufferedReader(new InputStreamReader(resource.openStream()));
+            StringBuilder sb = new StringBuilder();
+            for (String line = in.readLine(); line != null; line = in.readLine()) {
+                sb.append(line);
+                sb.append('\n');
+            }
+            area.setText(sb.toString());
+            area.setCaretPosition(0);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return area;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java	(revision 1169)
@@ -41,5 +41,5 @@
 
 /**
- * This action displays a dialog where the user can enter a latitude and longitude, 
+ * This action displays a dialog where the user can enter a latitude and longitude,
  * and when ok is pressed, a new node is created at the specified position.
  */
@@ -47,17 +47,17 @@
 
     public AddNodeAction() {
-    	super(tr("Add Node"), "addnode", tr("Add a node by entering latitude and longitude."),
-		Shortcut.registerShortcut("addnode", tr("Edit: {0}", tr("Add Node")), KeyEvent.VK_D, Shortcut.GROUP_EDIT,
-		Shortcut.SHIFT_DEFAULT), true);
+        super(tr("Add Node"), "addnode", tr("Add a node by entering latitude and longitude."),
+        Shortcut.registerShortcut("addnode", tr("Edit: {0}", tr("Add Node")), KeyEvent.VK_D, Shortcut.GROUP_EDIT,
+        Shortcut.SHIFT_DEFAULT), true);
     }
 
-	public void actionPerformed(ActionEvent e) {   
+    public void actionPerformed(ActionEvent e) {
         JPanel p = new JPanel(new GridBagLayout());
         p.add(new JLabel("<html>"+
-                tr("Enter the coordinates for the new node.") + 
-                "<br>" + tr("Use decimal degrees.") + 
-                "<br>" + tr("Negative values denote Western/Southern hemisphere.")), 
+                tr("Enter the coordinates for the new node.") +
+                "<br>" + tr("Use decimal degrees.") +
+                "<br>" + tr("Negative values denote Western/Southern hemisphere.")),
                 GBC.eol());
-        
+
         p.add(new JLabel(tr("Latitude")), GBC.std().insets(0,10,5,0));
         final JTextField lat = new JTextField(12);
@@ -65,6 +65,6 @@
         p.add(new JLabel(tr("Longitude")), GBC.std().insets(0,0,5,10));
         final JTextField lon = new JTextField(12);
-        p.add(lon, GBC.eol().insets(0,0,0,10));    
-        
+        p.add(lon, GBC.eol().insets(0,0,0,10));
+
         Node nnew = null;
 
@@ -79,10 +79,10 @@
             } catch (Exception ex) { }
         }
-        
-		/* Now execute the commands to add the dupicated contents of the paste buffer to the map */
-		
-		Main.main.undoRedo.add(new AddCommand(nnew));
-		Main.ds.setSelected(nnew);
-		Main.map.mapView.repaint();
+
+        /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
+
+        Main.main.undoRedo.add(new AddCommand(nnew));
+        Main.ds.setSelected(nnew);
+        Main.map.mapView.repaint();
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(revision 1169)
@@ -24,5 +24,5 @@
 /**
  * Aligns all selected nodes within a circle. (Useful for roundabouts)
- * 
+ *
  * @author Matthew Newton
  * @author Petr Dlouhý
@@ -31,6 +31,6 @@
 
     public AlignInCircleAction() {
-        super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."), 
-                Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), 
+        super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."),
+                Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")),
                         KeyEvent.VK_O, Shortcut.GROUP_EDIT), true);
     }
Index: trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java	(revision 1169)
@@ -29,98 +29,98 @@
 public final class AlignInLineAction extends JosmAction {
 
-	public AlignInLineAction() {
-		super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."),
-		Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true);
-	}
+    public AlignInLineAction() {
+        super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."),
+        Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true);
+    }
 
-	/**
-	 * 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);
-			}
-		// special case if no single nodes are selected and exactly one way is:
-		// then use the way's nodes
-		if ((nodes.size() == 0) && (sel.size() == 1))
-			for (OsmPrimitive osm : sel)
-				if (osm instanceof Way) {
-					nodes.addAll(((Way)osm).nodes);
-					itnodes.addAll(((Way)osm).nodes);
-				}
-		if (nodes.size() < 3) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
-			return;
-		}
+    /**
+     * 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);
+            }
+        // special case if no single nodes are selected and exactly one way is:
+        // then use the way's nodes
+        if ((nodes.size() == 0) && (sel.size() == 1))
+            for (OsmPrimitive osm : sel)
+                if (osm instanceof Way) {
+                    nodes.addAll(((Way)osm).nodes);
+                    itnodes.addAll(((Way)osm).nodes);
+                }
+        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;
+        // 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;
+        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;
-				}
-			}
-		}
+        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);
+        // 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();
+        // 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>();
+        // 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();
+        // 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);
+            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;
-			}
+                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() ));
-		}
+            // 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.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
-		Main.map.repaint();
-	}
+        // Do it!
+        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
+        Main.map.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 1169)
@@ -47,5 +47,5 @@
     public AutoScaleAction(String mode) {
         super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)),
-				Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true);
+                Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true);
         String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1);
         putValue("help", "Action/AutoScale/" + modeHelp);
Index: trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 1169)
@@ -49,254 +49,254 @@
 public class CombineWayAction extends JosmAction implements SelectionChangedListener {
 
-	public CombineWayAction() {
-		super(tr("Combine Way"), "combineway", tr("Combine several ways into one."),
-		Shortcut.registerShortcut("tools:combineway", tr("Tool: {0}", tr("Combine Way")), KeyEvent.VK_C, Shortcut.GROUP_EDIT), true);
-		DataSet.selListeners.add(this);
-	}
-
-	public void actionPerformed(ActionEvent event) {
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-		LinkedList<Way> selectedWays = new LinkedList<Way>();
-
-		for (OsmPrimitive osm : selection)
-			if (osm instanceof Way)
-				selectedWays.add((Way)osm);
-
-		if (selectedWays.size() < 2) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two ways to combine."));
-			return;
-		}
-
-		// Check whether all ways have identical relationship membership. More
-		// specifically: If one of the selected ways is a member of relation X
-		// in role Y, then all selected ways must be members of X in role Y.
-
-		// FIXME: In a later revision, we should display some sort of conflict
-		// dialog like we do for tags, to let the user choose which relations
-		// should be kept.
-
-		// Step 1, iterate over all relations and figure out which of our
-		// selected ways are members of a relation.
-		HashMap<Pair<Relation,String>, HashSet<Way>> backlinks =
-			new HashMap<Pair<Relation,String>, HashSet<Way>>();
-		HashSet<Relation> relationsUsingWays = new HashSet<Relation>();
-		for (Relation r : Main.ds.relations) {
-			if (r.deleted || r.incomplete) continue;
-			for (RelationMember rm : r.members) {
-				if (rm.member instanceof Way) {
-					for(Way w : selectedWays) {
-						if (rm.member == w) {
-							Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
-							HashSet<Way> waylinks = new HashSet<Way>();
-							if (backlinks.containsKey(pair)) {
-								waylinks = backlinks.get(pair);
-							} else {
-								waylinks = new HashSet<Way>();
-								backlinks.put(pair, waylinks);
-							}
-							waylinks.add(w);
-
-							// this is just a cache for later use
-							relationsUsingWays.add(r);
-						}
-					}
-				}
-			}
-		}
-
-		// Complain to the user if the ways don't have equal memberships.
-		for (HashSet<Way> waylinks : backlinks.values()) {
-			if (!waylinks.containsAll(selectedWays)) {
-				int option = JOptionPane.showConfirmDialog(Main.parent,
-					tr("The selected ways have differing relation memberships.  "
-						+ "Do you still want to combine them?"),
-					tr("Combine ways with different memberships?"),
-					JOptionPane.YES_NO_OPTION);
-				if (option == JOptionPane.YES_OPTION)
-					break;
-				return;
-			}
-		}
-
-		// collect properties for later conflict resolving
-		Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
-		for (Way w : selectedWays) {
-			for (Entry<String,String> e : w.entrySet()) {
-				if (!props.containsKey(e.getKey()))
-					props.put(e.getKey(), new TreeSet<String>());
-				props.get(e.getKey()).add(e.getValue());
-			}
-		}
-
-		List<Node> nodeList = null;
-		Object firstTry = actuallyCombineWays(selectedWays, false);
-		if (firstTry instanceof List) {
-			nodeList = (List<Node>) firstTry;
-		} else {
-			Object secondTry = actuallyCombineWays(selectedWays, true);
-			if (secondTry instanceof List) {
-				int option = JOptionPane.showConfirmDialog(Main.parent,
-					tr("The ways can not be combined in their current directions.  "
-					+ "Do you want to reverse some of them?"), tr("Change directions?"),
-					JOptionPane.YES_NO_OPTION);
-				if (option != JOptionPane.YES_OPTION) {
-					return;
-				}
-				nodeList = (List<Node>) secondTry;
-			} else {
-				JOptionPane.showMessageDialog(Main.parent, secondTry);
-				return;
-			}
-		}
-
-		// Find the most appropriate way to modify.
-
-		// Eventually this might want to be the way with the longest
-		// history or the longest selected way but for now just attempt
-		// to reuse an existing id.
-		Way modifyWay = selectedWays.peek();
-		for (Way w : selectedWays) {
-			modifyWay = w;
-			if (w.id != 0) break;
-		}
-		Way newWay = new Way(modifyWay);
-
-		newWay.nodes.clear();
-		newWay.nodes.addAll(nodeList);
-
-		// display conflict dialog
-		Map<String, JComboBox> components = new HashMap<String, JComboBox>();
-		JPanel p = new JPanel(new GridBagLayout());
-		for (Entry<String, Set<String>> e : props.entrySet()) {
-			if (TigerUtils.isTigerTag(e.getKey())) {
-				String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
-				newWay.put(e.getKey(), combined);
-			} else if (e.getValue().size() > 1) {
-				if("created_by".equals(e.getKey()))
-				{
-					newWay.put("created_by", "JOSM");
-				}
-				else
-				{
-					JComboBox c = new JComboBox(e.getValue().toArray());
-					c.setEditable(true);
-					p.add(new JLabel(e.getKey()), GBC.std());
-					p.add(Box.createHorizontalStrut(10), GBC.std());
-					p.add(c, GBC.eol());
-					components.put(e.getKey(), c);
-				}
-			} else
-				newWay.put(e.getKey(), e.getValue().iterator().next());
-		}
-
-		if (!components.isEmpty()) {
-			int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
-			if (answer != JOptionPane.OK_OPTION)
-				return;
-			for (Entry<String, JComboBox> e : components.entrySet())
-				newWay.put(e.getKey(), e.getValue().getEditor().getItem().toString());
-		}
-
-		LinkedList<Command> cmds = new LinkedList<Command>();
-		LinkedList<Way> deletedWays = new LinkedList<Way>(selectedWays);
-		deletedWays.remove(modifyWay);
-		cmds.add(new DeleteCommand(deletedWays));
-		cmds.add(new ChangeCommand(modifyWay, newWay));
-
-		// modify all relations containing the now-deleted ways
-		for (Relation r : relationsUsingWays) {
-			Relation newRel = new Relation(r);
-			newRel.members.clear();
-			HashSet<String> rolesToReAdd = new HashSet<String>();
-			for (RelationMember rm : r.members) {
-				// Don't copy the member if it to one of our ways, just keep a
-				// note to re-add it later on.
-				if (selectedWays.contains(rm.member)) {
-					rolesToReAdd.add(rm.role);
-				} else {
-					newRel.members.add(rm);
-				}
-			}
-			for (String role : rolesToReAdd) {
-				newRel.members.add(new RelationMember(role, modifyWay));
-			}
-			cmds.add(new ChangeCommand(r, newRel));
-		}
-		Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds));
-		Main.ds.setSelected(modifyWay);
-	}
-
-	/**
-	 * @return a message if combining failed, else a list of nodes.
-	 */
-	private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) {
-		// Battle plan:
-		//  1. Split the ways into small chunks of 2 nodes and weed out
-		//	   duplicates.
-		//  2. Take a chunk and see if others could be appended or prepended,
-		//	   if so, do it and remove it from the list of remaining chunks.
-		//	   Rather, rinse, repeat.
-		//  3. If this algorithm does not produce a single way,
-		//     complain to the user.
-		//  4. Profit!
-
-		HashSet<Pair<Node,Node>> chunkSet = new HashSet<Pair<Node,Node>>();
-		for (Way w : ways)
-			chunkSet.addAll(w.getNodePairs(ignoreDirection));
-
-		LinkedList<Pair<Node,Node>> chunks = new LinkedList<Pair<Node,Node>>(chunkSet);
-
-		if (chunks.isEmpty()) {
-			return tr("All the ways were empty");
-		}
-
-		List<Node> nodeList = Pair.toArrayList(chunks.poll());
-		while (!chunks.isEmpty()) {
-			ListIterator<Pair<Node,Node>> it = chunks.listIterator();
-			boolean foundChunk = false;
-			while (it.hasNext()) {
-				Pair<Node,Node> curChunk = it.next();
-				if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append
-					nodeList.add(curChunk.b);
-				} else if (curChunk.b == nodeList.get(0)) { // prepend
-					nodeList.add(0, curChunk.a);
-				} else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append
-					nodeList.add(curChunk.a);
-				} else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend
-					nodeList.add(0, curChunk.b);
-				} else {
-					continue;
-				}
-
-				foundChunk = true;
-				it.remove();
-				break;
-			}
-			if (!foundChunk) break;
-		}
-
-		if (!chunks.isEmpty()) {
-			return tr("Could not combine ways "
-				+ "(They could not be merged into a single string of nodes)");
-		}
-
-		return nodeList;
-	}
-
-	/**
-	 * Enable the "Combine way" menu option if more then one way is selected
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		boolean first = false;
-		for (OsmPrimitive osm : newSelection) {
-			if (osm instanceof Way) {
-				if (first) {
-					setEnabled(true);
-					return;
-				}
-				first = true;
-			}
-		}
-		setEnabled(false);
-	}
+    public CombineWayAction() {
+        super(tr("Combine Way"), "combineway", tr("Combine several ways into one."),
+        Shortcut.registerShortcut("tools:combineway", tr("Tool: {0}", tr("Combine Way")), KeyEvent.VK_C, Shortcut.GROUP_EDIT), true);
+        DataSet.selListeners.add(this);
+    }
+
+    public void actionPerformed(ActionEvent event) {
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+        LinkedList<Way> selectedWays = new LinkedList<Way>();
+
+        for (OsmPrimitive osm : selection)
+            if (osm instanceof Way)
+                selectedWays.add((Way)osm);
+
+        if (selectedWays.size() < 2) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two ways to combine."));
+            return;
+        }
+
+        // Check whether all ways have identical relationship membership. More
+        // specifically: If one of the selected ways is a member of relation X
+        // in role Y, then all selected ways must be members of X in role Y.
+
+        // FIXME: In a later revision, we should display some sort of conflict
+        // dialog like we do for tags, to let the user choose which relations
+        // should be kept.
+
+        // Step 1, iterate over all relations and figure out which of our
+        // selected ways are members of a relation.
+        HashMap<Pair<Relation,String>, HashSet<Way>> backlinks =
+            new HashMap<Pair<Relation,String>, HashSet<Way>>();
+        HashSet<Relation> relationsUsingWays = new HashSet<Relation>();
+        for (Relation r : Main.ds.relations) {
+            if (r.deleted || r.incomplete) continue;
+            for (RelationMember rm : r.members) {
+                if (rm.member instanceof Way) {
+                    for(Way w : selectedWays) {
+                        if (rm.member == w) {
+                            Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
+                            HashSet<Way> waylinks = new HashSet<Way>();
+                            if (backlinks.containsKey(pair)) {
+                                waylinks = backlinks.get(pair);
+                            } else {
+                                waylinks = new HashSet<Way>();
+                                backlinks.put(pair, waylinks);
+                            }
+                            waylinks.add(w);
+
+                            // this is just a cache for later use
+                            relationsUsingWays.add(r);
+                        }
+                    }
+                }
+            }
+        }
+
+        // Complain to the user if the ways don't have equal memberships.
+        for (HashSet<Way> waylinks : backlinks.values()) {
+            if (!waylinks.containsAll(selectedWays)) {
+                int option = JOptionPane.showConfirmDialog(Main.parent,
+                    tr("The selected ways have differing relation memberships.  "
+                        + "Do you still want to combine them?"),
+                    tr("Combine ways with different memberships?"),
+                    JOptionPane.YES_NO_OPTION);
+                if (option == JOptionPane.YES_OPTION)
+                    break;
+                return;
+            }
+        }
+
+        // collect properties for later conflict resolving
+        Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
+        for (Way w : selectedWays) {
+            for (Entry<String,String> e : w.entrySet()) {
+                if (!props.containsKey(e.getKey()))
+                    props.put(e.getKey(), new TreeSet<String>());
+                props.get(e.getKey()).add(e.getValue());
+            }
+        }
+
+        List<Node> nodeList = null;
+        Object firstTry = actuallyCombineWays(selectedWays, false);
+        if (firstTry instanceof List) {
+            nodeList = (List<Node>) firstTry;
+        } else {
+            Object secondTry = actuallyCombineWays(selectedWays, true);
+            if (secondTry instanceof List) {
+                int option = JOptionPane.showConfirmDialog(Main.parent,
+                    tr("The ways can not be combined in their current directions.  "
+                    + "Do you want to reverse some of them?"), tr("Change directions?"),
+                    JOptionPane.YES_NO_OPTION);
+                if (option != JOptionPane.YES_OPTION) {
+                    return;
+                }
+                nodeList = (List<Node>) secondTry;
+            } else {
+                JOptionPane.showMessageDialog(Main.parent, secondTry);
+                return;
+            }
+        }
+
+        // Find the most appropriate way to modify.
+
+        // Eventually this might want to be the way with the longest
+        // history or the longest selected way but for now just attempt
+        // to reuse an existing id.
+        Way modifyWay = selectedWays.peek();
+        for (Way w : selectedWays) {
+            modifyWay = w;
+            if (w.id != 0) break;
+        }
+        Way newWay = new Way(modifyWay);
+
+        newWay.nodes.clear();
+        newWay.nodes.addAll(nodeList);
+
+        // display conflict dialog
+        Map<String, JComboBox> components = new HashMap<String, JComboBox>();
+        JPanel p = new JPanel(new GridBagLayout());
+        for (Entry<String, Set<String>> e : props.entrySet()) {
+            if (TigerUtils.isTigerTag(e.getKey())) {
+                String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
+                newWay.put(e.getKey(), combined);
+            } else if (e.getValue().size() > 1) {
+                if("created_by".equals(e.getKey()))
+                {
+                    newWay.put("created_by", "JOSM");
+                }
+                else
+                {
+                    JComboBox c = new JComboBox(e.getValue().toArray());
+                    c.setEditable(true);
+                    p.add(new JLabel(e.getKey()), GBC.std());
+                    p.add(Box.createHorizontalStrut(10), GBC.std());
+                    p.add(c, GBC.eol());
+                    components.put(e.getKey(), c);
+                }
+            } else
+                newWay.put(e.getKey(), e.getValue().iterator().next());
+        }
+
+        if (!components.isEmpty()) {
+            int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
+            if (answer != JOptionPane.OK_OPTION)
+                return;
+            for (Entry<String, JComboBox> e : components.entrySet())
+                newWay.put(e.getKey(), e.getValue().getEditor().getItem().toString());
+        }
+
+        LinkedList<Command> cmds = new LinkedList<Command>();
+        LinkedList<Way> deletedWays = new LinkedList<Way>(selectedWays);
+        deletedWays.remove(modifyWay);
+        cmds.add(new DeleteCommand(deletedWays));
+        cmds.add(new ChangeCommand(modifyWay, newWay));
+
+        // modify all relations containing the now-deleted ways
+        for (Relation r : relationsUsingWays) {
+            Relation newRel = new Relation(r);
+            newRel.members.clear();
+            HashSet<String> rolesToReAdd = new HashSet<String>();
+            for (RelationMember rm : r.members) {
+                // Don't copy the member if it to one of our ways, just keep a
+                // note to re-add it later on.
+                if (selectedWays.contains(rm.member)) {
+                    rolesToReAdd.add(rm.role);
+                } else {
+                    newRel.members.add(rm);
+                }
+            }
+            for (String role : rolesToReAdd) {
+                newRel.members.add(new RelationMember(role, modifyWay));
+            }
+            cmds.add(new ChangeCommand(r, newRel));
+        }
+        Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds));
+        Main.ds.setSelected(modifyWay);
+    }
+
+    /**
+     * @return a message if combining failed, else a list of nodes.
+     */
+    private Object actuallyCombineWays(List<Way> ways, boolean ignoreDirection) {
+        // Battle plan:
+        //  1. Split the ways into small chunks of 2 nodes and weed out
+        //     duplicates.
+        //  2. Take a chunk and see if others could be appended or prepended,
+        //     if so, do it and remove it from the list of remaining chunks.
+        //     Rather, rinse, repeat.
+        //  3. If this algorithm does not produce a single way,
+        //     complain to the user.
+        //  4. Profit!
+
+        HashSet<Pair<Node,Node>> chunkSet = new HashSet<Pair<Node,Node>>();
+        for (Way w : ways)
+            chunkSet.addAll(w.getNodePairs(ignoreDirection));
+
+        LinkedList<Pair<Node,Node>> chunks = new LinkedList<Pair<Node,Node>>(chunkSet);
+
+        if (chunks.isEmpty()) {
+            return tr("All the ways were empty");
+        }
+
+        List<Node> nodeList = Pair.toArrayList(chunks.poll());
+        while (!chunks.isEmpty()) {
+            ListIterator<Pair<Node,Node>> it = chunks.listIterator();
+            boolean foundChunk = false;
+            while (it.hasNext()) {
+                Pair<Node,Node> curChunk = it.next();
+                if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append
+                    nodeList.add(curChunk.b);
+                } else if (curChunk.b == nodeList.get(0)) { // prepend
+                    nodeList.add(0, curChunk.a);
+                } else if (ignoreDirection && curChunk.b == nodeList.get(nodeList.size() - 1)) { // append
+                    nodeList.add(curChunk.a);
+                } else if (ignoreDirection && curChunk.a == nodeList.get(0)) { // prepend
+                    nodeList.add(0, curChunk.b);
+                } else {
+                    continue;
+                }
+
+                foundChunk = true;
+                it.remove();
+                break;
+            }
+            if (!foundChunk) break;
+        }
+
+        if (!chunks.isEmpty()) {
+            return tr("Could not combine ways "
+                + "(They could not be merged into a single string of nodes)");
+        }
+
+        return nodeList;
+    }
+
+    /**
+     * Enable the "Combine way" menu option if more then one way is selected
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        boolean first = false;
+        for (OsmPrimitive osm : newSelection) {
+            if (osm instanceof Way) {
+                if (first) {
+                    setEnabled(true);
+                    return;
+                }
+                first = true;
+            }
+        }
+        setEnabled(false);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/CopyAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CopyAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/CopyAction.java	(revision 1169)
@@ -28,92 +28,92 @@
 public final class CopyAction extends JosmAction implements SelectionChangedListener {
 
-	private LinkedList<JosmAction> listeners;
+    private LinkedList<JosmAction> listeners;
 
-	public CopyAction() {
-		super(tr("Copy"), "copy",
-				tr("Copy selected objects to paste buffer."),
-				Shortcut.registerShortcut("system:copy", tr("Edit: {0}", tr("Copy")), KeyEvent.VK_C, Shortcut.GROUP_MENU), true);
-		setEnabled(false);
-		DataSet.selListeners.add(this);
-		listeners = new LinkedList<JosmAction>();
-	}
+    public CopyAction() {
+        super(tr("Copy"), "copy",
+                tr("Copy selected objects to paste buffer."),
+                Shortcut.registerShortcut("system:copy", tr("Edit: {0}", tr("Copy")), KeyEvent.VK_C, Shortcut.GROUP_MENU), true);
+        setEnabled(false);
+        DataSet.selListeners.add(this);
+        listeners = new LinkedList<JosmAction>();
+    }
 
-	@Override public void addListener(JosmAction a) {
-		listeners.add(a);
-	}
+    @Override public void addListener(JosmAction a) {
+        listeners.add(a);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		if (sel.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent,
-					tr("Please select something to copy."));
-			return;
-		}
+    public void actionPerformed(ActionEvent e) {
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        if (sel.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("Please select something to copy."));
+            return;
+        }
 
-		/* New pasteBuffer - will be assigned to the global one at the end */
-		final DataSet pasteBuffer = new DataSet();
-		final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
-		/* temporarily maps old nodes to new so we can do a true deep copy */
+        /* New pasteBuffer - will be assigned to the global one at the end */
+        final DataSet pasteBuffer = new DataSet();
+        final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
+        /* temporarily maps old nodes to new so we can do a true deep copy */
 
-		/* scan the selected objects, mapping them to copies; when copying a way or relation,
-		 * the copy references the copies of their child objects */
-		new Visitor(){
-			public void visit(Node n) {
-				/* check if already in pasteBuffer - e.g. two ways are selected which share a node;
-				 * or a way and a node in that way is selected, we'll see it twice, once via the
-				 * way and once directly; and so on. */
-				if (map.containsKey(n)) { return; }
-				Node nnew = new Node(n);
-				map.put(n, nnew);
-				pasteBuffer.addPrimitive(nnew);
-			}
-			public void visit(Way w) {
-				/* check if already in pasteBuffer - could have come from a relation, and directly etc. */
-				if (map.containsKey(w)) { return; }
-				Way wnew = new Way();
-				wnew.cloneFrom(w);
-				wnew.nodes.clear();
-				List<Node> nodes = new ArrayList<Node>();
-				for (Node n : w.nodes) {
-					if (! map.containsKey(n)) {
-						n.visit(this);
-					}
-					nodes.add((Node)map.get(n));
-				}
-				wnew.nodes.clear();
-				wnew.nodes.addAll(nodes);
-				pasteBuffer.addPrimitive(wnew);
-			}
-			public void visit(Relation e) {
-				if (map.containsKey(e)) { return; }
-				Relation enew = new Relation(e);
-				List<RelationMember> members = new ArrayList<RelationMember>();
-				for (RelationMember m : e.members) {
-					if (! map.containsKey(m.member)) {
-						m.member.visit(this);
-					}
-					RelationMember mnew = new RelationMember(m);
-					mnew.member = map.get(m.member);
-					members.add(mnew);
-				}
-				enew.members.addAll(members);
-				pasteBuffer.addPrimitive(enew);
-			}
-			public void visitAll() {
-				for (OsmPrimitive osm : Main.ds.getSelected())
-					osm.visit(this);
-			}
-		}.visitAll();
+        /* scan the selected objects, mapping them to copies; when copying a way or relation,
+         * the copy references the copies of their child objects */
+        new Visitor(){
+            public void visit(Node n) {
+                /* check if already in pasteBuffer - e.g. two ways are selected which share a node;
+                 * or a way and a node in that way is selected, we'll see it twice, once via the
+                 * way and once directly; and so on. */
+                if (map.containsKey(n)) { return; }
+                Node nnew = new Node(n);
+                map.put(n, nnew);
+                pasteBuffer.addPrimitive(nnew);
+            }
+            public void visit(Way w) {
+                /* check if already in pasteBuffer - could have come from a relation, and directly etc. */
+                if (map.containsKey(w)) { return; }
+                Way wnew = new Way();
+                wnew.cloneFrom(w);
+                wnew.nodes.clear();
+                List<Node> nodes = new ArrayList<Node>();
+                for (Node n : w.nodes) {
+                    if (! map.containsKey(n)) {
+                        n.visit(this);
+                    }
+                    nodes.add((Node)map.get(n));
+                }
+                wnew.nodes.clear();
+                wnew.nodes.addAll(nodes);
+                pasteBuffer.addPrimitive(wnew);
+            }
+            public void visit(Relation e) {
+                if (map.containsKey(e)) { return; }
+                Relation enew = new Relation(e);
+                List<RelationMember> members = new ArrayList<RelationMember>();
+                for (RelationMember m : e.members) {
+                    if (! map.containsKey(m.member)) {
+                        m.member.visit(this);
+                    }
+                    RelationMember mnew = new RelationMember(m);
+                    mnew.member = map.get(m.member);
+                    members.add(mnew);
+                }
+                enew.members.addAll(members);
+                pasteBuffer.addPrimitive(enew);
+            }
+            public void visitAll() {
+                for (OsmPrimitive osm : Main.ds.getSelected())
+                    osm.visit(this);
+            }
+        }.visitAll();
 
-		Main.pasteBuffer = pasteBuffer;
-		Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */
+        Main.pasteBuffer = pasteBuffer;
+        Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */
 
-		for(JosmAction a : listeners) {
-			a.pasteBufferChanged(Main.pasteBuffer);
-		}
-	}
+        for(JosmAction a : listeners) {
+            a.pasteBufferChanged(Main.pasteBuffer);
+        }
+    }
 
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		setEnabled(! newSelection.isEmpty());
-	}
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        setEnabled(! newSelection.isEmpty());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java	(revision 1169)
@@ -34,152 +34,152 @@
 public final class CreateCircleAction extends JosmAction {
 
-	public CreateCircleAction() {
-		super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."),
-		Shortcut.registerShortcut("tools:createcircle", tr("Tool: {0}", tr("Create Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
-	}
+    public CreateCircleAction() {
+        super(tr("Create Circle"), "createcircle", tr("Create a circle from three selected nodes."),
+        Shortcut.registerShortcut("tools:createcircle", tr("Tool: {0}", tr("Create Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
+    }
 
-	private double calcang(double xc, double yc, double x, double y) {
-		// calculate the angle from xc|yc to x|y
-		if (xc == x && yc == y) {
-			return 0; // actually invalid, but we won't have this case in this context
-		}
-		double yd = Math.abs(y - yc);
-		if (yd == 0 && xc < x) {
-			return 0;
-		}
-		if (yd == 0 && xc > x) {
-			return Math.PI;
-		}
-		double xd = Math.abs(x - xc);
-		double a = Math.atan2(xd, yd);
-		if (y > yc) {
-			a = Math.PI - a;
-		}
-		if (x < xc) {
-			a = -a;
-		}
-		a = 1.5*Math.PI + a;
-		if (a < 0) {
-			a += 2*Math.PI;
-		}
-		if (a >= 2*Math.PI) {
-			a -= 2*Math.PI;
-		}
-		return a;
-	}
+    private double calcang(double xc, double yc, double x, double y) {
+        // calculate the angle from xc|yc to x|y
+        if (xc == x && yc == y) {
+            return 0; // actually invalid, but we won't have this case in this context
+        }
+        double yd = Math.abs(y - yc);
+        if (yd == 0 && xc < x) {
+            return 0;
+        }
+        if (yd == 0 && xc > x) {
+            return Math.PI;
+        }
+        double xd = Math.abs(x - xc);
+        double a = Math.atan2(xd, yd);
+        if (y > yc) {
+            a = Math.PI - a;
+        }
+        if (x < xc) {
+            a = -a;
+        }
+        a = 1.5*Math.PI + a;
+        if (a < 0) {
+            a += 2*Math.PI;
+        }
+        if (a >= 2*Math.PI) {
+            a -= 2*Math.PI;
+        }
+        return a;
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		int numberOfNodesInCircle = Integer.parseInt(Main.pref.get("createcircle.nodecount", "8"));
-		if (numberOfNodesInCircle < 1) {
-			numberOfNodesInCircle = 1;
-		} else if (numberOfNodesInCircle > 100) {
-			numberOfNodesInCircle = 100;
-		}
+    public void actionPerformed(ActionEvent e) {
+        int numberOfNodesInCircle = Integer.parseInt(Main.pref.get("createcircle.nodecount", "8"));
+        if (numberOfNodesInCircle < 1) {
+            numberOfNodesInCircle = 1;
+        } else if (numberOfNodesInCircle > 100) {
+            numberOfNodesInCircle = 100;
+        }
 
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		Collection<Node> nodes = new LinkedList<Node>();
-		Way existingWay = null;
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        Collection<Node> nodes = new LinkedList<Node>();
+        Way existingWay = null;
 
-		for (OsmPrimitive osm : sel)
-			if (osm instanceof Node)
-				nodes.add((Node)osm);
+        for (OsmPrimitive osm : sel)
+            if (osm instanceof Node)
+                nodes.add((Node)osm);
 
-		// special case if no single nodes are selected and exactly one way is:
-		// then use the way's nodes
-		if ((nodes.size() == 0) && (sel.size() == 1))
-			for (OsmPrimitive osm : sel)
-				if (osm instanceof Way) {
-					existingWay = ((Way)osm);
-					for (Node n : ((Way)osm).nodes)
-					{
-						if(!nodes.contains(n))
-							nodes.add(n);
-					}
-				}
+        // special case if no single nodes are selected and exactly one way is:
+        // then use the way's nodes
+        if ((nodes.size() == 0) && (sel.size() == 1))
+            for (OsmPrimitive osm : sel)
+                if (osm instanceof Way) {
+                    existingWay = ((Way)osm);
+                    for (Node n : ((Way)osm).nodes)
+                    {
+                        if(!nodes.contains(n))
+                            nodes.add(n);
+                    }
+                }
 
-		if (nodes.size() != 3) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly three nodes or one way with exactly three nodes."));
-			return;
-		}
+        if (nodes.size() != 3) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Please select exactly three nodes or one way with exactly three nodes."));
+            return;
+        }
 
-		// let's get some shorter names
-		Node   n1 = ((Node)nodes.toArray()[0]);
-		double x1 = n1.eastNorth.east();
-		double y1 = n1.eastNorth.north();
-		Node   n2 = ((Node)nodes.toArray()[1]);
-		double x2 = n2.eastNorth.east();
-		double y2 = n2.eastNorth.north();
-		Node   n3 = ((Node)nodes.toArray()[2]);
-		double x3 = n3.eastNorth.east();
-		double y3 = n3.eastNorth.north();
+        // let's get some shorter names
+        Node   n1 = ((Node)nodes.toArray()[0]);
+        double x1 = n1.eastNorth.east();
+        double y1 = n1.eastNorth.north();
+        Node   n2 = ((Node)nodes.toArray()[1]);
+        double x2 = n2.eastNorth.east();
+        double y2 = n2.eastNorth.north();
+        Node   n3 = ((Node)nodes.toArray()[2]);
+        double x3 = n3.eastNorth.east();
+        double y3 = n3.eastNorth.north();
 
-		// calculate the center (xc/yc)
-		double s = 0.5*((x2 - x3)*(x1 - x3) - (y2 - y3)*(y3 - y1));
-		double sUnder = (x1 - x2)*(y3 - y1) - (y2 - y1)*(x1 - x3);
+        // calculate the center (xc/yc)
+        double s = 0.5*((x2 - x3)*(x1 - x3) - (y2 - y3)*(y3 - y1));
+        double sUnder = (x1 - x2)*(y3 - y1) - (y2 - y1)*(x1 - x3);
 
-		if (sUnder == 0) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Those nodes are not in a circle."));
-			return;
-		}
+        if (sUnder == 0) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Those nodes are not in a circle."));
+            return;
+        }
 
-		s /= sUnder;
+        s /= sUnder;
 
-		double xc = 0.5*(x1 + x2) + s*(y2 - y1);
-		double yc = 0.5*(y1 + y2) + s*(x1 - x2);
+        double xc = 0.5*(x1 + x2) + s*(y2 - y1);
+        double yc = 0.5*(y1 + y2) + s*(x1 - x2);
 
-		// calculate the radius (r)
-		double r = Math.sqrt(Math.pow(xc-x1,2) + Math.pow(yc-y1,2));
+        // calculate the radius (r)
+        double r = Math.sqrt(Math.pow(xc-x1,2) + Math.pow(yc-y1,2));
 
-		// find where to put the existing nodes
-		double a1 = calcang(xc, yc, x1, y1);
-		double a2 = calcang(xc, yc, x2, y2);
-		double a3 = calcang(xc, yc, x3, y3);
-		if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
-		if (a2 < a3) { double at = a2; Node nt = n2; a2 = a3; n2 = n3; a3 = at; n3 = nt; }
-		if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
+        // find where to put the existing nodes
+        double a1 = calcang(xc, yc, x1, y1);
+        double a2 = calcang(xc, yc, x2, y2);
+        double a3 = calcang(xc, yc, x3, y3);
+        if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
+        if (a2 < a3) { double at = a2; Node nt = n2; a2 = a3; n2 = n3; a3 = at; n3 = nt; }
+        if (a1 < a2) { double at = a1; Node nt = n1; a1 = a2; n1 = n2; a2 = at; n2 = nt; }
 
-		// now we can start doing thigs to OSM data
-		Collection<Command> cmds = new LinkedList<Command>();
+        // now we can start doing thigs to OSM data
+        Collection<Command> cmds = new LinkedList<Command>();
 
-		// build a way for the circle
-		Way wayToAdd;
-		if (existingWay == null) {
-			wayToAdd = new Way();
-		} else {
-			// re-use existing way if it was selected
-			wayToAdd = new Way(existingWay);
-			wayToAdd.nodes.clear();
-		}
-		for (int i = 1; i <= numberOfNodesInCircle; i++) {
-			double a = 2*Math.PI*(1.0 - i/(double)numberOfNodesInCircle); // "1-" to get it clock-wise
-			// insert existing nodes if they fit before this new node (999 means "already added this node")
-			if (a1 < 999 && a1 > a) {
-				wayToAdd.nodes.add(n1);
-				a1 = 999;
-			}
-			if (a2 < 999 && a2 > a) {
-				wayToAdd.nodes.add(n2);
-				a2 = 999;
-			}
-			if (a3 < 999 && a3 > a) {
-				wayToAdd.nodes.add(n3);
-				a3 = 999;
-			}
-			// get the position of the new node and insert it
-			double x = xc + r*Math.cos(a);
-			double y = yc + r*Math.sin(a);
-			Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
-			wayToAdd.nodes.add(n);
-			cmds.add(new AddCommand(n));
-		}
-		wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the circle
-		if (existingWay == null) {
-			cmds.add(new AddCommand(wayToAdd));
-		} else {
-			cmds.add(new ChangeCommand(existingWay, wayToAdd));
-		}
+        // build a way for the circle
+        Way wayToAdd;
+        if (existingWay == null) {
+            wayToAdd = new Way();
+        } else {
+            // re-use existing way if it was selected
+            wayToAdd = new Way(existingWay);
+            wayToAdd.nodes.clear();
+        }
+        for (int i = 1; i <= numberOfNodesInCircle; i++) {
+            double a = 2*Math.PI*(1.0 - i/(double)numberOfNodesInCircle); // "1-" to get it clock-wise
+            // insert existing nodes if they fit before this new node (999 means "already added this node")
+            if (a1 < 999 && a1 > a) {
+                wayToAdd.nodes.add(n1);
+                a1 = 999;
+            }
+            if (a2 < 999 && a2 > a) {
+                wayToAdd.nodes.add(n2);
+                a2 = 999;
+            }
+            if (a3 < 999 && a3 > a) {
+                wayToAdd.nodes.add(n3);
+                a3 = 999;
+            }
+            // get the position of the new node and insert it
+            double x = xc + r*Math.cos(a);
+            double y = yc + r*Math.sin(a);
+            Node n = new Node(Main.proj.eastNorth2latlon(new EastNorth(x,y)));
+            wayToAdd.nodes.add(n);
+            cmds.add(new AddCommand(n));
+        }
+        wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the circle
+        if (existingWay == null) {
+            cmds.add(new AddCommand(wayToAdd));
+        } else {
+            cmds.add(new ChangeCommand(existingWay, wayToAdd));
+        }
 
-		Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds));
-		Main.map.repaint();
-	}
+        Main.main.undoRedo.add(new SequenceCommand(tr("Create Circle"), cmds));
+        Main.map.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/DeleteAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DeleteAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/DeleteAction.java	(revision 1169)
@@ -17,15 +17,15 @@
 public final class DeleteAction extends JosmAction implements SelectionChangedListener {
 
-	public DeleteAction() {
-		super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
-		Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.GROUP_DIRECT), true);
+    public DeleteAction() {
+        super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."),
+        Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.GROUP_DIRECT), true);
         DataSet.selListeners.add(this);
-		setEnabled(false);
-	}
+        setEnabled(false);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		new org.openstreetmap.josm.actions.mapmode.DeleteAction(Main.map)
-		        .doActionPerformed(e);
-	}
+    public void actionPerformed(ActionEvent e) {
+        new org.openstreetmap.josm.actions.mapmode.DeleteAction(Main.map)
+                .doActionPerformed(e);
+    }
     public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
         setEnabled(! newSelection.isEmpty());
Index: trunk/src/org/openstreetmap/josm/actions/DiskAccessAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 1169)
@@ -17,41 +17,41 @@
 abstract public class DiskAccessAction extends JosmAction {
 
-	public DiskAccessAction(String name, String iconName, String tooltip, Shortcut shortcut) {
-		super(name, iconName, tooltip, shortcut, true);
-	}
+    public DiskAccessAction(String name, String iconName, String tooltip, Shortcut shortcut) {
+        super(name, iconName, tooltip, shortcut, true);
+    }
 
-	@Deprecated
-	public DiskAccessAction(String name, String iconName, String tooltip, int shortcut, int modifiers) {
-		super(name, iconName, tooltip, shortcut, modifiers, true);
-	}
+    @Deprecated
+    public DiskAccessAction(String name, String iconName, String tooltip, int shortcut, int modifiers) {
+        super(name, iconName, tooltip, shortcut, modifiers, true);
+    }
 
-	protected static JFileChooser createAndOpenFileChooser(boolean open, boolean multiple, String title) {
-		String curDir = Main.pref.get("lastDirectory");
-		if (curDir.equals(""))
-			curDir = ".";
-		JFileChooser fc = new JFileChooser(new File(curDir));
-		if(title != null)
-			fc.setDialogTitle(title);
+    protected static JFileChooser createAndOpenFileChooser(boolean open, boolean multiple, String title) {
+        String curDir = Main.pref.get("lastDirectory");
+        if (curDir.equals(""))
+            curDir = ".";
+        JFileChooser fc = new JFileChooser(new File(curDir));
+        if(title != null)
+            fc.setDialogTitle(title);
 
-		fc.setMultiSelectionEnabled(multiple);
-		for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
-			fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
-		fc.setAcceptAllFileFilterUsed(true);
+        fc.setMultiSelectionEnabled(multiple);
+        for (int i = 0; i < ExtensionFileFilter.filters.length; ++i)
+            fc.addChoosableFileFilter(ExtensionFileFilter.filters[i]);
+        fc.setAcceptAllFileFilterUsed(true);
 
-		int answer = open ? fc.showOpenDialog(Main.parent) : fc.showSaveDialog(Main.parent);
-		if (answer != JFileChooser.APPROVE_OPTION)
-			return null;
+        int answer = open ? fc.showOpenDialog(Main.parent) : fc.showSaveDialog(Main.parent);
+        if (answer != JFileChooser.APPROVE_OPTION)
+            return null;
 
-		if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
-			Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
+        if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
+            Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
 
-		if (!open) {
-			File file = fc.getSelectedFile();
-			if (file == null || (file.exists() && JOptionPane.YES_OPTION !=
-					JOptionPane.showConfirmDialog(Main.parent, tr("File exists. Overwrite?"), tr("Overwrite"), JOptionPane.YES_NO_OPTION)))
-				return null;
-		}
+        if (!open) {
+            File file = fc.getSelectedFile();
+            if (file == null || (file.exists() && JOptionPane.YES_OPTION !=
+                    JOptionPane.showConfirmDialog(Main.parent, tr("File exists. Overwrite?"), tr("Overwrite"), JOptionPane.YES_NO_OPTION)))
+                return null;
+        }
 
-		return fc;
-	}
+        return fc;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 1169)
@@ -28,48 +28,48 @@
 public class DownloadAction extends JosmAction {
 
-	public DownloadDialog dialog;
+    public DownloadDialog dialog;
 
-	public DownloadAction() {
-		super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."),
-		Shortcut.registerShortcut("file:download", tr("File: {0}", tr("Download from OSM ...")), KeyEvent.VK_D, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
-	}
+    public DownloadAction() {
+        super(tr("Download from OSM ..."), "download", tr("Download map data from the OSM server."),
+        Shortcut.registerShortcut("file:download", tr("File: {0}", tr("Download from OSM ...")), KeyEvent.VK_D, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		dialog = new DownloadDialog();
+    public void actionPerformed(ActionEvent e) {
+        dialog = new DownloadDialog();
 
-		JPanel downPanel = new JPanel(new GridBagLayout());
-		downPanel.add(dialog, GBC.eol().fill(GBC.BOTH));
+        JPanel downPanel = new JPanel(new GridBagLayout());
+        downPanel.add(dialog, GBC.eol().fill(GBC.BOTH));
 
-		JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
-		JDialog dlg = pane.createDialog(Main.parent, tr("Download"));
-		dlg.setResizable(true);
-		dialog.setOptionPane(pane);
+        JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
+        JDialog dlg = pane.createDialog(Main.parent, tr("Download"));
+        dlg.setResizable(true);
+        dialog.setOptionPane(pane);
 
-		if (dlg.getWidth() > 1000)
-			dlg.setSize(1000, dlg.getHeight());
-		if (dlg.getHeight() > 600)
-			dlg.setSize(dlg.getWidth(),600);
+        if (dlg.getWidth() > 1000)
+            dlg.setSize(1000, dlg.getHeight());
+        if (dlg.getHeight() > 600)
+            dlg.setSize(dlg.getWidth(),600);
 
-		boolean finish = false;
+        boolean finish = false;
         while (!finish) {
             dlg.setVisible(true);
             Main.pref.put("download.newlayer", dialog.newLayer.isSelected());
-        	if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) {
-        		Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab()));
-        		for (DownloadTask task : dialog.downloadTasks) {
-        			Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
-        			if (task.getCheckBox().isSelected()) {
-        				task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon);
-        				finish = true;
-        			}
-        		}
-        	} else
-        		finish = true;
-        	if (!finish)
-        		JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one task to download"));
+            if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) {
+                Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab()));
+                for (DownloadTask task : dialog.downloadTasks) {
+                    Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
+                    if (task.getCheckBox().isSelected()) {
+                        task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon);
+                        finish = true;
+                    }
+                }
+            } else
+                finish = true;
+            if (!finish)
+                JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one task to download"));
         }
 
                 dialog = null;
-		dlg.dispose();
-	}
+        dlg.dispose();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java	(revision 1169)
@@ -18,18 +18,18 @@
 
     public DuplicateAction() {
-    	super(tr("Duplicate"), "duplicate",
-			tr("Duplicate selection by copy and immediate paste."),
-			Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.GROUP_MENU), true);
-    	setEnabled(false);
-			DataSet.selListeners.add(this);
+        super(tr("Duplicate"), "duplicate",
+            tr("Duplicate selection by copy and immediate paste."),
+            Shortcut.registerShortcut("system:duplicate", tr("Edit: {0}", tr("Duplicate")), KeyEvent.VK_D, Shortcut.GROUP_MENU), true);
+        setEnabled(false);
+            DataSet.selListeners.add(this);
     }
 
-	public void actionPerformed(ActionEvent e) {
-		Main.main.menu.copy.actionPerformed(e);
-		Main.main.menu.paste.actionPerformed(e);
+    public void actionPerformed(ActionEvent e) {
+        Main.main.menu.copy.actionPerformed(e);
+        Main.main.menu.paste.actionPerformed(e);
     }
 
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		setEnabled(! newSelection.isEmpty());
-	}
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        setEnabled(! newSelection.isEmpty());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ExitAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ExitAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ExitAction.java	(revision 1169)
@@ -16,15 +16,15 @@
  */
 public class ExitAction extends JosmAction {
-	/**
-	 * Construct the action with "Exit" as label
-	 */
-	public ExitAction() {
-		super(tr("Exit"), "exit", tr("Exit the application."),
-		Shortcut.registerShortcut("system:menuexit", tr("Exit"), KeyEvent.VK_Q, Shortcut.GROUP_MENU), true);
-	}
+    /**
+     * Construct the action with "Exit" as label
+     */
+    public ExitAction() {
+        super(tr("Exit"), "exit", tr("Exit the application."),
+        Shortcut.registerShortcut("system:menuexit", tr("Exit"), KeyEvent.VK_Q, Shortcut.GROUP_MENU), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		if (!Main.breakBecauseUnsavedChanges())
-			System.exit(0);
-	}
+    public void actionPerformed(ActionEvent e) {
+        if (!Main.breakBecauseUnsavedChanges())
+            System.exit(0);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 1169)
@@ -9,50 +9,50 @@
 
 /**
- * A file filter that filters after the extension. Also includes a list of file 
+ * A file filter that filters after the extension. Also includes a list of file
  * filters used in JOSM.
- * 
+ *
  * @author imi
  */
 public class ExtensionFileFilter extends FileFilter {
-	private final String extension;
-	private final String description;
-	public final String defaultExtension;
+    private final String extension;
+    private final String description;
+    public final String defaultExtension;
 
-	public static final int OSM = 0;
-	public static final int GPX = 1;
-	public static final int NMEA = 2;
-	
-	public static ExtensionFileFilter[] filters = {
-		new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")),
-		new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")),
-		new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")),
-	};
+    public static final int OSM = 0;
+    public static final int GPX = 1;
+    public static final int NMEA = 2;
 
-	/**
-	 * Construct an extension file filter by giving the extension to check after.
-	 *
-	 */
-	public ExtensionFileFilter(String extension, String defExt, String description) {
-		this.extension = extension;
-		defaultExtension = defExt;
-		this.description = description;
-	}
+    public static ExtensionFileFilter[] filters = {
+        new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files (*.osm *.xml)")),
+        new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files (*.gpx *.gpx.gz)")),
+        new ExtensionFileFilter("nmea,txt", "nmea", tr("NMEA-0183 Files (*.nmea *.txt)")),
+    };
 
-	public boolean acceptName(String filename) {
-		String name = filename.toLowerCase();
-		for (String ext : extension.split(","))
-			if (name.endsWith("."+ext))
-				return true;
-		return false;
-	}
+    /**
+     * Construct an extension file filter by giving the extension to check after.
+     *
+     */
+    public ExtensionFileFilter(String extension, String defExt, String description) {
+        this.extension = extension;
+        defaultExtension = defExt;
+        this.description = description;
+    }
 
-	@Override public boolean accept(File pathname) {
-		if (pathname.isDirectory())
-			return true;
-		return acceptName(pathname.getName());
-	}
+    public boolean acceptName(String filename) {
+        String name = filename.toLowerCase();
+        for (String ext : extension.split(","))
+            if (name.endsWith("."+ext))
+                return true;
+        return false;
+    }
 
-	@Override public String getDescription() {
-		return description;
-	}
+    @Override public boolean accept(File pathname) {
+        if (pathname.isDirectory())
+            return true;
+        return acceptName(pathname.getName());
+    }
+
+    @Override public String getDescription() {
+        return description;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/GpxExportAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 1169)
@@ -40,197 +40,197 @@
 public class GpxExportAction extends DiskAccessAction {
 
-	private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
-
-	private final Layer layer;
-
-	public GpxExportAction(Layer layer) {
-		super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."),
-		Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX ..."), KeyEvent.VK_E, Shortcut.GROUP_MENU));
-		this.layer = layer;
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		if (layer == null && Main.map == null) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first."));
-			return;
-		}
-
-		JFileChooser fc = createAndOpenFileChooser(false, false, null);
-		if (fc == null)
-			return;
-		File file = fc.getSelectedFile();
-		if (file == null)
-			return;
-
-		exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer);
-	}
-
-	public static void exportGpx(File file, Layer layer) {
-		String fn = file.getPath();
-		if (fn.indexOf('.') == -1) {
-			fn += ".gpx";
-			file = new File(fn);
-		}
-
-		// open the dialog asking for options
-		JPanel p = new JPanel(new GridBagLayout());
-
-		p.add(new JLabel(tr("gps track description")), GBC.eol());
-		JTextArea desc = new JTextArea(3,40);
-		desc.setWrapStyleWord(true);
-		desc.setLineWrap(true);
-		p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
-
-		JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
-		author.setSelected(true);
-		p.add(author, GBC.eol());
-		JLabel nameLabel = new JLabel(tr("Real name"));
-		p.add(nameLabel, GBC.std().insets(10,0,5,0));
-		JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
-		p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
-		JLabel emailLabel = new JLabel(tr("Email"));
-		p.add(emailLabel, GBC.std().insets(10,0,5,0));
-		JTextField email = new JTextField(Main.pref.get("osm-server.username"));
-		p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
-		JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
-		p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
-		JTextField copyright = new JTextField();
-		p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
-		JButton predefined = new JButton(tr("Predefined"));
-		p.add(predefined, GBC.eol().insets(5,0,0,0));
-		JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
-		p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
-		JTextField copyrightYear = new JTextField("");
-		p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
-		JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
-		p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
-		addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
-
-		p.add(new JLabel(tr("Keywords")), GBC.eol());
-		JTextField keywords = new JTextField();
-		p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
-
-		int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Export options"), JOptionPane.OK_CANCEL_OPTION);
-		if (answer != JOptionPane.OK_OPTION)
-			return;
-
-		Main.pref.put("lastAddAuthor", author.isSelected());
-		if (authorName.getText().length() != 0)
-			Main.pref.put("lastAuthorName", authorName.getText());
-		if (copyright.getText().length() != 0)
-			Main.pref.put("lastCopyright", copyright.getText());
-
-		GpxData gpxData;
-		if (layer instanceof OsmDataLayer)
-			gpxData = ((OsmDataLayer)layer).toGpxData();
-		else if (layer instanceof GpxLayer)
-			gpxData = ((GpxLayer)layer).data;
-		else
-			gpxData = OsmDataLayer.toGpxData(Main.ds);
-		// TODO: add copyright, etc.
-		try {
-			FileOutputStream fo = new FileOutputStream(file);
-			new GpxWriter(fo).write(gpxData);
-			fo.flush();
-			fo.close();
-		} catch (IOException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}", fn)+":\n"+x.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
-		}
-	}
-
-	/**
-	 * Add all those listeners to handle the enable state of the fields.
-	 * @param copyrightYearLabel
-	 * @param copyrightLabel
-	 * @param emailLabel
-	 * @param nameLabel
-	 * @param warning
-	 */
-	private static void addDependencies(
-			final JCheckBox author,
-			final JTextField authorName,
-			final JTextField email,
-			final JTextField copyright,
-			final JButton predefined,
-			final JTextField copyrightYear,
-			final JLabel nameLabel,
-			final JLabel emailLabel,
-			final JLabel copyrightLabel,
-			final JLabel copyrightYearLabel,
-			final JLabel warning) {
-
-		ActionListener authorActionListener = new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				boolean b = author.isSelected();
-				authorName.setEnabled(b);
-				email.setEnabled(b);
-				nameLabel.setEnabled(b);
-				emailLabel.setEnabled(b);
-				authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
-				email.setText(b ? Main.pref.get("osm-server.username") : "");
-
-				boolean authorSet = authorName.getText().length() != 0;
-				enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
-			}
-		};
-		author.addActionListener(authorActionListener);
-
-		KeyAdapter authorNameListener = new KeyAdapter(){
-					@Override public void keyReleased(KeyEvent e) {
-						boolean b = authorName.getText().length()!=0 && author.isSelected();
-						enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
-					}
-				};
-		authorName.addKeyListener(authorNameListener);
-
-		predefined.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
-				l.setVisibleRowCount(4);
-				l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-				int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
-				if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
-					return;
-				final String[] urls = {
-						"http://creativecommons.org/licenses/by-sa/2.5",
-						"public domain",
-						"http://www.gnu.org/copyleft/lesser.html",
-						"http://www.opensource.org/licenses/bsd-license.php"};
-				String license = "";
-				for (int i : l.getSelectedIndices()) {
-					if (i == 1) {
-						license = "public domain";
-						break;
-					}
-					license += license.length()==0 ? urls[i] : ", "+urls[i];
-				}
-				copyright.setText(license);
-				copyright.setCaretPosition(0);
-			}
-		});
-
-		authorActionListener.actionPerformed(null);
-		authorNameListener.keyReleased(null);
-	}
-
-	private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
-		copyright.setEnabled(enable);
-		predefined.setEnabled(enable);
-		copyrightYear.setEnabled(enable);
-		copyrightLabel.setEnabled(enable);
-		copyrightYearLabel.setEnabled(enable);
-		warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
-
-		if (enable && copyrightYear.getText().length()==0) {
-			copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
-		} else if (!enable)
-			copyrightYear.setText("");
-
-		if (enable && copyright.getText().length()==0) {
-			copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
-			copyright.setCaretPosition(0);
-		} else if (!enable)
-			copyright.setText("");
-	}
+    private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
+
+    private final Layer layer;
+
+    public GpxExportAction(Layer layer) {
+        super(tr("Export to GPX ..."), "exportgpx", tr("Export the data to GPX file."),
+        Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX ..."), KeyEvent.VK_E, Shortcut.GROUP_MENU));
+        this.layer = layer;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        if (layer == null && Main.map == null) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first."));
+            return;
+        }
+
+        JFileChooser fc = createAndOpenFileChooser(false, false, null);
+        if (fc == null)
+            return;
+        File file = fc.getSelectedFile();
+        if (file == null)
+            return;
+
+        exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer);
+    }
+
+    public static void exportGpx(File file, Layer layer) {
+        String fn = file.getPath();
+        if (fn.indexOf('.') == -1) {
+            fn += ".gpx";
+            file = new File(fn);
+        }
+
+        // open the dialog asking for options
+        JPanel p = new JPanel(new GridBagLayout());
+
+        p.add(new JLabel(tr("gps track description")), GBC.eol());
+        JTextArea desc = new JTextArea(3,40);
+        desc.setWrapStyleWord(true);
+        desc.setLineWrap(true);
+        p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
+
+        JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
+        author.setSelected(true);
+        p.add(author, GBC.eol());
+        JLabel nameLabel = new JLabel(tr("Real name"));
+        p.add(nameLabel, GBC.std().insets(10,0,5,0));
+        JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
+        p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel emailLabel = new JLabel(tr("Email"));
+        p.add(emailLabel, GBC.std().insets(10,0,5,0));
+        JTextField email = new JTextField(Main.pref.get("osm-server.username"));
+        p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
+        p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
+        JTextField copyright = new JTextField();
+        p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
+        JButton predefined = new JButton(tr("Predefined"));
+        p.add(predefined, GBC.eol().insets(5,0,0,0));
+        JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
+        p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
+        JTextField copyrightYear = new JTextField("");
+        p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
+        p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
+        addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
+
+        p.add(new JLabel(tr("Keywords")), GBC.eol());
+        JTextField keywords = new JTextField();
+        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
+
+        int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Export options"), JOptionPane.OK_CANCEL_OPTION);
+        if (answer != JOptionPane.OK_OPTION)
+            return;
+
+        Main.pref.put("lastAddAuthor", author.isSelected());
+        if (authorName.getText().length() != 0)
+            Main.pref.put("lastAuthorName", authorName.getText());
+        if (copyright.getText().length() != 0)
+            Main.pref.put("lastCopyright", copyright.getText());
+
+        GpxData gpxData;
+        if (layer instanceof OsmDataLayer)
+            gpxData = ((OsmDataLayer)layer).toGpxData();
+        else if (layer instanceof GpxLayer)
+            gpxData = ((GpxLayer)layer).data;
+        else
+            gpxData = OsmDataLayer.toGpxData(Main.ds);
+        // TODO: add copyright, etc.
+        try {
+            FileOutputStream fo = new FileOutputStream(file);
+            new GpxWriter(fo).write(gpxData);
+            fo.flush();
+            fo.close();
+        } catch (IOException x) {
+            x.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}", fn)+":\n"+x.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    /**
+     * Add all those listeners to handle the enable state of the fields.
+     * @param copyrightYearLabel
+     * @param copyrightLabel
+     * @param emailLabel
+     * @param nameLabel
+     * @param warning
+     */
+    private static void addDependencies(
+            final JCheckBox author,
+            final JTextField authorName,
+            final JTextField email,
+            final JTextField copyright,
+            final JButton predefined,
+            final JTextField copyrightYear,
+            final JLabel nameLabel,
+            final JLabel emailLabel,
+            final JLabel copyrightLabel,
+            final JLabel copyrightYearLabel,
+            final JLabel warning) {
+
+        ActionListener authorActionListener = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                boolean b = author.isSelected();
+                authorName.setEnabled(b);
+                email.setEnabled(b);
+                nameLabel.setEnabled(b);
+                emailLabel.setEnabled(b);
+                authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
+                email.setText(b ? Main.pref.get("osm-server.username") : "");
+
+                boolean authorSet = authorName.getText().length() != 0;
+                enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
+            }
+        };
+        author.addActionListener(authorActionListener);
+
+        KeyAdapter authorNameListener = new KeyAdapter(){
+                    @Override public void keyReleased(KeyEvent e) {
+                        boolean b = authorName.getText().length()!=0 && author.isSelected();
+                        enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
+                    }
+                };
+        authorName.addKeyListener(authorNameListener);
+
+        predefined.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
+                l.setVisibleRowCount(4);
+                l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+                int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
+                if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
+                    return;
+                final String[] urls = {
+                        "http://creativecommons.org/licenses/by-sa/2.5",
+                        "public domain",
+                        "http://www.gnu.org/copyleft/lesser.html",
+                        "http://www.opensource.org/licenses/bsd-license.php"};
+                String license = "";
+                for (int i : l.getSelectedIndices()) {
+                    if (i == 1) {
+                        license = "public domain";
+                        break;
+                    }
+                    license += license.length()==0 ? urls[i] : ", "+urls[i];
+                }
+                copyright.setText(license);
+                copyright.setCaretPosition(0);
+            }
+        });
+
+        authorActionListener.actionPerformed(null);
+        authorNameListener.keyReleased(null);
+    }
+
+    private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
+        copyright.setEnabled(enable);
+        predefined.setEnabled(enable);
+        copyrightYear.setEnabled(enable);
+        copyrightLabel.setEnabled(enable);
+        copyrightYearLabel.setEnabled(enable);
+        warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
+
+        if (enable && copyrightYear.getText().length()==0) {
+            copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
+        } else if (!enable)
+            copyrightYear.setText("");
+
+        if (enable && copyright.getText().length()==0) {
+            copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
+            copyright.setCaretPosition(0);
+        } else if (!enable)
+            copyright.setText("");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/HelpAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/HelpAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/HelpAction.java	(revision 1169)
@@ -42,174 +42,174 @@
 public class HelpAction extends AbstractAction {
 
-	public interface Helpful {
-		String helpTopic();
+    public interface Helpful {
+        String helpTopic();
     }
 
         private String languageCode = Main.getLanguageCodeU();
-	private JFrame helpBrowser = new JFrame(tr("JOSM Online Help"));
-	private String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
-	private JEditorPane help = new JEditorPane();
-	private WikiReader reader = new WikiReader(baseurl);
-	private String url;
-
-	public HelpAction() {
-		super(tr("Help"), ImageProvider.get("help"));
-		help.setEditable(false);
-		help.addHyperlinkListener(new HyperlinkListener(){
-			public void hyperlinkUpdate(HyperlinkEvent e) {
-				if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED)
-					return;
-				if (e.getURL() == null)
-					help.setText("<html>404 not found</html>");
-				else if (e.getURL().toString().startsWith(WikiReader.JOSM_EXTERN))
-					OpenBrowser.displayUrl("http://"+e.getURL().toString().substring(WikiReader.JOSM_EXTERN.length())+"?action=edit");
-				else
-					setHelpUrl(e.getURL().toString());
-			}
-		});
-		help.setContentType("text/html");
-
-		JPanel p = new JPanel(new BorderLayout());
-		helpBrowser.setContentPane(p);
-
-		p.add(new JScrollPane(help), BorderLayout.CENTER);
-		String[] bounds = Main.pref.get("help.window.bounds", "0,0,800,600").split(",");
-		helpBrowser.setBounds(
-				Integer.parseInt(bounds[0]),
-				Integer.parseInt(bounds[1]),
-				Integer.parseInt(bounds[2]),
-				Integer.parseInt(bounds[3]));
-
-		JPanel buttons = new JPanel();
-		p.add(buttons, BorderLayout.SOUTH);
-		createButton(buttons, tr("Open in Browser"));
-		createButton(buttons, tr("Edit"));
-		createButton(buttons, tr("Reload"));
-
-		helpBrowser.addWindowListener(new WindowAdapter(){
-			@Override public void windowClosing(WindowEvent e) {
-				closeHelp();
-			}
-		});
+    private JFrame helpBrowser = new JFrame(tr("JOSM Online Help"));
+    private String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
+    private JEditorPane help = new JEditorPane();
+    private WikiReader reader = new WikiReader(baseurl);
+    private String url;
+
+    public HelpAction() {
+        super(tr("Help"), ImageProvider.get("help"));
+        help.setEditable(false);
+        help.addHyperlinkListener(new HyperlinkListener(){
+            public void hyperlinkUpdate(HyperlinkEvent e) {
+                if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED)
+                    return;
+                if (e.getURL() == null)
+                    help.setText("<html>404 not found</html>");
+                else if (e.getURL().toString().startsWith(WikiReader.JOSM_EXTERN))
+                    OpenBrowser.displayUrl("http://"+e.getURL().toString().substring(WikiReader.JOSM_EXTERN.length())+"?action=edit");
+                else
+                    setHelpUrl(e.getURL().toString());
+            }
+        });
+        help.setContentType("text/html");
+
+        JPanel p = new JPanel(new BorderLayout());
+        helpBrowser.setContentPane(p);
+
+        p.add(new JScrollPane(help), BorderLayout.CENTER);
+        String[] bounds = Main.pref.get("help.window.bounds", "0,0,800,600").split(",");
+        helpBrowser.setBounds(
+                Integer.parseInt(bounds[0]),
+                Integer.parseInt(bounds[1]),
+                Integer.parseInt(bounds[2]),
+                Integer.parseInt(bounds[3]));
+
+        JPanel buttons = new JPanel();
+        p.add(buttons, BorderLayout.SOUTH);
+        createButton(buttons, tr("Open in Browser"));
+        createButton(buttons, tr("Edit"));
+        createButton(buttons, tr("Reload"));
+
+        helpBrowser.addWindowListener(new WindowAdapter(){
+            @Override public void windowClosing(WindowEvent e) {
+                closeHelp();
+            }
+        });
 
         help.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Close");
         help.getActionMap().put("Close", new AbstractAction(){
-			public void actionPerformed(ActionEvent e) {
-				closeHelp();
+            public void actionPerformed(ActionEvent e) {
+                closeHelp();
             }
         });
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		if (tr("Open in Browser").equals(e.getActionCommand())) {
-			OpenBrowser.displayUrl(url);
-		} else if (tr("Edit").equals(e.getActionCommand())) {
-			if (!url.startsWith(baseurl)) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Can only edit help pages from JOSM Online Help"));
-				return;
-			}
-			OpenBrowser.displayUrl(url+"?action=edit");
-		} else if (tr("Reload").equals(e.getActionCommand())) {
-			setHelpUrl(url);
-		} else if (e.getActionCommand() == null) {
-			String topic = null;
-			Point mouse = Main.parent.getMousePosition();
-			if (mouse != null)
-				topic = contextSensitiveHelp(SwingUtilities.getDeepestComponentAt(Main.parent, mouse.x, mouse.y));
-			if (topic == null) {
-				helpBrowser.setVisible(false);
-				setHelpUrl(baseurl+"/wiki/Help");
-			} else
-				help(topic);
-		} else {
-			helpBrowser.setVisible(false);
-			setHelpUrl(baseurl+"/wiki/Help");
-		}
-	}
-
-	/**
-	 * @return The topic of the help. <code>null</code> for "don't know"
-	 */
-	private String contextSensitiveHelp(Object c) {
-		if (c instanceof Helpful)
-			return ((Helpful)c).helpTopic();
-		if (c instanceof JMenu)
-			return "Menu/"+((JMenu)c).getText();
-		if (c instanceof AbstractButton) {
-			AbstractButton b = (AbstractButton)c;
-			if (b.getClientProperty("help") != null)
-				return (String)b.getClientProperty("help");
-			return contextSensitiveHelp(((AbstractButton)c).getAction());
-		}
-		if (c instanceof Action)
-			return (String)((Action)c).getValue("help");
-		if (c instanceof Component)
-			return contextSensitiveHelp(((Component)c).getParent());
-		return null;
-    }
-
-	/**
-	 * Displays the help (or browse on the already open help) on the online page
-	 * with the given help topic. Use this for larger help descriptions.
-	 */
-	public void help(String topic) {
-		helpBrowser.setVisible(false);
-		setHelpUrl(baseurl+"/wiki/Help/"+topic);
-	}
-
-	/**
-	 * Set the content of the help window to a specific text (in html format)
-	 * @param url The url this content is the representation of
-	 */
-	public void setHelpUrl(String url) {
-		int i = url.lastIndexOf("/")+1;
-		String title = url.substring(i);
-		if(!title.startsWith(languageCode))
-			title = languageCode + title;
-		String langurl = url.substring(0, i) + title;
-		if(langurl.equals(this.url) || langurl.equals(url))
-		{
-			this.url = url;
-			try {
-				help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
-			} catch (IOException ex) {
-				help.setText(tr("Error while loading page {0}",url));
-			}
-		}
-		else
-		{
-			try {
-				help.read(new StringReader(reader.read(langurl)), help.getEditorKit().createDefaultDocument());
-				String message = help.getText();
-				String le = "http://josm-extern." + langurl.substring(7);
-				if(message.indexOf("Describe &quot;") >= 0 && message.indexOf(le) >= 0)
-					throw new IOException();
-				this.url = langurl;
-			} catch (IOException e) {
-				this.url = url;
-				try {
-					help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
-				} catch (IOException ex) {
-					help.setText(tr("Error while loading page {0}",url));
-				}
-			}
-		}
-		helpBrowser.setVisible(true);
-	}
-
-	/**
-	 * Closes the help window
-	 */
-	public void closeHelp() {
-		String bounds = helpBrowser.getX()+","+helpBrowser.getY()+","+helpBrowser.getWidth()+","+helpBrowser.getHeight();
-		Main.pref.put("help.window.bounds", bounds);
-		helpBrowser.setVisible(false);
-	}
-
-	private void createButton(JPanel buttons, String name) {
-		JButton b = new JButton(tr(name));
-		b.setActionCommand(name);
-		b.addActionListener(this);
-		buttons.add(b);
-	}
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        if (tr("Open in Browser").equals(e.getActionCommand())) {
+            OpenBrowser.displayUrl(url);
+        } else if (tr("Edit").equals(e.getActionCommand())) {
+            if (!url.startsWith(baseurl)) {
+                JOptionPane.showMessageDialog(Main.parent, tr("Can only edit help pages from JOSM Online Help"));
+                return;
+            }
+            OpenBrowser.displayUrl(url+"?action=edit");
+        } else if (tr("Reload").equals(e.getActionCommand())) {
+            setHelpUrl(url);
+        } else if (e.getActionCommand() == null) {
+            String topic = null;
+            Point mouse = Main.parent.getMousePosition();
+            if (mouse != null)
+                topic = contextSensitiveHelp(SwingUtilities.getDeepestComponentAt(Main.parent, mouse.x, mouse.y));
+            if (topic == null) {
+                helpBrowser.setVisible(false);
+                setHelpUrl(baseurl+"/wiki/Help");
+            } else
+                help(topic);
+        } else {
+            helpBrowser.setVisible(false);
+            setHelpUrl(baseurl+"/wiki/Help");
+        }
+    }
+
+    /**
+     * @return The topic of the help. <code>null</code> for "don't know"
+     */
+    private String contextSensitiveHelp(Object c) {
+        if (c instanceof Helpful)
+            return ((Helpful)c).helpTopic();
+        if (c instanceof JMenu)
+            return "Menu/"+((JMenu)c).getText();
+        if (c instanceof AbstractButton) {
+            AbstractButton b = (AbstractButton)c;
+            if (b.getClientProperty("help") != null)
+                return (String)b.getClientProperty("help");
+            return contextSensitiveHelp(((AbstractButton)c).getAction());
+        }
+        if (c instanceof Action)
+            return (String)((Action)c).getValue("help");
+        if (c instanceof Component)
+            return contextSensitiveHelp(((Component)c).getParent());
+        return null;
+    }
+
+    /**
+     * Displays the help (or browse on the already open help) on the online page
+     * with the given help topic. Use this for larger help descriptions.
+     */
+    public void help(String topic) {
+        helpBrowser.setVisible(false);
+        setHelpUrl(baseurl+"/wiki/Help/"+topic);
+    }
+
+    /**
+     * Set the content of the help window to a specific text (in html format)
+     * @param url The url this content is the representation of
+     */
+    public void setHelpUrl(String url) {
+        int i = url.lastIndexOf("/")+1;
+        String title = url.substring(i);
+        if(!title.startsWith(languageCode))
+            title = languageCode + title;
+        String langurl = url.substring(0, i) + title;
+        if(langurl.equals(this.url) || langurl.equals(url))
+        {
+            this.url = url;
+            try {
+                help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
+            } catch (IOException ex) {
+                help.setText(tr("Error while loading page {0}",url));
+            }
+        }
+        else
+        {
+            try {
+                help.read(new StringReader(reader.read(langurl)), help.getEditorKit().createDefaultDocument());
+                String message = help.getText();
+                String le = "http://josm-extern." + langurl.substring(7);
+                if(message.indexOf("Describe &quot;") >= 0 && message.indexOf(le) >= 0)
+                    throw new IOException();
+                this.url = langurl;
+            } catch (IOException e) {
+                this.url = url;
+                try {
+                    help.read(new StringReader(reader.read(url)), help.getEditorKit().createDefaultDocument());
+                } catch (IOException ex) {
+                    help.setText(tr("Error while loading page {0}",url));
+                }
+            }
+        }
+        helpBrowser.setVisible(true);
+    }
+
+    /**
+     * Closes the help window
+     */
+    public void closeHelp() {
+        String bounds = helpBrowser.getX()+","+helpBrowser.getY()+","+helpBrowser.getWidth()+","+helpBrowser.getHeight();
+        Main.pref.put("help.window.bounds", bounds);
+        helpBrowser.setVisible(false);
+    }
+
+    private void createButton(JPanel buttons, String name) {
+        JButton b = new JButton(tr(name));
+        b.setActionCommand(name);
+        b.addActionListener(this);
+        buttons.add(b);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java	(revision 1169)
@@ -18,14 +18,14 @@
 public class HistoryInfoAction extends JosmAction {
 
-	public HistoryInfoAction() {
-		super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."),
-		Shortcut.registerShortcut("core:history", tr("OSM History Information"), KeyEvent.VK_H, Shortcut.GROUP_HOTKEY), true);
-	}
+    public HistoryInfoAction() {
+        super(tr("OSM History Information"), "about",tr("Display history information about OSM ways or nodes."),
+        Shortcut.registerShortcut("core:history", tr("OSM History Information"), KeyEvent.VK_H, Shortcut.GROUP_HOTKEY), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
+    public void actionPerformed(ActionEvent e) {
                 new Visitor() {
                         public void visit(Node n) {
-				OpenBrowser.displayUrl("http://www.openstreetmap.org/browse/node/" + n.id + "/history");
-			}
+                OpenBrowser.displayUrl("http://www.openstreetmap.org/browse/node/" + n.id + "/history");
+            }
 
                         public void visit(Way w) {
@@ -43,5 +43,5 @@
                 }.visitAll();
 
-	}
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 1169)
@@ -26,59 +26,59 @@
 
 public class JoinNodeWayAction extends JosmAction {
-	public JoinNodeWayAction() {
-	    super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"),
-			Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join node to way")), KeyEvent.VK_J, Shortcut.GROUP_EDIT), true);
-	}
+    public JoinNodeWayAction() {
+        super(tr("Join node to way"), "joinnodeway", tr("Join a node into the nearest way segments"),
+            Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join node to way")), KeyEvent.VK_J, Shortcut.GROUP_EDIT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return;
-		Node node = (Node) sel.iterator().next();
+    public void actionPerformed(ActionEvent e) {
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return;
+        Node node = (Node) sel.iterator().next();
 
-		List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
-			Main.map.mapView.getPoint(node.eastNorth));
-		HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
-		for (WaySegment ws : wss) {
-			List<Integer> is;
-			if (insertPoints.containsKey(ws.way)) {
-				is = insertPoints.get(ws.way);
-			} else {
-				is = new ArrayList<Integer>();
-				insertPoints.put(ws.way, is);
-			}
+        List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
+            Main.map.mapView.getPoint(node.eastNorth));
+        HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
+        for (WaySegment ws : wss) {
+            List<Integer> is;
+            if (insertPoints.containsKey(ws.way)) {
+                is = insertPoints.get(ws.way);
+            } else {
+                is = new ArrayList<Integer>();
+                insertPoints.put(ws.way, is);
+            }
 
-			if (ws.way.nodes.get(ws.lowerIndex) != node
-					&& ws.way.nodes.get(ws.lowerIndex+1) != node) {
-				is.add(ws.lowerIndex);
-			}
-		}
+            if (ws.way.nodes.get(ws.lowerIndex) != node
+                    && ws.way.nodes.get(ws.lowerIndex+1) != node) {
+                is.add(ws.lowerIndex);
+            }
+        }
 
-		Collection<Command> cmds = new LinkedList<Command>();
-		for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
-			Way w = insertPoint.getKey();
-			Way wnew = new Way(w);
-			List<Integer> is = insertPoint.getValue();
-			pruneSuccsAndReverse(is);
-			for (int i : is) wnew.nodes.add(i+1, node);
-			cmds.add(new ChangeCommand(w, wnew));
-		}
+        Collection<Command> cmds = new LinkedList<Command>();
+        for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
+            Way w = insertPoint.getKey();
+            Way wnew = new Way(w);
+            List<Integer> is = insertPoint.getValue();
+            pruneSuccsAndReverse(is);
+            for (int i : is) wnew.nodes.add(i+1, node);
+            cmds.add(new ChangeCommand(w, wnew));
+        }
 
-		Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
-		Main.map.repaint();
-	}
+        Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
+        Main.map.repaint();
+    }
 
-	private static void pruneSuccsAndReverse(List<Integer> is) {
-		//if (is.size() < 2) return;
+    private static void pruneSuccsAndReverse(List<Integer> is) {
+        //if (is.size() < 2) return;
 
-		HashSet<Integer> is2 = new HashSet<Integer>();
-		for (int i : is) {
-			if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
-				is2.add(i);
-			}
-		}
-		is.clear();
-		is.addAll(is2);
-		Collections.sort(is);
-		Collections.reverse(is);
-	}
+        HashSet<Integer> is2 = new HashSet<Integer>();
+        for (int i : is) {
+            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
+                is2.add(i);
+            }
+        }
+        is.clear();
+        is.addAll(is2);
+        Collections.sort(is);
+        Collections.reverse(is);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 1169)
@@ -25,99 +25,99 @@
 abstract public class JosmAction extends AbstractAction implements Destroyable {
 
-	@Deprecated
-	public KeyStroke shortcut;
-	protected Shortcut sc;
+    @Deprecated
+    public KeyStroke shortcut;
+    protected Shortcut sc;
 
-	public Shortcut getShortcut() {
-		if (sc == null) {
-			sc = Shortcut.registerShortcut("core:none", "No Shortcut", 0, Shortcut.GROUP_NONE);
-			sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut,
-			                   // we shouldn't allow the user to change it...
-		}
-		return sc;
-	}
+    public Shortcut getShortcut() {
+        if (sc == null) {
+            sc = Shortcut.registerShortcut("core:none", "No Shortcut", 0, Shortcut.GROUP_NONE);
+            sc.setAutomatic(); // as this shortcut is shared by all action that don't want to have a shortcut,
+                               // we shouldn't allow the user to change it...
+        }
+        return sc;
+    }
 
-	@Deprecated
-	public JosmAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean register) {
-		super(name, iconName == null ? null : ImageProvider.get(iconName));
-		setHelpId();
-		if (shortcut != 0) {
-			int group = Shortcut.GROUP_LAYER; //GROUP_NONE;
-			if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) {
-				group = Shortcut.GROUP_MENU;
-			} else if (modifier == 0) {
-				group = Shortcut.GROUP_EDIT;
-			}
-			sc = Shortcut.registerShortcut("auto:"+name, name, shortcut, group);
-			this.shortcut = sc.getKeyStroke();
-			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
-			Main.contentPane.getActionMap().put(name, this);
-		}
-		putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
-		putValue("toolbar", iconName);
+    @Deprecated
+    public JosmAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean register) {
+        super(name, iconName == null ? null : ImageProvider.get(iconName));
+        setHelpId();
+        if (shortcut != 0) {
+            int group = Shortcut.GROUP_LAYER; //GROUP_NONE;
+            if (((modifier & InputEvent.CTRL_MASK) != 0) || ((modifier & InputEvent.CTRL_DOWN_MASK) != 0)) {
+                group = Shortcut.GROUP_MENU;
+            } else if (modifier == 0) {
+                group = Shortcut.GROUP_EDIT;
+            }
+            sc = Shortcut.registerShortcut("auto:"+name, name, shortcut, group);
+            this.shortcut = sc.getKeyStroke();
+            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
+            Main.contentPane.getActionMap().put(name, this);
+        }
+        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
+        putValue("toolbar", iconName);
     if (register)
-    	Main.toolbar.register(this);
-	}
+        Main.toolbar.register(this);
+    }
 
-	/**
-	 * The new super for all actions.
-	 *
-	 * Use this super constructor to setup your action. It takes 5 parameters:
-	 *
-	 * name - the action's text as displayed on the menu (if it is added to a menu)
-	 * iconName - the filename of the icon to use
-	 * tooltip - a longer description of the action that will be displayed in the tooltip. Please note
-	 *           that html is not supported for menu action on some platforms
-	 * shortcut - a ready-created shortcut object or null if you don't want a shortcut. But you always
-	 *            do want a shortcut, remember you can alway register it with group=none, so you
-	 *            won't be assigned a shurtcut unless the user configures one. If you pass null here,
-	 *            the user CANNOT configure a shortcut for your action.
-	 * register - register this action for the toolbar preferences?
-	 */
-	public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) {
-		super(name, iconName == null ? null : ImageProvider.get(iconName));
-		setHelpId();
-		sc = shortcut;
-		if (sc != null) {
-			this.shortcut = sc.getKeyStroke();
-			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
-			Main.contentPane.getActionMap().put(name, this);
-		}
-		putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
-		putValue("toolbar", iconName);
+    /**
+     * The new super for all actions.
+     *
+     * Use this super constructor to setup your action. It takes 5 parameters:
+     *
+     * name - the action's text as displayed on the menu (if it is added to a menu)
+     * iconName - the filename of the icon to use
+     * tooltip - a longer description of the action that will be displayed in the tooltip. Please note
+     *           that html is not supported for menu action on some platforms
+     * shortcut - a ready-created shortcut object or null if you don't want a shortcut. But you always
+     *            do want a shortcut, remember you can alway register it with group=none, so you
+     *            won't be assigned a shurtcut unless the user configures one. If you pass null here,
+     *            the user CANNOT configure a shortcut for your action.
+     * register - register this action for the toolbar preferences?
+     */
+    public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) {
+        super(name, iconName == null ? null : ImageProvider.get(iconName));
+        setHelpId();
+        sc = shortcut;
+        if (sc != null) {
+            this.shortcut = sc.getKeyStroke();
+            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
+            Main.contentPane.getActionMap().put(name, this);
+        }
+        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
+        putValue("toolbar", iconName);
     if (register)
-    	Main.toolbar.register(this);
-	}
+        Main.toolbar.register(this);
+    }
 
-	public void destroy() {
-		if (shortcut != null) {
-			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
-			Main.contentPane.getActionMap().remove(sc.getKeyStroke());
-		}
-	}
+    public void destroy() {
+        if (shortcut != null) {
+            Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
+            Main.contentPane.getActionMap().remove(sc.getKeyStroke());
+        }
+    }
 
-	public JosmAction() {
-		setHelpId();
-	}
+    public JosmAction() {
+        setHelpId();
+    }
 
-	/**
-	 * needs to be overridden to be useful
-	 */
-	public void pasteBufferChanged(DataSet newPasteBuffer) {
-		return;
-	}
+    /**
+     * needs to be overridden to be useful
+     */
+    public void pasteBufferChanged(DataSet newPasteBuffer) {
+        return;
+    }
 
-	/**
-	 * needs to be overridden to be useful
-	 */
-	public void addListener(JosmAction a) {
-		return;
-	}
+    /**
+     * needs to be overridden to be useful
+     */
+    public void addListener(JosmAction a) {
+        return;
+    }
 
-	private void setHelpId() {
-		String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
-		if (helpId.endsWith("Action"))
-			helpId = helpId.substring(0, helpId.length()-6);
-		putValue("help", helpId);
-	}
+    private void setHelpId() {
+        String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
+        if (helpId.endsWith("Action"))
+            helpId = helpId.substring(0, helpId.length()-6);
+        putValue("help", helpId);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 1169)
@@ -52,245 +52,245 @@
 public class MergeNodesAction extends JosmAction implements SelectionChangedListener {
 
-	public MergeNodesAction() {
-		super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."),
-		Shortcut.registerShortcut("tools:mergenodes", tr("Tool: {0}", tr("Merge Nodes")), KeyEvent.VK_M, Shortcut.GROUP_EDIT), true);
-		DataSet.selListeners.add(this);
-	}
-
-	public void actionPerformed(ActionEvent event) {
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-		LinkedList<Node> selectedNodes = new LinkedList<Node>();
-
-		// the selection check should stop this procedure starting if
-		// nothing but node are selected - otherwise we don't care
-		// anyway as long as we have at least two nodes
-		for (OsmPrimitive osm : selection)
-			if (osm instanceof Node)
-				selectedNodes.add((Node)osm);
-
-		if (selectedNodes.size() < 2) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two nodes to merge."));
-			return;
-		}
-
-		// Find which node to merge into (i.e. which one will be left)
-		// - this should be combined from two things:
-		//   1. It will be the first node in the list that has a
-		//      positive ID number, OR the first node.
-		//   2. It will be at the position of the first node in the
-		//      list.
-		//
-		// *However* - there is the problem that the selection list is
-		// _not_ in the order that the nodes were clicked on, meaning
-		// that the user doesn't know which node will be chosen (so
-		// (2) is not implemented yet.)  :-(
-		Node useNode = null;
-		for (Node n: selectedNodes) {
-			if (n.id > 0) {
-				useNode = n;
-				break;
-			}
-		}
-		if (useNode == null)
-			useNode = selectedNodes.iterator().next();
-
-		mergeNodes(selectedNodes, useNode);
-	}
-
-	/**
-	 * really do the merging - returns the node that is left
-	 */
-	public static Node mergeNodes(LinkedList<Node> allNodes, Node dest) {
-		Node newNode = new Node(dest);
-
-		// Check whether all ways have identical relationship membership. More
-		// specifically: If one of the selected ways is a member of relation X
-		// in role Y, then all selected ways must be members of X in role Y.
-
-		// FIXME: In a later revision, we should display some sort of conflict
-		// dialog like we do for tags, to let the user choose which relations
-		// should be kept.
-
-		// Step 1, iterate over all relations and figure out which of our
-		// selected ways are members of a relation.
-		HashMap<Pair<Relation,String>, HashSet<Node>> backlinks =
-			new HashMap<Pair<Relation,String>, HashSet<Node>>();
-		HashSet<Relation> relationsUsingNodes = new HashSet<Relation>();
-		for (Relation r : Main.ds.relations) {
-			if (r.deleted || r.incomplete) continue;
-			for (RelationMember rm : r.members) {
-				if (rm.member instanceof Node) {
-					for (Node n : allNodes) {
-						if (rm.member == n) {
-							Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
-							HashSet<Node> nodelinks = new HashSet<Node>();
-							if (backlinks.containsKey(pair)) {
-								nodelinks = backlinks.get(pair);
-							} else {
-								nodelinks = new HashSet<Node>();
-								backlinks.put(pair, nodelinks);
-							}
-							nodelinks.add(n);
-
-							// this is just a cache for later use
-							relationsUsingNodes.add(r);
-						}
-					}
-				}
-			}
-		}
-
-		// Complain to the user if the ways don't have equal memberships.
-		for (HashSet<Node> nodelinks : backlinks.values()) {
-			if (!nodelinks.containsAll(allNodes)) {
-				int option = JOptionPane.showConfirmDialog(Main.parent,
-					tr("The selected nodes have differing relation memberships.  "
-						+ "Do you still want to merge them?"),
-					tr("Merge nodes with different memberships?"),
-					JOptionPane.YES_NO_OPTION);
-				if (option == JOptionPane.YES_OPTION)
-					break;
-				return null;
-			}
-		}
-
-		// collect properties for later conflict resolving
-		Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
-		for (Node n : allNodes) {
-			for (Entry<String,String> e : n.entrySet()) {
-				if (!props.containsKey(e.getKey()))
-					props.put(e.getKey(), new TreeSet<String>());
-				props.get(e.getKey()).add(e.getValue());
-			}
-		}
-
-		// display conflict dialog
-		Map<String, JComboBox> components = new HashMap<String, JComboBox>();
-		JPanel p = new JPanel(new GridBagLayout());
-		for (Entry<String, Set<String>> e : props.entrySet()) {
-			if (TigerUtils.isTigerTag(e.getKey())) {
-				String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
-				newNode.put(e.getKey(), combined);
-			} else if (e.getValue().size() > 1) {
-				if("created_by".equals(e.getKey()))
-				{
-					newNode.put("created_by", "JOSM");
-				}
-				else
-				{
-					JComboBox c = new JComboBox(e.getValue().toArray());
-					c.setEditable(true);
-					p.add(new JLabel(e.getKey()), GBC.std());
-					p.add(Box.createHorizontalStrut(10), GBC.std());
-					p.add(c, GBC.eol());
-					components.put(e.getKey(), c);
-				}
-			} else
-				newNode.put(e.getKey(), e.getValue().iterator().next());
-		}
-
-		if (!components.isEmpty()) {
-			int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
-			if (answer != JOptionPane.OK_OPTION)
-				return null;
-			for (Entry<String, JComboBox> e : components.entrySet())
-				newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString());
-		}
-
-		LinkedList<Command> cmds = new LinkedList<Command>();
-		cmds.add(new ChangeCommand(dest, newNode));
-
-		Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>();
-
-		for (Way w : Main.ds.ways) {
-			if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
-			boolean modify = false;
-			for (Node sn : allNodes) {
-				if (sn == dest) continue;
-				if (w.nodes.contains(sn)) {
-					modify = true;
-				}
-			}
-			if (!modify) continue;
-			// OK - this way contains one or more nodes to change
-			ArrayList<Node> nn = new ArrayList<Node>();
-			Node lastNode = null;
-			for (int i = 0; i < w.nodes.size(); i++) {
-				Node pushNode = w.nodes.get(i);
-				if (allNodes.contains(pushNode)) {
-					pushNode = dest;
-				}
-				if (pushNode != lastNode) {
-					nn.add(pushNode);
-				}
-				lastNode = pushNode;
-			}
-			if (nn.size() < 2) {
-				CollectBackReferencesVisitor backRefs =
-					new CollectBackReferencesVisitor(Main.ds, false);
-				w.visit(backRefs);
-				if (!backRefs.data.isEmpty()) {
-					JOptionPane.showMessageDialog(Main.parent,
-						tr("Cannot merge nodes: " +
-							"Would have to delete a way that is still used."));
-					return null;
-				}
-				del.add(w);
-			} else {
-				Way newWay = new Way(w);
-				newWay.nodes.clear();
-				newWay.nodes.addAll(nn);
-				cmds.add(new ChangeCommand(w, newWay));
-			}
-		}
-
-		// delete any merged nodes
-		del.addAll(allNodes);
-		del.remove(dest);
-		if (!del.isEmpty()) cmds.add(new DeleteCommand(del));
-
-		// modify all relations containing the now-deleted nodes
-		for (Relation r : relationsUsingNodes) {
-			Relation newRel = new Relation(r);
-			newRel.members.clear();
-			HashSet<String> rolesToReAdd = new HashSet<String>();
-			for (RelationMember rm : r.members) {
-				// Don't copy the member if it points to one of our nodes,
-				// just keep a note to re-add it later on.
-				if (allNodes.contains(rm.member)) {
-					rolesToReAdd.add(rm.role);
-				} else {
-					newRel.members.add(rm);
-				}
-			}
-			for (String role : rolesToReAdd) {
-				newRel.members.add(new RelationMember(role, dest));
-			}
-			cmds.add(new ChangeCommand(r, newRel));
-		}
-
-		Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds));
-		Main.ds.setSelected(dest);
-
-		return dest;
-	}
-
-
-	/**
-	 * Enable the "Merge Nodes" menu option if more then one node is selected
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		boolean ok = true;
-		if (newSelection.size() < 2) {
-			setEnabled(false);
-			return;
-		}
-		for (OsmPrimitive osm : newSelection) {
-			if (!(osm instanceof Node)) {
-				ok = false;
-				break;
-			}
-		}
-		setEnabled(ok);
-	}
+    public MergeNodesAction() {
+        super(tr("Merge Nodes"), "mergenodes", tr("Merge nodes into the oldest one."),
+        Shortcut.registerShortcut("tools:mergenodes", tr("Tool: {0}", tr("Merge Nodes")), KeyEvent.VK_M, Shortcut.GROUP_EDIT), true);
+        DataSet.selListeners.add(this);
+    }
+
+    public void actionPerformed(ActionEvent event) {
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+        LinkedList<Node> selectedNodes = new LinkedList<Node>();
+
+        // the selection check should stop this procedure starting if
+        // nothing but node are selected - otherwise we don't care
+        // anyway as long as we have at least two nodes
+        for (OsmPrimitive osm : selection)
+            if (osm instanceof Node)
+                selectedNodes.add((Node)osm);
+
+        if (selectedNodes.size() < 2) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least two nodes to merge."));
+            return;
+        }
+
+        // Find which node to merge into (i.e. which one will be left)
+        // - this should be combined from two things:
+        //   1. It will be the first node in the list that has a
+        //      positive ID number, OR the first node.
+        //   2. It will be at the position of the first node in the
+        //      list.
+        //
+        // *However* - there is the problem that the selection list is
+        // _not_ in the order that the nodes were clicked on, meaning
+        // that the user doesn't know which node will be chosen (so
+        // (2) is not implemented yet.)  :-(
+        Node useNode = null;
+        for (Node n: selectedNodes) {
+            if (n.id > 0) {
+                useNode = n;
+                break;
+            }
+        }
+        if (useNode == null)
+            useNode = selectedNodes.iterator().next();
+
+        mergeNodes(selectedNodes, useNode);
+    }
+
+    /**
+     * really do the merging - returns the node that is left
+     */
+    public static Node mergeNodes(LinkedList<Node> allNodes, Node dest) {
+        Node newNode = new Node(dest);
+
+        // Check whether all ways have identical relationship membership. More
+        // specifically: If one of the selected ways is a member of relation X
+        // in role Y, then all selected ways must be members of X in role Y.
+
+        // FIXME: In a later revision, we should display some sort of conflict
+        // dialog like we do for tags, to let the user choose which relations
+        // should be kept.
+
+        // Step 1, iterate over all relations and figure out which of our
+        // selected ways are members of a relation.
+        HashMap<Pair<Relation,String>, HashSet<Node>> backlinks =
+            new HashMap<Pair<Relation,String>, HashSet<Node>>();
+        HashSet<Relation> relationsUsingNodes = new HashSet<Relation>();
+        for (Relation r : Main.ds.relations) {
+            if (r.deleted || r.incomplete) continue;
+            for (RelationMember rm : r.members) {
+                if (rm.member instanceof Node) {
+                    for (Node n : allNodes) {
+                        if (rm.member == n) {
+                            Pair<Relation,String> pair = new Pair<Relation,String>(r, rm.role);
+                            HashSet<Node> nodelinks = new HashSet<Node>();
+                            if (backlinks.containsKey(pair)) {
+                                nodelinks = backlinks.get(pair);
+                            } else {
+                                nodelinks = new HashSet<Node>();
+                                backlinks.put(pair, nodelinks);
+                            }
+                            nodelinks.add(n);
+
+                            // this is just a cache for later use
+                            relationsUsingNodes.add(r);
+                        }
+                    }
+                }
+            }
+        }
+
+        // Complain to the user if the ways don't have equal memberships.
+        for (HashSet<Node> nodelinks : backlinks.values()) {
+            if (!nodelinks.containsAll(allNodes)) {
+                int option = JOptionPane.showConfirmDialog(Main.parent,
+                    tr("The selected nodes have differing relation memberships.  "
+                        + "Do you still want to merge them?"),
+                    tr("Merge nodes with different memberships?"),
+                    JOptionPane.YES_NO_OPTION);
+                if (option == JOptionPane.YES_OPTION)
+                    break;
+                return null;
+            }
+        }
+
+        // collect properties for later conflict resolving
+        Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
+        for (Node n : allNodes) {
+            for (Entry<String,String> e : n.entrySet()) {
+                if (!props.containsKey(e.getKey()))
+                    props.put(e.getKey(), new TreeSet<String>());
+                props.get(e.getKey()).add(e.getValue());
+            }
+        }
+
+        // display conflict dialog
+        Map<String, JComboBox> components = new HashMap<String, JComboBox>();
+        JPanel p = new JPanel(new GridBagLayout());
+        for (Entry<String, Set<String>> e : props.entrySet()) {
+            if (TigerUtils.isTigerTag(e.getKey())) {
+                String combined = TigerUtils.combineTags(e.getKey(), e.getValue());
+                newNode.put(e.getKey(), combined);
+            } else if (e.getValue().size() > 1) {
+                if("created_by".equals(e.getKey()))
+                {
+                    newNode.put("created_by", "JOSM");
+                }
+                else
+                {
+                    JComboBox c = new JComboBox(e.getValue().toArray());
+                    c.setEditable(true);
+                    p.add(new JLabel(e.getKey()), GBC.std());
+                    p.add(Box.createHorizontalStrut(10), GBC.std());
+                    p.add(c, GBC.eol());
+                    components.put(e.getKey(), c);
+                }
+            } else
+                newNode.put(e.getKey(), e.getValue().iterator().next());
+        }
+
+        if (!components.isEmpty()) {
+            int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter values for all conflicts."), JOptionPane.OK_CANCEL_OPTION);
+            if (answer != JOptionPane.OK_OPTION)
+                return null;
+            for (Entry<String, JComboBox> e : components.entrySet())
+                newNode.put(e.getKey(), e.getValue().getEditor().getItem().toString());
+        }
+
+        LinkedList<Command> cmds = new LinkedList<Command>();
+        cmds.add(new ChangeCommand(dest, newNode));
+
+        Collection<OsmPrimitive> del = new HashSet<OsmPrimitive>();
+
+        for (Way w : Main.ds.ways) {
+            if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
+            boolean modify = false;
+            for (Node sn : allNodes) {
+                if (sn == dest) continue;
+                if (w.nodes.contains(sn)) {
+                    modify = true;
+                }
+            }
+            if (!modify) continue;
+            // OK - this way contains one or more nodes to change
+            ArrayList<Node> nn = new ArrayList<Node>();
+            Node lastNode = null;
+            for (int i = 0; i < w.nodes.size(); i++) {
+                Node pushNode = w.nodes.get(i);
+                if (allNodes.contains(pushNode)) {
+                    pushNode = dest;
+                }
+                if (pushNode != lastNode) {
+                    nn.add(pushNode);
+                }
+                lastNode = pushNode;
+            }
+            if (nn.size() < 2) {
+                CollectBackReferencesVisitor backRefs =
+                    new CollectBackReferencesVisitor(Main.ds, false);
+                w.visit(backRefs);
+                if (!backRefs.data.isEmpty()) {
+                    JOptionPane.showMessageDialog(Main.parent,
+                        tr("Cannot merge nodes: " +
+                            "Would have to delete a way that is still used."));
+                    return null;
+                }
+                del.add(w);
+            } else {
+                Way newWay = new Way(w);
+                newWay.nodes.clear();
+                newWay.nodes.addAll(nn);
+                cmds.add(new ChangeCommand(w, newWay));
+            }
+        }
+
+        // delete any merged nodes
+        del.addAll(allNodes);
+        del.remove(dest);
+        if (!del.isEmpty()) cmds.add(new DeleteCommand(del));
+
+        // modify all relations containing the now-deleted nodes
+        for (Relation r : relationsUsingNodes) {
+            Relation newRel = new Relation(r);
+            newRel.members.clear();
+            HashSet<String> rolesToReAdd = new HashSet<String>();
+            for (RelationMember rm : r.members) {
+                // Don't copy the member if it points to one of our nodes,
+                // just keep a note to re-add it later on.
+                if (allNodes.contains(rm.member)) {
+                    rolesToReAdd.add(rm.role);
+                } else {
+                    newRel.members.add(rm);
+                }
+            }
+            for (String role : rolesToReAdd) {
+                newRel.members.add(new RelationMember(role, dest));
+            }
+            cmds.add(new ChangeCommand(r, newRel));
+        }
+
+        Main.main.undoRedo.add(new SequenceCommand(tr("Merge {0} nodes", allNodes.size()), cmds));
+        Main.ds.setSelected(dest);
+
+        return dest;
+    }
+
+
+    /**
+     * Enable the "Merge Nodes" menu option if more then one node is selected
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        boolean ok = true;
+        if (newSelection.size() < 2) {
+            setEnabled(false);
+            return;
+        }
+        for (OsmPrimitive osm : newSelection) {
+            if (!(osm instanceof Node)) {
+                ok = false;
+                break;
+            }
+        }
+        setEnabled(ok);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/MoveAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/MoveAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/MoveAction.java	(revision 1169)
@@ -26,87 +26,87 @@
 public class MoveAction extends JosmAction {
 
-	public enum Direction { UP, LEFT, RIGHT, DOWN }
-	private Direction myDirection;
+    public enum Direction { UP, LEFT, RIGHT, DOWN }
+    private Direction myDirection;
 
-	// any better idea?
-	private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) {
-		Shortcut sc;
-		String directiontext;
-		if        (dir == Direction.UP)   {
-			directiontext = tr("up");
-			sc = Shortcut.registerShortcut("core:moveup",    tr("Move objects {0}", directiontext), KeyEvent.VK_UP,    Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
-		} else if (dir == Direction.DOWN)  {
-			directiontext = tr("down");
-			sc = Shortcut.registerShortcut("core:movedown",  tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
-		} else if (dir == Direction.LEFT)  {
-			directiontext = tr("left");
-			sc = Shortcut.registerShortcut("core:moveleft",  tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
-		} else { //dir == Direction.RIGHT) {
-			directiontext = tr("right");
-			sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
-		}
-		if (text) {
-			return directiontext;
-		} else {
-			return sc;
-		}
-	}
+    // any better idea?
+    private static Object calltosupermustbefirststatementinconstructor(Direction dir, boolean text) {
+        Shortcut sc;
+        String directiontext;
+        if        (dir == Direction.UP)   {
+            directiontext = tr("up");
+            sc = Shortcut.registerShortcut("core:moveup",    tr("Move objects {0}", directiontext), KeyEvent.VK_UP,    Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
+        } else if (dir == Direction.DOWN)  {
+            directiontext = tr("down");
+            sc = Shortcut.registerShortcut("core:movedown",  tr("Move objects {0}", directiontext), KeyEvent.VK_DOWN,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
+        } else if (dir == Direction.LEFT)  {
+            directiontext = tr("left");
+            sc = Shortcut.registerShortcut("core:moveleft",  tr("Move objects {0}", directiontext), KeyEvent.VK_LEFT,  Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
+        } else { //dir == Direction.RIGHT) {
+            directiontext = tr("right");
+            sc = Shortcut.registerShortcut("core:moveright", tr("Move objects {0}", directiontext), KeyEvent.VK_RIGHT, Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT);
+        }
+        if (text) {
+            return directiontext;
+        } else {
+            return sc;
+        }
+    }
 
-	public MoveAction(Direction dir) {
-		super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null,
-		      tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)),
-		      (Shortcut)calltosupermustbefirststatementinconstructor(dir, false), true);
-		myDirection = dir;
-	}
+    public MoveAction(Direction dir) {
+        super(tr("Move {0}", calltosupermustbefirststatementinconstructor(dir, true)), null,
+              tr("Moves Objects {0}", calltosupermustbefirststatementinconstructor(dir, true)),
+              (Shortcut)calltosupermustbefirststatementinconstructor(dir, false), true);
+        myDirection = dir;
+    }
 
-	public void actionPerformed(ActionEvent event) {
+    public void actionPerformed(ActionEvent event) {
 
-		// find out how many "real" units the objects have to be moved in order to
-		// achive an 1-pixel movement
+        // find out how many "real" units the objects have to be moved in order to
+        // achive an 1-pixel movement
 
-		EastNorth en1 = Main.map.mapView.getEastNorth(100, 100);
-		EastNorth en2 = Main.map.mapView.getEastNorth(101, 101);
+        EastNorth en1 = Main.map.mapView.getEastNorth(100, 100);
+        EastNorth en2 = Main.map.mapView.getEastNorth(101, 101);
 
-		double distx = en2.east() - en1.east();
-		double disty = en2.north() - en1.north();
+        double distx = en2.east() - en1.east();
+        double disty = en2.north() - en1.north();
 
-		switch (myDirection) {
-		case UP:
-			distx = 0;
-			disty = -disty;
-			break;
-		case DOWN:
-			distx = 0;
-			break;
-		case LEFT:
-			disty = 0;
-			distx = -distx;
-		default:
-			disty = 0;
-		}
+        switch (myDirection) {
+        case UP:
+            distx = 0;
+            disty = -disty;
+            break;
+        case DOWN:
+            distx = 0;
+            break;
+        case LEFT:
+            disty = 0;
+            distx = -distx;
+        default:
+            disty = 0;
+        }
 
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-		Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+        Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
 
-		Command c = !Main.main.undoRedo.commands.isEmpty()
-		? Main.main.undoRedo.commands.getLast() : null;
+        Command c = !Main.main.undoRedo.commands.isEmpty()
+        ? Main.main.undoRedo.commands.getLast() : null;
 
-		if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects))
-			((MoveCommand)c).moveAgain(distx, disty);
-		else
-			Main.main.undoRedo.add(
-					c = new MoveCommand(selection, distx, disty));
+        if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).objects))
+            ((MoveCommand)c).moveAgain(distx, disty);
+        else
+            Main.main.undoRedo.add(
+                    c = new MoveCommand(selection, distx, disty));
 
-		for (Node n : affectedNodes) {
-			if (n.coor.isOutSideWorld()) {
-				// Revert move
-				((MoveCommand) c).moveAgain(-distx, -disty);
-				JOptionPane.showMessageDialog(Main.parent,
-						tr("Cannot move objects outside of the world."));
-				return;
-			}
-		}
+        for (Node n : affectedNodes) {
+            if (n.coor.isOutSideWorld()) {
+                // Revert move
+                ((MoveCommand) c).moveAgain(-distx, -disty);
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("Cannot move objects outside of the world."));
+                return;
+            }
+        }
 
-		Main.map.mapView.repaint();
-	}
+        Main.map.mapView.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/NewAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/NewAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/NewAction.java	(revision 1169)
@@ -14,11 +14,11 @@
 public class NewAction extends JosmAction {
 
-	public NewAction() {
-		super(tr("New"), "new", tr("Create a new map."),
-		Shortcut.registerShortcut("system:new", tr("File: {0}", tr("New")), KeyEvent.VK_N, Shortcut.GROUP_MENU), true);
-	}
+    public NewAction() {
+        super(tr("New"), "new", tr("Create a new map."),
+        Shortcut.registerShortcut("system:new", tr("File: {0}", tr("New")), KeyEvent.VK_N, Shortcut.GROUP_MENU), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Main.main.addLayer(new OsmDataLayer(new DataSet(), tr("unnamed"), null));
-	}
+    public void actionPerformed(ActionEvent e) {
+        Main.main.addLayer(new OsmDataLayer(new DataSet(), tr("unnamed"), null));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java	(revision 1169)
@@ -35,135 +35,135 @@
 public class OpenFileAction extends DiskAccessAction {
 
-	/**
-	 * Create an open action. The name is "Open a file".
-	 */
-	public OpenFileAction() {
-		super(tr("Open ..."), "open", tr("Open a file."),
-		Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU));
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		JFileChooser fc = createAndOpenFileChooser(true, true, null);
-		if (fc == null)
-			return;
-		File[] files = fc.getSelectedFiles();
-		for (int i = files.length; i > 0; --i)
-			openFile(files[i-1]);
-	}
-
-	/**
-	 * Open the given file.
-	 */
-	public void openFile(File file) {
-		try {
-			if (asGpxData(file.getName()))
-				openFileAsGpx(file);
-			else if (asNmeaData(file.getName()))
-				openFileAsNmea(file);
-			else
-				openAsData(file);
-		} catch (SAXException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage());
-		} catch (IOException x) {
-			x.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage());
-		}
-	}
-
-	private void openAsData(File file) throws SAXException, IOException, FileNotFoundException {
-		String fn = file.getName();
-		if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
-			DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg);
-			OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file);
-			Main.main.addLayer(layer);
-			layer.fireDataChange();
-		}
-		else
-			JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1)));
-	}
-
-	private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException {
-		String fn = file.getName();
-		if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
-			GpxReader r = null;
-			InputStream is;
-			if (file.getName().endsWith(".gpx.gz")) {
-				is = new GZIPInputStream(new FileInputStream(file));
-			} else {
-				is = new FileInputStream(file);
-			}
-			// Workaround for SAX BOM bug
-			// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835
-			if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) {
-				is.close();
-				if (file.getName().endsWith(".gpx.gz")) {
-					is = new GZIPInputStream(new FileInputStream(file));
-				} else {
-					is = new FileInputStream(file);
-				}
-			}
-			r = new GpxReader(is,file.getAbsoluteFile().getParentFile());
-			r.data.storageFile = file;
-			GpxLayer gpxLayer = new GpxLayer(r.data, fn);
-			Main.main.addLayer(gpxLayer);
-			if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
-				MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
-				if (ml.data.size() > 0) {
-					Main.main.addLayer(ml);
-				}
-			}
-
-		} else {
-			throw new IllegalStateException();
-		}
-    }
-	
-	private void showNmeaInfobox(boolean success, NmeaReader r) {
-		String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" +
-		tr("Malformed sentences: ") + r.getParserMalformed() + "\n" +
-		tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n";
-		if(!success) // don't scare the user unneccessarily
-			msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n";
-		msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates();
-		if(success) {	
-			JOptionPane.showMessageDialog(
-				Main.parent, msg,
-				tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE);
-		} else {
-			JOptionPane.showMessageDialog(
-				Main.parent, msg,
-				tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE);
-		}
-	}
-
-	private void openFileAsNmea(File file) throws IOException, FileNotFoundException {
-		String fn = file.getName();
-		if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) {
-			NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile());
-			if(r.getNumberOfCoordinates()>0) {
-				r.data.storageFile = file;
-				GpxLayer gpxLayer = new GpxLayer(r.data, fn);
-				Main.main.addLayer(gpxLayer);
-				if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
-					MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
-					if (ml.data.size() > 0) {
-						Main.main.addLayer(ml);
-					}
-				}
-			}
-			showNmeaInfobox(r.getNumberOfCoordinates()>0, r);
-		} else {
-			throw new IllegalStateException();
-		}
+    /**
+     * Create an open action. The name is "Open a file".
+     */
+    public OpenFileAction() {
+        super(tr("Open ..."), "open", tr("Open a file."),
+        Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open ...")), KeyEvent.VK_O, Shortcut.GROUP_MENU));
     }
 
-	private boolean asGpxData(String fn) {
-		return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn);
-	}
+    public void actionPerformed(ActionEvent e) {
+        JFileChooser fc = createAndOpenFileChooser(true, true, null);
+        if (fc == null)
+            return;
+        File[] files = fc.getSelectedFiles();
+        for (int i = files.length; i > 0; --i)
+            openFile(files[i-1]);
+    }
 
-	private boolean asNmeaData(String fn) {
-		return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn);
-	}
+    /**
+     * Open the given file.
+     */
+    public void openFile(File file) {
+        try {
+            if (asGpxData(file.getName()))
+                openFileAsGpx(file);
+            else if (asNmeaData(file.getName()))
+                openFileAsNmea(file);
+            else
+                openAsData(file);
+        } catch (SAXException x) {
+            x.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Error while parsing {0}",file.getName())+": "+x.getMessage());
+        } catch (IOException x) {
+            x.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not read \"{0}\"",file.getName())+"\n"+x.getMessage());
+        }
+    }
+
+    private void openAsData(File file) throws SAXException, IOException, FileNotFoundException {
+        String fn = file.getName();
+        if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(fn)) {
+            DataSet dataSet = OsmReader.parseDataSet(new FileInputStream(file), null, Main.pleaseWaitDlg);
+            OsmDataLayer layer = new OsmDataLayer(dataSet, file.getName(), file);
+            Main.main.addLayer(layer);
+            layer.fireDataChange();
+        }
+        else
+            JOptionPane.showMessageDialog(Main.parent, fn+": "+tr("Unknown file extension: {0}", fn.substring(file.getName().lastIndexOf('.')+1)));
+    }
+
+    private void openFileAsGpx(File file) throws SAXException, IOException, FileNotFoundException {
+        String fn = file.getName();
+        if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn)) {
+            GpxReader r = null;
+            InputStream is;
+            if (file.getName().endsWith(".gpx.gz")) {
+                is = new GZIPInputStream(new FileInputStream(file));
+            } else {
+                is = new FileInputStream(file);
+            }
+            // Workaround for SAX BOM bug
+            // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206835
+            if(!((is.read()==0xef)&&(is.read()==0xbb)&&(is.read()==0xbf))) {
+                is.close();
+                if (file.getName().endsWith(".gpx.gz")) {
+                    is = new GZIPInputStream(new FileInputStream(file));
+                } else {
+                    is = new FileInputStream(file);
+                }
+            }
+            r = new GpxReader(is,file.getAbsoluteFile().getParentFile());
+            r.data.storageFile = file;
+            GpxLayer gpxLayer = new GpxLayer(r.data, fn);
+            Main.main.addLayer(gpxLayer);
+            if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
+                MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
+                if (ml.data.size() > 0) {
+                    Main.main.addLayer(ml);
+                }
+            }
+
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    private void showNmeaInfobox(boolean success, NmeaReader r) {
+        String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" +
+        tr("Malformed sentences: ") + r.getParserMalformed() + "\n" +
+        tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n";
+        if(!success) // don't scare the user unneccessarily
+            msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n";
+        msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates();
+        if(success) {
+            JOptionPane.showMessageDialog(
+                Main.parent, msg,
+                tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE);
+        } else {
+            JOptionPane.showMessageDialog(
+                Main.parent, msg,
+                tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    private void openFileAsNmea(File file) throws IOException, FileNotFoundException {
+        String fn = file.getName();
+        if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) {
+            NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile());
+            if(r.getNumberOfCoordinates()>0) {
+                r.data.storageFile = file;
+                GpxLayer gpxLayer = new GpxLayer(r.data, fn);
+                Main.main.addLayer(gpxLayer);
+                if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
+                    MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
+                    if (ml.data.size() > 0) {
+                        Main.main.addLayer(ml);
+                    }
+                }
+            }
+            showNmeaInfobox(r.getNumberOfCoordinates()>0, r);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    private boolean asGpxData(String fn) {
+        return ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(fn);
+    }
+
+    private boolean asNmeaData(String fn) {
+        return ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn);
+    }
 
 
Index: trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 1169)
@@ -42,33 +42,33 @@
 public class OpenLocationAction extends JosmAction {
 
-	/**
-	 * Create an open action. The name is "Open a file".
-	 */
-	public OpenLocationAction() {
-		super(tr("Open Location..."), "openlocation", tr("Open a URL."),
-		Shortcut.registerShortcut("system:open_location", tr("File: {0}", tr("Open Location...")), KeyEvent.VK_L, Shortcut.GROUP_MENU), true);
-	}
+    /**
+     * Create an open action. The name is "Open a file".
+     */
+    public OpenLocationAction() {
+        super(tr("Open Location..."), "openlocation", tr("Open a URL."),
+        Shortcut.registerShortcut("system:open_location", tr("File: {0}", tr("Open Location...")), KeyEvent.VK_L, Shortcut.GROUP_MENU), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
+    public void actionPerformed(ActionEvent e) {
 
-	    JCheckBox layer = new JCheckBox(tr("Separate Layer"));
-	    layer.setSelected(Main.pref.getBoolean("download.newlayer"));
-	    JPanel all = new JPanel(new GridBagLayout());
-	    all.add(new JLabel("Enter URL to download:"), GBC.eol());
-	    JTextField urltext = new JTextField(40);
-	    all.add(urltext, GBC.eol());
-	    all.add(layer, GBC.eol());
-	    int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Download Location"), JOptionPane.OK_CANCEL_OPTION);
-	    if (answer != JOptionPane.OK_OPTION)
-	        return;
-	    openUrl(layer.isSelected(), urltext.getText());
-	}
+        JCheckBox layer = new JCheckBox(tr("Separate Layer"));
+        layer.setSelected(Main.pref.getBoolean("download.newlayer"));
+        JPanel all = new JPanel(new GridBagLayout());
+        all.add(new JLabel("Enter URL to download:"), GBC.eol());
+        JTextField urltext = new JTextField(40);
+        all.add(urltext, GBC.eol());
+        all.add(layer, GBC.eol());
+        int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Download Location"), JOptionPane.OK_CANCEL_OPTION);
+        if (answer != JOptionPane.OK_OPTION)
+            return;
+        openUrl(layer.isSelected(), urltext.getText());
+    }
 
-	/**
-	 * Open the given file.
-	 */
-	public void openUrl(boolean new_layer, String url) {
-	    new DownloadOsmTask().loadUrl(new_layer, url);
-	}
+    /**
+     * Open the given file.
+     */
+    public void openUrl(boolean new_layer, String url) {
+        new DownloadOsmTask().loadUrl(new_layer, url);
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java	(revision 1169)
@@ -28,6 +28,6 @@
 
 /**
- * Align edges of a way so all angles are right angles. 
- * 
+ * Align edges of a way so all angles are right angles.
+ *
  * 1. Find orientation of all edges
  * 2. Compute main orientation, weighted by length of edge, normalized to angles between 0 and pi/2
@@ -38,12 +38,12 @@
 public final class OrthogonalizeAction extends JosmAction {
 
-	public OrthogonalizeAction() {
-        super(tr("Orthogonalize shape"), 
-            "ortho", 
+    public OrthogonalizeAction() {
+        super(tr("Orthogonalize shape"),
+            "ortho",
             tr("Move nodes so all angles are 90 or 270deg"),
-            Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")), 
-            KeyEvent.VK_Q, 
+            Shortcut.registerShortcut("tools:orthogonalize", tr("Tool: {0}", tr("Orthogonalize")),
+            KeyEvent.VK_Q,
             Shortcut.GROUP_EDIT), true);
-	}
+    }
 
     public void actionPerformed(ActionEvent e) {
@@ -60,5 +60,5 @@
                     JOptionPane.showMessageDialog(Main.parent, tr("Only two nodes allowed"));
                     return;
-                } 
+                }
                 dirnodes.add((Node) osm);
                 continue;
@@ -68,5 +68,5 @@
                 JOptionPane.showMessageDialog(Main.parent, tr("Selection must consist only of ways."));
                 return;
-            } 
+            }
 
             // Check if every way is made of at least four segments and closed
@@ -78,5 +78,5 @@
 
             // Check if every edge in the way is a definite edge of at least 45 degrees of direction change
-            // Otherwise, two segments could be turned into same direction and intersection would fail. 
+            // Otherwise, two segments could be turned into same direction and intersection would fail.
             // Or changes of shape would be too serious.
             for (int i1=0; i1 < way.nodes.size()-1; i1++) {
@@ -116,6 +116,6 @@
         boolean use_dirnodes = false;
 
-        if (dirnodes.size() == 2) { 
-            // When selection contains two nodes, use the nodes to compute a direction 
+        if (dirnodes.size() == 2) {
+            // When selection contains two nodes, use the nodes to compute a direction
             // to align all ways to
             align_to_heading = normalize_angle(dirnodes.get(0).eastNorth.heading(dirnodes.get(1).eastNorth));
@@ -124,5 +124,5 @@
 
         for (OsmPrimitive osm : sel) {
-            if(!(osm instanceof Way)) 
+            if(!(osm instanceof Way))
                 continue;
 
@@ -164,7 +164,7 @@
 
                 if (angle_diff_max > Math.PI/3) {
-                    // rearrange headings: everything < 0 gets PI/2-rotated 
+                    // rearrange headings: everything < 0 gets PI/2-rotated
                     for (int i=0; i < sides; i++) {
-                        if (headings[i] < 0) 
+                        if (headings[i] < 0)
                             headings[i] += Math.PI/2;
                     }
@@ -183,11 +183,11 @@
                     sum_weights += weights[i];
                 }
-                align_to_heading = normalize_angle(sum_weighted_headings/sum_weights); 
+                align_to_heading = normalize_angle(sum_weighted_headings/sum_weights);
             }
 
 
             for (int i=0; i < sides; i++) {
-                // Compute handy indices of three nodes to be used in one loop iteration. 
-                // We use segments (i1,i2) and (i2,i3), align them and compute the new 
+                // Compute handy indices of three nodes to be used in one loop iteration.
+                // We use segments (i1,i2) and (i2,i3), align them and compute the new
                 // position of the i2-node as the intersection of the realigned (i1,i2), (i2,i3) segments
                 // Not the most efficient algorithm, but we don't handle millions of nodes...
@@ -212,9 +212,9 @@
 
                 // compute intersection of segments
-                double u=det(B.east() - A.east(), B.north() - A.north(), 
+                double u=det(B.east() - A.east(), B.north() - A.north(),
                         C.east() - D.east(), C.north() - D.north());
 
                 // Check for parallel segments and do nothing if they are
-                // In practice this will probably only happen when a way has 
+                // In practice this will probably only happen when a way has
                 // been duplicated
 
@@ -225,5 +225,5 @@
                 // if the segment is scaled to length 1
 
-                double q = det(B.north() - C.north(), B.east() - C.east(), 
+                double q = det(B.north() - C.north(), B.east() - C.east(),
                         D.north() - C.north(), D.east() - C.east()) / u;
                 EastNorth intersection = new EastNorth(
@@ -239,5 +239,5 @@
                     cmds.add(new MoveCommand(n, dx, dy));
                 }
-            }  
+            }
         }
 
Index: trunk/src/org/openstreetmap/josm/actions/PasteAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/PasteAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/PasteAction.java	(revision 1169)
@@ -29,82 +29,82 @@
 
     public PasteAction() {
-    	super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
-			Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true);
-			setEnabled(false);
+        super(tr("Paste"), "paste", tr("Paste contents of paste buffer."),
+            Shortcut.registerShortcut("system:paste", tr("Edit: {0}", tr("Paste")), KeyEvent.VK_V, Shortcut.GROUP_MENU), true);
+            setEnabled(false);
     }
 
-	public void actionPerformed(ActionEvent e) {
-		DataSet pasteBuffer = Main.pasteBuffer;
+    public void actionPerformed(ActionEvent e) {
+        DataSet pasteBuffer = Main.pasteBuffer;
 
-		/* Find the middle of the pasteBuffer area */
-		double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
-		for (Node n : pasteBuffer.nodes) {
-			double east = n.eastNorth.east();
-			double north = n.eastNorth.north();
-			if (east > maxEast) { maxEast = east; }
-			if (east < minEast) { minEast = east; }
-			if (north > maxNorth) { maxNorth = north; }
-			if (north < minNorth) { minNorth = north; }
-		}
+        /* Find the middle of the pasteBuffer area */
+        double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
+        for (Node n : pasteBuffer.nodes) {
+            double east = n.eastNorth.east();
+            double north = n.eastNorth.north();
+            if (east > maxEast) { maxEast = east; }
+            if (east < minEast) { minEast = east; }
+            if (north > maxNorth) { maxNorth = north; }
+            if (north < minNorth) { minNorth = north; }
+        }
 
-		EastNorth mPosition;
-		if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){
-			mPosition = Main.map.mapView.getCenter();
-		} else {
-			mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY());
-		}
+        EastNorth mPosition;
+        if((e.getModifiers() & ActionEvent.CTRL_MASK) ==0){
+            mPosition = Main.map.mapView.getCenter();
+        } else {
+            mPosition = Main.map.mapView.getEastNorth(Main.map.mapView.lastMEvent.getX(), Main.map.mapView.lastMEvent.getY());
+        }
 
-		double offsetEast  = mPosition.east() - (maxEast + minEast)/2.0;
-		double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
+        double offsetEast  = mPosition.east() - (maxEast + minEast)/2.0;
+        double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
 
-		HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
-		  /* temporarily maps old nodes to new so we can do a true deep copy */
+        HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
+          /* temporarily maps old nodes to new so we can do a true deep copy */
 
-		/* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */
-		for (Node n : pasteBuffer.nodes) {
-			Node nnew = new Node(n);
-			nnew.id = 0;
-			/* adjust the coordinates to the middle of the visible map area */
-			nnew.eastNorth = new EastNorth(nnew.eastNorth.east() + offsetEast, nnew.eastNorth.north() + offsetNorth);
-			nnew.coor = Main.proj.eastNorth2latlon(nnew.eastNorth);
-			map.put(n, nnew);
-		}
-		for (Way w : pasteBuffer.ways) {
-			Way wnew = new Way();
-			wnew.cloneFrom(w);
-			wnew.id = 0;
-			/* make sure we reference the new nodes corresponding to the old ones */
-			List<Node> nodes = new ArrayList<Node>();
-			for (Node n : w.nodes) {
-				nodes.add((Node)map.get(n));
-			}
-			wnew.nodes.clear();
-			wnew.nodes.addAll(nodes);
-			map.put(w, wnew);
-		}
-		for (Relation r : pasteBuffer.relations) {
-			Relation rnew = new Relation(r);
-			rnew.id = 0;
-			List<RelationMember> members = new ArrayList<RelationMember>();
-			for (RelationMember m : r.members) {
-				RelationMember mnew = new RelationMember(m);
-				mnew.member = map.get(m.member);
-				members.add(mnew);
-			}
-			rnew.members.clear();
-			rnew.members.addAll(members);
-			map.put(r, rnew);
-		}
+        /* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */
+        for (Node n : pasteBuffer.nodes) {
+            Node nnew = new Node(n);
+            nnew.id = 0;
+            /* adjust the coordinates to the middle of the visible map area */
+            nnew.eastNorth = new EastNorth(nnew.eastNorth.east() + offsetEast, nnew.eastNorth.north() + offsetNorth);
+            nnew.coor = Main.proj.eastNorth2latlon(nnew.eastNorth);
+            map.put(n, nnew);
+        }
+        for (Way w : pasteBuffer.ways) {
+            Way wnew = new Way();
+            wnew.cloneFrom(w);
+            wnew.id = 0;
+            /* make sure we reference the new nodes corresponding to the old ones */
+            List<Node> nodes = new ArrayList<Node>();
+            for (Node n : w.nodes) {
+                nodes.add((Node)map.get(n));
+            }
+            wnew.nodes.clear();
+            wnew.nodes.addAll(nodes);
+            map.put(w, wnew);
+        }
+        for (Relation r : pasteBuffer.relations) {
+            Relation rnew = new Relation(r);
+            rnew.id = 0;
+            List<RelationMember> members = new ArrayList<RelationMember>();
+            for (RelationMember m : r.members) {
+                RelationMember mnew = new RelationMember(m);
+                mnew.member = map.get(m.member);
+                members.add(mnew);
+            }
+            rnew.members.clear();
+            rnew.members.addAll(members);
+            map.put(r, rnew);
+        }
 
-		/* Now execute the commands to add the dupicated contents of the paste buffer to the map */
-		Collection<OsmPrimitive> osms = map.values();
-		Collection<Command> clist = new LinkedList<Command>();
-		for (OsmPrimitive osm : osms) {
-			clist.add(new AddCommand(osm));
-		}
+        /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
+        Collection<OsmPrimitive> osms = map.values();
+        Collection<Command> clist = new LinkedList<Command>();
+        for (OsmPrimitive osm : osms) {
+            clist.add(new AddCommand(osm));
+        }
 
-		Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist));
-		Main.ds.setSelected(osms);
-		Main.map.mapView.repaint();
+        Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist));
+        Main.ds.setSelected(osms);
+        Main.map.mapView.repaint();
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java	(revision 1169)
@@ -24,85 +24,85 @@
 public final class PasteTagsAction extends JosmAction implements SelectionChangedListener {
 
-	public PasteTagsAction(JosmAction copyAction) {
-		super(tr("Paste Tags"), "pastetags",
-			tr("Apply tags of contents of paste buffer to all selected items."),
-			Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
-		DataSet.selListeners.add(this);
-		copyAction.addListener(this);
-		setEnabled(false);
-	}
+    public PasteTagsAction(JosmAction copyAction) {
+        super(tr("Paste Tags"), "pastetags",
+            tr("Apply tags of contents of paste buffer to all selected items."),
+            Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
+        DataSet.selListeners.add(this);
+        copyAction.addListener(this);
+        setEnabled(false);
+    }
 
-	private void pasteKeys(Collection<Command> clist, Collection<? extends OsmPrimitive> pasteBufferSubset, Collection<OsmPrimitive> selectionSubset) {
-		/* scan the paste buffer, and add tags to each of the selected objects.
-		 * If a tag already exists, it is overwritten */
-		if (selectionSubset != null && ! selectionSubset.isEmpty()) {
-			for (Iterator<? extends OsmPrimitive> it = pasteBufferSubset.iterator(); it.hasNext();) {
-				OsmPrimitive osm = it.next();
-				Map<String, String> m = osm.keys;
-				if(m != null)
-				{
-					for (String key : m.keySet()) {
-						if (! key.equals("created_by"))
-							clist.add(new ChangePropertyCommand(selectionSubset, key, osm.keys.get(key)));
-					}
-				}
-			}
-		}
-	}
+    private void pasteKeys(Collection<Command> clist, Collection<? extends OsmPrimitive> pasteBufferSubset, Collection<OsmPrimitive> selectionSubset) {
+        /* scan the paste buffer, and add tags to each of the selected objects.
+         * If a tag already exists, it is overwritten */
+        if (selectionSubset != null && ! selectionSubset.isEmpty()) {
+            for (Iterator<? extends OsmPrimitive> it = pasteBufferSubset.iterator(); it.hasNext();) {
+                OsmPrimitive osm = it.next();
+                Map<String, String> m = osm.keys;
+                if(m != null)
+                {
+                    for (String key : m.keySet()) {
+                        if (! key.equals("created_by"))
+                            clist.add(new ChangePropertyCommand(selectionSubset, key, osm.keys.get(key)));
+                    }
+                }
+            }
+        }
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Collection<Command> clist = new LinkedList<Command>();
-		pasteKeys(clist, Main.pasteBuffer.nodes, Main.ds.getSelectedNodes());
-		pasteKeys(clist, Main.pasteBuffer.ways, Main.ds.getSelectedWays());
-		pasteKeys(clist, Main.pasteBuffer.relations, Main.ds.getSelectedRelations());
-		Main.main.undoRedo.add(new SequenceCommand(tr("Paste Tags"), clist));
-		Main.ds.setSelected(Main.ds.getSelected()); // to force selection listeners, in particular the tag panel, to update
-		Main.map.mapView.repaint();
-	}
+    public void actionPerformed(ActionEvent e) {
+        Collection<Command> clist = new LinkedList<Command>();
+        pasteKeys(clist, Main.pasteBuffer.nodes, Main.ds.getSelectedNodes());
+        pasteKeys(clist, Main.pasteBuffer.ways, Main.ds.getSelectedWays());
+        pasteKeys(clist, Main.pasteBuffer.relations, Main.ds.getSelectedRelations());
+        Main.main.undoRedo.add(new SequenceCommand(tr("Paste Tags"), clist));
+        Main.ds.setSelected(Main.ds.getSelected()); // to force selection listeners, in particular the tag panel, to update
+        Main.map.mapView.repaint();
+    }
 
-	private boolean containsSameKeysWithDifferentValues(Collection<? extends OsmPrimitive> osms) {
-		Map<String,String> kvSeen = new HashMap<String,String>();
-		for (Iterator<? extends OsmPrimitive> it = osms.iterator(); it.hasNext();) {
-			OsmPrimitive osm = it.next();
-			if (osm.keys == null || osm.keys.isEmpty())
-				continue;
-			for (String key : osm.keys.keySet()) {
-				if (key.equals("created_by")) // we ignore created_by
-					continue;
-				String value = osm.keys.get(key);
-				if (! kvSeen.containsKey(key))
-					kvSeen.put(key, value);
-				else if (! kvSeen.get(key).equals(value))
-					return true;
-			}
-		}
-		return false;
-	}
+    private boolean containsSameKeysWithDifferentValues(Collection<? extends OsmPrimitive> osms) {
+        Map<String,String> kvSeen = new HashMap<String,String>();
+        for (Iterator<? extends OsmPrimitive> it = osms.iterator(); it.hasNext();) {
+            OsmPrimitive osm = it.next();
+            if (osm.keys == null || osm.keys.isEmpty())
+                continue;
+            for (String key : osm.keys.keySet()) {
+                if (key.equals("created_by")) // we ignore created_by
+                    continue;
+                String value = osm.keys.get(key);
+                if (! kvSeen.containsKey(key))
+                    kvSeen.put(key, value);
+                else if (! kvSeen.get(key).equals(value))
+                    return true;
+            }
+        }
+        return false;
+    }
 
-	/**
-	 * Determines whether to enable the widget depending on the contents of the paste
-	 * buffer and current selection
-	 * @param pasteBuffer
-	 */
-	private void possiblyEnable(Collection<? extends OsmPrimitive> selection, DataSet pasteBuffer) {
-		/* only enable if there is something selected to paste into and
-			if we don't have conflicting keys in the pastebuffer */
-		setEnabled(selection != null &&
-				! selection.isEmpty() &&
-				! pasteBuffer.allPrimitives().isEmpty() &&
-				(Main.ds.getSelectedNodes().isEmpty() ||
-					! containsSameKeysWithDifferentValues(pasteBuffer.nodes)) &&
-				(Main.ds.getSelectedWays().isEmpty() ||
-					! containsSameKeysWithDifferentValues(pasteBuffer.ways)) &&
-				(Main.ds.getSelectedRelations().isEmpty() ||
-					! containsSameKeysWithDifferentValues(pasteBuffer.relations)));
-	}
+    /**
+     * Determines whether to enable the widget depending on the contents of the paste
+     * buffer and current selection
+     * @param pasteBuffer
+     */
+    private void possiblyEnable(Collection<? extends OsmPrimitive> selection, DataSet pasteBuffer) {
+        /* only enable if there is something selected to paste into and
+            if we don't have conflicting keys in the pastebuffer */
+        setEnabled(selection != null &&
+                ! selection.isEmpty() &&
+                ! pasteBuffer.allPrimitives().isEmpty() &&
+                (Main.ds.getSelectedNodes().isEmpty() ||
+                    ! containsSameKeysWithDifferentValues(pasteBuffer.nodes)) &&
+                (Main.ds.getSelectedWays().isEmpty() ||
+                    ! containsSameKeysWithDifferentValues(pasteBuffer.ways)) &&
+                (Main.ds.getSelectedRelations().isEmpty() ||
+                    ! containsSameKeysWithDifferentValues(pasteBuffer.relations)));
+    }
 
-	@Override public void pasteBufferChanged(DataSet newPasteBuffer) {
-		possiblyEnable(Main.ds.getSelected(), newPasteBuffer);
-	}
+    @Override public void pasteBufferChanged(DataSet newPasteBuffer) {
+        possiblyEnable(Main.ds.getSelected(), newPasteBuffer);
+    }
 
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		possiblyEnable(newSelection, Main.pasteBuffer);
-	}
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        possiblyEnable(newSelection, Main.pasteBuffer);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/PreferencesAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/PreferencesAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/PreferencesAction.java	(revision 1169)
@@ -25,53 +25,53 @@
 public class PreferencesAction extends JosmAction {
 
-	/**
-	 * Create the preference action with "&Preferences" as label.
-	 */
-	public PreferencesAction() {
-		super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."),
-		Shortcut.registerShortcut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, Shortcut.GROUP_DIRECT), true);
-	}
+    /**
+     * Create the preference action with "&Preferences" as label.
+     */
+    public PreferencesAction() {
+        super(tr("Preferences ..."), "preference", tr("Open a preferences page for global settings."),
+        Shortcut.registerShortcut("system:preferences", tr("Preferences"), KeyEvent.VK_F12, Shortcut.GROUP_DIRECT), true);
+    }
 
-	/**
-	 * Launch the preferences dialog.
-	 */
-	public void actionPerformed(ActionEvent e) {
-		PreferenceDialog prefDlg = new PreferenceDialog();
-		prefDlg.setMinimumSize(new Dimension(400,300));
-		JPanel prefPanel = new JPanel(new GridBagLayout());
-		prefPanel.add(prefDlg, GBC.eol().fill(GBC.BOTH));
+    /**
+     * Launch the preferences dialog.
+     */
+    public void actionPerformed(ActionEvent e) {
+        PreferenceDialog prefDlg = new PreferenceDialog();
+        prefDlg.setMinimumSize(new Dimension(400,300));
+        JPanel prefPanel = new JPanel(new GridBagLayout());
+        prefPanel.add(prefDlg, GBC.eol().fill(GBC.BOTH));
 
-		JOptionPane pane = new JOptionPane(prefPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
-		JDialog dlg = pane.createDialog(Main.parent, tr("Preferences"));
-		dlg.setResizable(true);
-		dlg.setMinimumSize(new Dimension(500,400));
+        JOptionPane pane = new JOptionPane(prefPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
+        JDialog dlg = pane.createDialog(Main.parent, tr("Preferences"));
+        dlg.setResizable(true);
+        dlg.setMinimumSize(new Dimension(500,400));
 
-//		if (dlg.getWidth() > 600)
-//			dlg.setSize(600, dlg.getHeight());
-//		if (dlg.getHeight() > 600)
-//			dlg.setSize(dlg.getWidth(),600);
+//      if (dlg.getWidth() > 600)
+//          dlg.setSize(600, dlg.getHeight());
+//      if (dlg.getHeight() > 600)
+//          dlg.setSize(dlg.getWidth(),600);
 
-		int JOSMWidth = Main.parent.getWidth();
-		int JOSMHeight = Main.parent.getHeight();
+        int JOSMWidth = Main.parent.getWidth();
+        int JOSMHeight = Main.parent.getHeight();
 
-		if (JOSMWidth > 2000 && JOSMWidth >  JOSMHeight * 2)
-			// don't center on horizontal span monitor configurations (yes, can be selfish sometimes)
-			JOSMWidth /= 2;
+        if (JOSMWidth > 2000 && JOSMWidth >  JOSMHeight * 2)
+            // don't center on horizontal span monitor configurations (yes, can be selfish sometimes)
+            JOSMWidth /= 2;
 
-		int targetWidth = JOSMWidth / 2;
-		if (targetWidth < 600) targetWidth = 600;
-		if (targetWidth > 1200) targetWidth = 1200;
-		int targetHeight = (JOSMHeight * 3) / 4;
-		if (targetHeight < 600) targetHeight = 600;
-		if (targetHeight > 1200) targetHeight = 1200;
+        int targetWidth = JOSMWidth / 2;
+        if (targetWidth < 600) targetWidth = 600;
+        if (targetWidth > 1200) targetWidth = 1200;
+        int targetHeight = (JOSMHeight * 3) / 4;
+        if (targetHeight < 600) targetHeight = 600;
+        if (targetHeight > 1200) targetHeight = 1200;
 
-		int targetX = Main.parent.getX() + JOSMWidth / 2 - targetWidth / 2;
-		int targetY = Main.parent.getY() + JOSMHeight / 2 - targetHeight / 2;
+        int targetX = Main.parent.getX() + JOSMWidth / 2 - targetWidth / 2;
+        int targetY = Main.parent.getY() + JOSMHeight / 2 - targetHeight / 2;
 
-		dlg.setBounds(targetX, targetY, targetWidth, targetHeight);
+        dlg.setBounds(targetX, targetY, targetWidth, targetHeight);
 
-		dlg.setVisible(true);
-		if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION)
-			prefDlg.ok();
-	}
+        dlg.setVisible(true);
+        if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION)
+            prefDlg.ok();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/RedoAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/RedoAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/RedoAction.java	(revision 1169)
@@ -17,18 +17,18 @@
 public class RedoAction extends JosmAction {
 
-	/**
-	 * Construct the action with "Redo" as label.
-	 */
-	public RedoAction() {
-		super(tr("Redo"), "redo", tr("Redo the last undone action."),
-		Shortcut.registerShortcut("system:redo", tr("Edit: {0}", tr("Redo")), KeyEvent.VK_Y, Shortcut.GROUP_MENU), true);
-		setEnabled(false);
-	}
+    /**
+     * Construct the action with "Redo" as label.
+     */
+    public RedoAction() {
+        super(tr("Redo"), "redo", tr("Redo the last undone action."),
+        Shortcut.registerShortcut("system:redo", tr("Edit: {0}", tr("Redo")), KeyEvent.VK_Y, Shortcut.GROUP_MENU), true);
+        setEnabled(false);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		if (Main.map == null)
-			return;
-		Main.map.repaint();
-		Main.main.undoRedo.redo();
-	}
+    public void actionPerformed(ActionEvent e) {
+        if (Main.map == null)
+            return;
+        Main.map.repaint();
+        Main.main.undoRedo.redo();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/RenameLayerAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/RenameLayerAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/RenameLayerAction.java	(revision 1169)
@@ -21,75 +21,75 @@
  * Action to rename an specific layer. Provides the option to rename the
  * file, this layer was loaded from as well (if it was loaded from a file).
- * 
+ *
  * @author Imi
  */
 public class RenameLayerAction extends AbstractAction {
 
-	private File file;
-	private Layer layer;
+    private File file;
+    private Layer layer;
 
-	/**
-	 * @param file The file of the original location of this layer.
-	 * 		If null, no possibility to "rename the file as well" is provided. 
-	 */
-	public RenameLayerAction(File file, Layer layer) {
-		super(tr("Rename layer"), ImageProvider.get("dialogs", "edit"));
-		this.file = file;
-		this.layer = layer;
-		this.putValue("help", "Action/LayerRename");
-	}
+    /**
+     * @param file The file of the original location of this layer.
+     *      If null, no possibility to "rename the file as well" is provided.
+     */
+    public RenameLayerAction(File file, Layer layer) {
+        super(tr("Rename layer"), ImageProvider.get("dialogs", "edit"));
+        this.file = file;
+        this.layer = layer;
+        this.putValue("help", "Action/LayerRename");
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Box panel = Box.createVerticalBox();
-		final JTextField name = new JTextField(layer.name);
-		panel.add(name);
-		JCheckBox filerename = new JCheckBox(tr("Also rename the file"));
-		if (Main.applet) {
-			filerename.setEnabled(false);
-			filerename.setSelected(false);
-		} else {
-			panel.add(filerename);
-			filerename.setEnabled(file != null);
-		}
-		if (filerename.isEnabled())
-			filerename.setSelected(Main.pref.getBoolean("layer.rename-file", true));
+    public void actionPerformed(ActionEvent e) {
+        Box panel = Box.createVerticalBox();
+        final JTextField name = new JTextField(layer.name);
+        panel.add(name);
+        JCheckBox filerename = new JCheckBox(tr("Also rename the file"));
+        if (Main.applet) {
+            filerename.setEnabled(false);
+            filerename.setSelected(false);
+        } else {
+            panel.add(filerename);
+            filerename.setEnabled(file != null);
+        }
+        if (filerename.isEnabled())
+            filerename.setSelected(Main.pref.getBoolean("layer.rename-file", true));
 
-		final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
-			@Override public void selectInitialValue() {
-				name.requestFocusInWindow();
-				name.selectAll();
-			}
-		};
-		final JDialog dlg = optionPane.createDialog(Main.parent, tr("Rename layer"));
-		dlg.setVisible(true);
+        final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
+            @Override public void selectInitialValue() {
+                name.requestFocusInWindow();
+                name.selectAll();
+            }
+        };
+        final JDialog dlg = optionPane.createDialog(Main.parent, tr("Rename layer"));
+        dlg.setVisible(true);
 
-		Object answer = optionPane.getValue();
-		if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
-				(answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
-			return;
-		}
+        Object answer = optionPane.getValue();
+        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
+                (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
+            return;
+        }
 
-		String nameText = name.getText();
-		if (filerename.isEnabled()) {
-			Main.pref.put("layer.rename-file", filerename.isSelected());
-			if (filerename.isSelected()) {
-				String newname = nameText;
-				if (newname.indexOf("/") == -1 && newname.indexOf("\\") == -1)
-					newname = file.getParent() + File.separator + newname;
-				String oldname = file.getName();
-				if (name.getText().indexOf('.') == -1 && oldname.indexOf('.') >= 0)
-					newname += oldname.substring(oldname.lastIndexOf('.'));
-				File newFile = new File(newname);
-				if (file.renameTo(newFile)) {
-					layer.associatedFile = newFile;
-					nameText = newFile.getName();
-				} else {
-					JOptionPane.showMessageDialog(Main.parent, tr("Could not rename the file \"{0}\".", file.getPath()));
-					return;
-				}
-			}
-		}
-		layer.name = nameText;
-		Main.parent.repaint();
-	}
+        String nameText = name.getText();
+        if (filerename.isEnabled()) {
+            Main.pref.put("layer.rename-file", filerename.isSelected());
+            if (filerename.isSelected()) {
+                String newname = nameText;
+                if (newname.indexOf("/") == -1 && newname.indexOf("\\") == -1)
+                    newname = file.getParent() + File.separator + newname;
+                String oldname = file.getName();
+                if (name.getText().indexOf('.') == -1 && oldname.indexOf('.') >= 0)
+                    newname += oldname.substring(oldname.lastIndexOf('.'));
+                File newFile = new File(newname);
+                if (file.renameTo(newFile)) {
+                    layer.associatedFile = newFile;
+                    nameText = newFile.getName();
+                } else {
+                    JOptionPane.showMessageDialog(Main.parent, tr("Could not rename the file \"{0}\".", file.getPath()));
+                    return;
+                }
+            }
+        }
+        layer.name = nameText;
+        Main.parent.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 1169)
@@ -28,59 +28,59 @@
 public final class ReverseWayAction extends JosmAction {
 
-	public ReverseWayAction() {
-		super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."),
-		Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true);
-	}
+    public ReverseWayAction() {
+        super(tr("Reverse ways"), "wayflip", tr("Reverse the direction of all selected ways."),
+        Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		final Collection<Way> sel = new LinkedList<Way>();
-		new Visitor() {
-			public void visit(Node n) {
-			}
+    public void actionPerformed(ActionEvent e) {
+        final Collection<Way> sel = new LinkedList<Way>();
+        new Visitor() {
+            public void visit(Node n) {
+            }
 
-			public void visit(Way w) {
-				sel.add(w);
-			}
+            public void visit(Way w) {
+                sel.add(w);
+            }
 
-			public void visit(Relation e) {
-			}
+            public void visit(Relation e) {
+            }
 
-			public void visitAll() {
-				for (OsmPrimitive osm : Main.ds.getSelected())
-					osm.visit(this);
-			}
-		}.visitAll();
+            public void visitAll() {
+                for (OsmPrimitive osm : Main.ds.getSelected())
+                    osm.visit(this);
+            }
+        }.visitAll();
 
-		if (sel.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent,
-			        tr("Please select at least one way."));
-			return;
-		}
+        if (sel.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("Please select at least one way."));
+            return;
+        }
 
-		boolean propertiesUpdated = false;
-		ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
-		Collection<Command> c = new LinkedList<Command>();
-		for (Way w : sel) {
-			Way wnew = new Way(w);
-			Collections.reverse(wnew.nodes);
-			if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
-				try
-				{
-					final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(wnew);
-					propertiesUpdated = propertiesUpdated
-				        || (changePropertyCommands != null && !changePropertyCommands.isEmpty());
-					c.addAll(changePropertyCommands);
-				}
-				catch(UserCancelException ex)
-				{
-					return;
-				}
-			}
-			c.add(new ChangeCommand(w, wnew));
-		}
-		Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
-		if (propertiesUpdated)
-			DataSet.fireSelectionChanged(Main.ds.getSelected());
-		Main.map.repaint();
-	}
+        boolean propertiesUpdated = false;
+        ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
+        Collection<Command> c = new LinkedList<Command>();
+        for (Way w : sel) {
+            Way wnew = new Way(w);
+            Collections.reverse(wnew.nodes);
+            if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
+                try
+                {
+                    final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(wnew);
+                    propertiesUpdated = propertiesUpdated
+                        || (changePropertyCommands != null && !changePropertyCommands.isEmpty());
+                    c.addAll(changePropertyCommands);
+                }
+                catch(UserCancelException ex)
+                {
+                    return;
+                }
+            }
+            c.add(new ChangeCommand(w, wnew));
+        }
+        Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
+        if (propertiesUpdated)
+            DataSet.fireSelectionChanged(Main.ds.getSelected());
+        Main.map.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 1169)
@@ -19,27 +19,27 @@
 public class SaveAction extends SaveActionBase {
 
-	/**
-	 * Construct the action with "Save" as label.
-	 * @param layer Save this layer.
-	 */
-	public SaveAction(Layer layer) {
-		super(tr("Save"), "save", tr("Save the current data."),
-		Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.GROUP_MENU), layer);
-	}
+    /**
+     * Construct the action with "Save" as label.
+     * @param layer Save this layer.
+     */
+    public SaveAction(Layer layer) {
+        super(tr("Save"), "save", tr("Save the current data."),
+        Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.GROUP_MENU), layer);
+    }
 
-	@Override public File getFile(Layer layer) {
-		if (layer instanceof OsmDataLayer) {
-			File f = ((OsmDataLayer)layer).associatedFile;
-			if (f != null) {
-				return f;
-			}
-		}
-		if (layer instanceof GpxLayer) {
-			File f = ((GpxLayer)layer).data.storageFile;
-			if (f != null) {
-				return f;
-			}
-		}
-		return openFileDialog(layer);
-	}
+    @Override public File getFile(Layer layer) {
+        if (layer instanceof OsmDataLayer) {
+            File f = ((OsmDataLayer)layer).associatedFile;
+            if (f != null) {
+                return f;
+            }
+        }
+        if (layer instanceof GpxLayer) {
+            File f = ((GpxLayer)layer).data.storageFile;
+            if (f != null) {
+                return f;
+            }
+        }
+        return openFileDialog(layer);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 1169)
@@ -26,211 +26,211 @@
 public abstract class SaveActionBase extends DiskAccessAction {
 
-	private Layer layer;
-
-	public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
-		super(name, iconName, tooltip, shortcut);
-		this.layer = layer;
-	}
-
-	@Deprecated
-	public SaveActionBase(String name, String iconName, String tooltip, int shortcut, int modifiers, Layer layer) {
-		super(name, iconName, tooltip, shortcut, modifiers);
-		this.layer = layer;
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		Layer layer = this.layer;
-		if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
-				|| Main.map.mapView.getActiveLayer() instanceof GpxLayer))
-			layer = Main.map.mapView.getActiveLayer();
-		if (layer == null)
-			layer = Main.main.editLayer();
-
-		if (!checkSaveConditions(layer))
-			return;
-
-
-		File file = getFile(layer);
-		if (file == null)
-			return;
-
-		save(file, layer);
-
-		layer.name = file.getName();
-		layer.associatedFile = file;
-		Main.parent.repaint();
-	}
-
-	protected abstract File getFile(Layer layer);
-
-	/**
-	 * Checks whether it is ok to launch a save (whether we have data,
-	 * there is no conflict etc.)
-	 * @return <code>true</code>, if it is safe to save.
-	 */
-	public boolean checkSaveConditions(Layer layer) {
-		if (layer == null) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug."));
-			return false;
-		}
-		if (Main.map == null) {
-			JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save."));
-			return false;
-		}
-
-		if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(Main.parent,tr("The document contains no data. Save anyway?"), tr("Empty document"), JOptionPane.YES_NO_OPTION)) {
-			return false;
-		}
-		if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
-			return false;
-		}
-		if (!Main.map.conflictDialog.conflicts.isEmpty()) {
-			int answer = JOptionPane.showConfirmDialog(Main.parent,
-					tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),tr("Conflicts"), JOptionPane.YES_NO_OPTION);
-			if (answer != JOptionPane.YES_OPTION)
-				return false;
-		}
-		return true;
-	}
-
-	public static File openFileDialog(Layer layer) {
-		JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file"));
-		if (fc == null)
-			return null;
-
-		File file = fc.getSelectedFile();
-
-		String fn = file.getPath();
-		if (fn.indexOf('.') == -1) {
-			FileFilter ff = fc.getFileFilter();
-			if (ff instanceof ExtensionFileFilter)
-				fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
-			else if (layer instanceof GpxLayer)
-				fn += ".gpx";
-			else
-				fn += ".osm";
-			file = new File(fn);
-		}
-		return file;
-	}
-
-	private static void copy(File src, File dst) throws IOException {
-		FileInputStream srcStream;
-		FileOutputStream dstStream;
-		try {
-			srcStream = new FileInputStream(src);
-			dstStream = new FileOutputStream(dst);
-		} catch (FileNotFoundException e) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage());
-			return;
-		}
-		byte buf[] = new byte[1<<16];
-		int len;
-		while ((len = srcStream.read(buf)) != -1) {
-			dstStream.write(buf, 0, len);
-		}
-		srcStream.close();
-		dstStream.close();
-	}
-
-	public static void save(File file, Layer layer) {
-		if (layer instanceof GpxLayer) {
-			save(file, (GpxLayer)layer);
-			((GpxLayer)layer).data.storageFile = file;
-		} else if (layer instanceof OsmDataLayer) {
-			save(file, (OsmDataLayer)layer);
-		}
-	}
-
-	public static void save(File file, OsmDataLayer layer) {
-		File tmpFile = null;
-		try {
-			if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
-				GpxExportAction.exportGpx(file, layer);
-			} else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) {
-				// use a tmp file because if something errors out in the
-				// process of writing the file, we might just end up with
-				// a truncated file.  That can destroy lots of work.
-				if (file.exists()) {
-					tmpFile = new File(file.getPath() + "~");
-					copy(file, tmpFile);
-				}
-				OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false));
-				if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
-					tmpFile.delete();
-			} else {
-				JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
-				return;
-			}
-			layer.cleanData(null, false);
-		} catch (IOException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
-
-			try {
-				// if the file save failed, then the tempfile will not
-				// be deleted.  So, restore the backup if we made one.
-				if (tmpFile != null && tmpFile.exists()) {
-					copy(tmpFile, file);
-				}
-			} catch (IOException e2) {
-				e2.printStackTrace();
-				JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
-			}
-		}
-	}
-
-	public static void save(File file, GpxLayer layer) {
-		File tmpFile = null;
-		try {
-			if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
-
-				// use a tmp file because if something errors out in the
-				// process of writing the file, we might just end up with
-				// a truncated file.  That can destroy lots of work.
-				if (file.exists()) {
-					tmpFile = new File(file.getPath() + "~");
-					copy(file, tmpFile);
-				}
-				FileOutputStream fo = new FileOutputStream(file);
-				new GpxWriter(fo).write(layer.data);
-				fo.flush();
-				fo.close();
-
-				if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
-					tmpFile.delete();
-				}
-			} else {
-				JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
-				return;
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
-		}
-		try {
-			// if the file save failed, then the tempfile will not
-			// be deleted.  So, restore the backup if we made one.
-			if (tmpFile != null && tmpFile.exists()) {
-				copy(tmpFile, file);
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
-		}
-	}
-
-	/**
-	 * Check the data set if it would be empty on save. It is empty, if it contains
-	 * no objects (after all objects that are created and deleted without being
-	 * transfered to the server have been removed).
-	 *
-	 * @return <code>true</code>, if a save result in an empty data set.
-	 */
-	private boolean isDataSetEmpty(OsmDataLayer layer) {
-		for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
-			if (!osm.deleted || osm.id > 0)
-				return false;
-		return true;
-	}
+    private Layer layer;
+
+    public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
+        super(name, iconName, tooltip, shortcut);
+        this.layer = layer;
+    }
+
+    @Deprecated
+    public SaveActionBase(String name, String iconName, String tooltip, int shortcut, int modifiers, Layer layer) {
+        super(name, iconName, tooltip, shortcut, modifiers);
+        this.layer = layer;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        Layer layer = this.layer;
+        if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
+                || Main.map.mapView.getActiveLayer() instanceof GpxLayer))
+            layer = Main.map.mapView.getActiveLayer();
+        if (layer == null)
+            layer = Main.main.editLayer();
+
+        if (!checkSaveConditions(layer))
+            return;
+
+
+        File file = getFile(layer);
+        if (file == null)
+            return;
+
+        save(file, layer);
+
+        layer.name = file.getName();
+        layer.associatedFile = file;
+        Main.parent.repaint();
+    }
+
+    protected abstract File getFile(Layer layer);
+
+    /**
+     * Checks whether it is ok to launch a save (whether we have data,
+     * there is no conflict etc.)
+     * @return <code>true</code>, if it is safe to save.
+     */
+    public boolean checkSaveConditions(Layer layer) {
+        if (layer == null) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug."));
+            return false;
+        }
+        if (Main.map == null) {
+            JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save."));
+            return false;
+        }
+
+        if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(Main.parent,tr("The document contains no data. Save anyway?"), tr("Empty document"), JOptionPane.YES_NO_OPTION)) {
+            return false;
+        }
+        if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
+            return false;
+        }
+        if (!Main.map.conflictDialog.conflicts.isEmpty()) {
+            int answer = JOptionPane.showConfirmDialog(Main.parent,
+                    tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),tr("Conflicts"), JOptionPane.YES_NO_OPTION);
+            if (answer != JOptionPane.YES_OPTION)
+                return false;
+        }
+        return true;
+    }
+
+    public static File openFileDialog(Layer layer) {
+        JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file"));
+        if (fc == null)
+            return null;
+
+        File file = fc.getSelectedFile();
+
+        String fn = file.getPath();
+        if (fn.indexOf('.') == -1) {
+            FileFilter ff = fc.getFileFilter();
+            if (ff instanceof ExtensionFileFilter)
+                fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
+            else if (layer instanceof GpxLayer)
+                fn += ".gpx";
+            else
+                fn += ".osm";
+            file = new File(fn);
+        }
+        return file;
+    }
+
+    private static void copy(File src, File dst) throws IOException {
+        FileInputStream srcStream;
+        FileOutputStream dstStream;
+        try {
+            srcStream = new FileInputStream(src);
+            dstStream = new FileOutputStream(dst);
+        } catch (FileNotFoundException e) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage());
+            return;
+        }
+        byte buf[] = new byte[1<<16];
+        int len;
+        while ((len = srcStream.read(buf)) != -1) {
+            dstStream.write(buf, 0, len);
+        }
+        srcStream.close();
+        dstStream.close();
+    }
+
+    public static void save(File file, Layer layer) {
+        if (layer instanceof GpxLayer) {
+            save(file, (GpxLayer)layer);
+            ((GpxLayer)layer).data.storageFile = file;
+        } else if (layer instanceof OsmDataLayer) {
+            save(file, (OsmDataLayer)layer);
+        }
+    }
+
+    public static void save(File file, OsmDataLayer layer) {
+        File tmpFile = null;
+        try {
+            if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
+                GpxExportAction.exportGpx(file, layer);
+            } else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) {
+                // use a tmp file because if something errors out in the
+                // process of writing the file, we might just end up with
+                // a truncated file.  That can destroy lots of work.
+                if (file.exists()) {
+                    tmpFile = new File(file.getPath() + "~");
+                    copy(file, tmpFile);
+                }
+                OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false));
+                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
+                    tmpFile.delete();
+            } else {
+                JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
+                return;
+            }
+            layer.cleanData(null, false);
+        } catch (IOException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
+
+            try {
+                // if the file save failed, then the tempfile will not
+                // be deleted.  So, restore the backup if we made one.
+                if (tmpFile != null && tmpFile.exists()) {
+                    copy(tmpFile, file);
+                }
+            } catch (IOException e2) {
+                e2.printStackTrace();
+                JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
+            }
+        }
+    }
+
+    public static void save(File file, GpxLayer layer) {
+        File tmpFile = null;
+        try {
+            if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
+
+                // use a tmp file because if something errors out in the
+                // process of writing the file, we might just end up with
+                // a truncated file.  That can destroy lots of work.
+                if (file.exists()) {
+                    tmpFile = new File(file.getPath() + "~");
+                    copy(file, tmpFile);
+                }
+                FileOutputStream fo = new FileOutputStream(file);
+                new GpxWriter(fo).write(layer.data);
+                fo.flush();
+                fo.close();
+
+                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
+                    tmpFile.delete();
+                }
+            } else {
+                JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
+                return;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
+        }
+        try {
+            // if the file save failed, then the tempfile will not
+            // be deleted.  So, restore the backup if we made one.
+            if (tmpFile != null && tmpFile.exists()) {
+                copy(tmpFile, file);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
+        }
+    }
+
+    /**
+     * Check the data set if it would be empty on save. It is empty, if it contains
+     * no objects (after all objects that are created and deleted without being
+     * transfered to the server have been removed).
+     *
+     * @return <code>true</code>, if a save result in an empty data set.
+     */
+    private boolean isDataSetEmpty(OsmDataLayer layer) {
+        for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
+            if (!osm.deleted || osm.id > 0)
+                return false;
+        return true;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 1169)
@@ -17,15 +17,15 @@
 public class SaveAsAction extends SaveActionBase {
 
-	/**
-	 * Construct the action with "Save" as label.
-	 * @param layer Save this layer.
-	 */
-	public SaveAsAction(Layer layer) {
-		super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."),
-		Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save as ...")), KeyEvent.VK_S, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), layer);
-	}
+    /**
+     * Construct the action with "Save" as label.
+     * @param layer Save this layer.
+     */
+    public SaveAsAction(Layer layer) {
+        super(tr("Save as ..."), "save_as", tr("Save the current data to a new file."),
+        Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save as ...")), KeyEvent.VK_S, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), layer);
+    }
 
-	@Override protected File getFile(Layer layer) {
-		return openFileDialog(layer);
-	}
+    @Override protected File getFile(Layer layer) {
+        return openFileDialog(layer);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SelectAllAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SelectAllAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/SelectAllAction.java	(revision 1169)
@@ -12,11 +12,11 @@
 public class SelectAllAction extends JosmAction {
 
-	public SelectAllAction() {
-		super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."),
-		Shortcut.registerShortcut("system:selectall", tr("Edit: {0}", tr("Select All")), KeyEvent.VK_A, Shortcut.GROUP_MENU), true);
-	}
+    public SelectAllAction() {
+        super(tr("Select All"),"selectall", tr("Select all undeleted objects in the data layer. This selects incomplete objects too."),
+        Shortcut.registerShortcut("system:selectall", tr("Edit: {0}", tr("Select All")), KeyEvent.VK_A, Shortcut.GROUP_MENU), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Main.ds.setSelected(Main.ds.allNonDeletedPhysicalPrimitives());
-	}
+    public void actionPerformed(ActionEvent e) {
+        Main.ds.setSelected(Main.ds.allNonDeletedPhysicalPrimitives());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 1169)
@@ -44,259 +44,259 @@
 public class SplitWayAction extends JosmAction implements SelectionChangedListener {
 
-	private Way selectedWay;
-	private List<Node> selectedNodes;
-
-	/**
-	 * Create a new SplitWayAction.
-	 */
-	public SplitWayAction() {
-		super(tr("Split Way"), "splitway", tr("Split a way at the selected node."),
-		Shortcut.registerShortcut("tools:splitway", tr("Tool: {0}", tr("Split Way")), KeyEvent.VK_P, Shortcut.GROUP_EDIT), true);
-		DataSet.selListeners.add(this);
-	}
-
-	/**
-	 * Called when the action is executed.
-	 *
-	 * This method performs an expensive check whether the selection clearly defines one
-	 * of the split actions outlined above, and if yes, calls the splitWay method.
-	 */
-	public void actionPerformed(ActionEvent e) {
-
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-
-		if (!checkSelection(selection)) {
-			JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for splitting."));
-			return;
-		}
-
-		selectedWay = null;
-		selectedNodes = null;
-
-		Visitor splitVisitor = new Visitor(){
-			public void visit(Node n) {
-				if (selectedNodes == null)
-					selectedNodes = new LinkedList<Node>();
-				selectedNodes.add(n);
-            }
-			public void visit(Way w) {
-				selectedWay = w;
-            }
-			public void visit(Relation e) {
-				// enties are not considered
-			}
-		};
-
-		for (OsmPrimitive p : selection)
-			p.visit(splitVisitor);
-
-		// If only nodes are selected, try to guess which way to split. This works if there
-		// is exactly one way that all nodes are part of.
-		if (selectedWay == null && selectedNodes != null) {
-			HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
-			for (Node n : selectedNodes) {
-				for (Way w : Main.ds.ways) {
-					if (w.deleted || w.incomplete) continue;
-					int last = w.nodes.size()-1;
-					if(last <= 0) continue; // zero or one node ways
-					Boolean circular = w.nodes.get(0).equals(w.nodes.get(last));
-					int i = 0;
-					for (Node wn : w.nodes) {
-						if ((circular || (i > 0 && i < last)) && n.equals(wn)) {
-							Integer old = wayOccurenceCounter.get(w);
-							wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
-							break;
-						}
-						i++;
-					}
-				}
-			}
-			if (wayOccurenceCounter.isEmpty()) {
-				JOptionPane.showMessageDialog(Main.parent,
-						trn("The selected node is no inner part of any way.",
-								"The selected nodes are no inner part of any way.", selectedNodes.size()));
-				return;
-			}
-
-			for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {
-				if (entry.getValue().equals(selectedNodes.size())) {
-					if (selectedWay != null) {
-						JOptionPane.showMessageDialog(Main.parent, tr("There is more than one way using the node(s) you selected. Please select the way also."));
-						return;
-					}
-					selectedWay = entry.getKey();
-				}
-			}
-
-			if (selectedWay == null) {
-				JOptionPane.showMessageDialog(Main.parent, tr("The selected nodes do not share the same way."));
-				return;
-			}
-
-		// If a way and nodes are selected, verify that the nodes are part of the way.
-		} else if (selectedWay != null && selectedNodes != null) {
-
-			HashSet<Node> nds = new HashSet<Node>(selectedNodes);
-			for (Node n : selectedWay.nodes) {
-				nds.remove(n);
-			}
-			if (!nds.isEmpty()) {
-				JOptionPane.showMessageDialog(Main.parent,
-						trn("The selected way does not contain the selected node.",
-								"The selected way does not contain all the selected nodes.", selectedNodes.size()));
-				return;
-			}
-		}
-
-		// and then do the work.
-		splitWay();
-	}
-
-	/**
-	 * Checks if the selection consists of something we can work with.
-	 * Checks only if the number and type of items selected looks good;
-	 * does not check whether the selected items are really a valid
-	 * input for splitting (this would be too expensive to be carried
-	 * out from the selectionChanged listener).
-	 */
-	private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
-		boolean way = false;
-		boolean node = false;
-		for (OsmPrimitive p : selection) {
-			if (p instanceof Way && !way) {
-				way = true;
-			} else if (p instanceof Node) {
-				node = true;
-			} else {
-				return false;
-		}
-		}
-		return node;
-	}
-
-	/**
-	 * Split a way into two or more parts, starting at a selected node.
-	 */
-	private void splitWay() {
-		// We take our way's list of nodes and copy them to a way chunk (a
-		// list of nodes).  Whenever we stumble upon a selected node, we start
-		// a new way chunk.
-
-		Set<Node> nodeSet = new HashSet<Node>(selectedNodes);
-		List<List<Node>> wayChunks = new LinkedList<List<Node>>();
-		List<Node> currentWayChunk = new ArrayList<Node>();
-		wayChunks.add(currentWayChunk);
-
-		Iterator<Node> it = selectedWay.nodes.iterator();
-		while (it.hasNext()) {
-			Node currentNode = it.next();
-			boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext();
-			currentWayChunk.add(currentNode);
-			if (nodeSet.contains(currentNode) && !atEndOfWay) {
-				currentWayChunk = new ArrayList<Node>();
-				currentWayChunk.add(currentNode);
-				wayChunks.add(currentWayChunk);
-			}
-		}
-
-		// Handle circular ways specially.
-		// If you split at a circular way at two nodes, you just want to split
-		// it at these points, not also at the former endpoint.
-		// So if the last node is the same first node, join the last and the
-		// first way chunk.
-		List<Node> lastWayChunk = wayChunks.get(wayChunks.size() - 1);
-		if (wayChunks.size() >= 2
-				&& wayChunks.get(0).get(0) == lastWayChunk.get(lastWayChunk.size() - 1)
-				&& !nodeSet.contains(wayChunks.get(0).get(0))) {
-			if (wayChunks.size() == 2) {
-				JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
-				return;
-			}
-			lastWayChunk.remove(lastWayChunk.size() - 1);
-			lastWayChunk.addAll(wayChunks.get(0));
-			wayChunks.remove(wayChunks.size() - 1);
-			wayChunks.set(0, lastWayChunk);
-		}
-
-		if (wayChunks.size() < 2) {
-			if(wayChunks.get(0).get(0) == wayChunks.get(0).get(wayChunks.get(0).size()-1))
-				JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
-			else
-				JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)"));
-			return;
-		}
-		//Main.debug("wayChunks.size(): " + wayChunks.size());
-		//Main.debug("way id: " + selectedWay.id);
-
-		// build a list of commands, and also a new selection list
-		Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
-		Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
-
-		Iterator<List<Node>> chunkIt = wayChunks.iterator();
-
-		// First, change the original way
-		Way changedWay = new Way(selectedWay);
-		changedWay.nodes.clear();
-		changedWay.nodes.addAll(chunkIt.next());
-		commandList.add(new ChangeCommand(selectedWay, changedWay));
-		newSelection.add(selectedWay);
-
-		Collection<Way> newWays = new ArrayList<Way>();
-		// Second, create new ways
-		while (chunkIt.hasNext()) {
-			Way wayToAdd = new Way();
-			if (selectedWay.keys != null) {
-				wayToAdd.keys = new HashMap<String, String>(selectedWay.keys);
-				wayToAdd.checkTagged();
+    private Way selectedWay;
+    private List<Node> selectedNodes;
+
+    /**
+     * Create a new SplitWayAction.
+     */
+    public SplitWayAction() {
+        super(tr("Split Way"), "splitway", tr("Split a way at the selected node."),
+        Shortcut.registerShortcut("tools:splitway", tr("Tool: {0}", tr("Split Way")), KeyEvent.VK_P, Shortcut.GROUP_EDIT), true);
+        DataSet.selListeners.add(this);
+    }
+
+    /**
+     * Called when the action is executed.
+     *
+     * This method performs an expensive check whether the selection clearly defines one
+     * of the split actions outlined above, and if yes, calls the splitWay method.
+     */
+    public void actionPerformed(ActionEvent e) {
+
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+
+        if (!checkSelection(selection)) {
+            JOptionPane.showMessageDialog(Main.parent, tr("The current selection cannot be used for splitting."));
+            return;
+        }
+
+        selectedWay = null;
+        selectedNodes = null;
+
+        Visitor splitVisitor = new Visitor(){
+            public void visit(Node n) {
+                if (selectedNodes == null)
+                    selectedNodes = new LinkedList<Node>();
+                selectedNodes.add(n);
+            }
+            public void visit(Way w) {
+                selectedWay = w;
+            }
+            public void visit(Relation e) {
+                // enties are not considered
+            }
+        };
+
+        for (OsmPrimitive p : selection)
+            p.visit(splitVisitor);
+
+        // If only nodes are selected, try to guess which way to split. This works if there
+        // is exactly one way that all nodes are part of.
+        if (selectedWay == null && selectedNodes != null) {
+            HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
+            for (Node n : selectedNodes) {
+                for (Way w : Main.ds.ways) {
+                    if (w.deleted || w.incomplete) continue;
+                    int last = w.nodes.size()-1;
+                    if(last <= 0) continue; // zero or one node ways
+                    Boolean circular = w.nodes.get(0).equals(w.nodes.get(last));
+                    int i = 0;
+                    for (Node wn : w.nodes) {
+                        if ((circular || (i > 0 && i < last)) && n.equals(wn)) {
+                            Integer old = wayOccurenceCounter.get(w);
+                            wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
+                            break;
+                        }
+                        i++;
+                    }
+                }
+            }
+            if (wayOccurenceCounter.isEmpty()) {
+                JOptionPane.showMessageDialog(Main.parent,
+                        trn("The selected node is no inner part of any way.",
+                                "The selected nodes are no inner part of any way.", selectedNodes.size()));
+                return;
+            }
+
+            for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {
+                if (entry.getValue().equals(selectedNodes.size())) {
+                    if (selectedWay != null) {
+                        JOptionPane.showMessageDialog(Main.parent, tr("There is more than one way using the node(s) you selected. Please select the way also."));
+                        return;
+                    }
+                    selectedWay = entry.getKey();
+                }
+            }
+
+            if (selectedWay == null) {
+                JOptionPane.showMessageDialog(Main.parent, tr("The selected nodes do not share the same way."));
+                return;
+            }
+
+        // If a way and nodes are selected, verify that the nodes are part of the way.
+        } else if (selectedWay != null && selectedNodes != null) {
+
+            HashSet<Node> nds = new HashSet<Node>(selectedNodes);
+            for (Node n : selectedWay.nodes) {
+                nds.remove(n);
+            }
+            if (!nds.isEmpty()) {
+                JOptionPane.showMessageDialog(Main.parent,
+                        trn("The selected way does not contain the selected node.",
+                                "The selected way does not contain all the selected nodes.", selectedNodes.size()));
+                return;
+            }
+        }
+
+        // and then do the work.
+        splitWay();
+    }
+
+    /**
+     * Checks if the selection consists of something we can work with.
+     * Checks only if the number and type of items selected looks good;
+     * does not check whether the selected items are really a valid
+     * input for splitting (this would be too expensive to be carried
+     * out from the selectionChanged listener).
+     */
+    private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
+        boolean way = false;
+        boolean node = false;
+        for (OsmPrimitive p : selection) {
+            if (p instanceof Way && !way) {
+                way = true;
+            } else if (p instanceof Node) {
+                node = true;
+            } else {
+                return false;
+        }
+        }
+        return node;
+    }
+
+    /**
+     * Split a way into two or more parts, starting at a selected node.
+     */
+    private void splitWay() {
+        // We take our way's list of nodes and copy them to a way chunk (a
+        // list of nodes).  Whenever we stumble upon a selected node, we start
+        // a new way chunk.
+
+        Set<Node> nodeSet = new HashSet<Node>(selectedNodes);
+        List<List<Node>> wayChunks = new LinkedList<List<Node>>();
+        List<Node> currentWayChunk = new ArrayList<Node>();
+        wayChunks.add(currentWayChunk);
+
+        Iterator<Node> it = selectedWay.nodes.iterator();
+        while (it.hasNext()) {
+            Node currentNode = it.next();
+            boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext();
+            currentWayChunk.add(currentNode);
+            if (nodeSet.contains(currentNode) && !atEndOfWay) {
+                currentWayChunk = new ArrayList<Node>();
+                currentWayChunk.add(currentNode);
+                wayChunks.add(currentWayChunk);
+            }
+        }
+
+        // Handle circular ways specially.
+        // If you split at a circular way at two nodes, you just want to split
+        // it at these points, not also at the former endpoint.
+        // So if the last node is the same first node, join the last and the
+        // first way chunk.
+        List<Node> lastWayChunk = wayChunks.get(wayChunks.size() - 1);
+        if (wayChunks.size() >= 2
+                && wayChunks.get(0).get(0) == lastWayChunk.get(lastWayChunk.size() - 1)
+                && !nodeSet.contains(wayChunks.get(0).get(0))) {
+            if (wayChunks.size() == 2) {
+                JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
+                return;
+            }
+            lastWayChunk.remove(lastWayChunk.size() - 1);
+            lastWayChunk.addAll(wayChunks.get(0));
+            wayChunks.remove(wayChunks.size() - 1);
+            wayChunks.set(0, lastWayChunk);
+        }
+
+        if (wayChunks.size() < 2) {
+            if(wayChunks.get(0).get(0) == wayChunks.get(0).get(wayChunks.get(0).size()-1))
+                JOptionPane.showMessageDialog(Main.parent, tr("You must select two or more nodes to split a circular way."));
+            else
+                JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)"));
+            return;
+        }
+        //Main.debug("wayChunks.size(): " + wayChunks.size());
+        //Main.debug("way id: " + selectedWay.id);
+
+        // build a list of commands, and also a new selection list
+        Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
+        Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
+
+        Iterator<List<Node>> chunkIt = wayChunks.iterator();
+
+        // First, change the original way
+        Way changedWay = new Way(selectedWay);
+        changedWay.nodes.clear();
+        changedWay.nodes.addAll(chunkIt.next());
+        commandList.add(new ChangeCommand(selectedWay, changedWay));
+        newSelection.add(selectedWay);
+
+        Collection<Way> newWays = new ArrayList<Way>();
+        // Second, create new ways
+        while (chunkIt.hasNext()) {
+            Way wayToAdd = new Way();
+            if (selectedWay.keys != null) {
+                wayToAdd.keys = new HashMap<String, String>(selectedWay.keys);
+                wayToAdd.checkTagged();
                                 wayToAdd.checkDirectionTagged();
-			}
-			newWays.add(wayToAdd);
-			wayToAdd.nodes.addAll(chunkIt.next());
-			commandList.add(new AddCommand(wayToAdd));
-			//Main.debug("wayToAdd: " + wayToAdd);
-			newSelection.add(wayToAdd);
-
-		}
-		Boolean warnme=false;
-		// now copy all relations to new way also
-		for (Relation r : Main.ds.relations) {
-			if (r.deleted || r.incomplete) continue;
-			for (RelationMember rm : r.members) {
-				if (rm.member instanceof Way) {
-					if (rm.member == selectedWay)
-					{
-						Relation c = new Relation(r);
-						for(Way wayToAdd : newWays)
-						{
-							RelationMember em = new RelationMember();
-							em.member = wayToAdd;
-							em.role = rm.role;
-							if(em.role.length() > 0)
-								warnme = true;
-							c.members.add(em);
-						}
-						commandList.add(new ChangeCommand(r, c));
-						break;
-					}
-				}
-			}
-		}
-		if(warnme)
-			JOptionPane.showMessageDialog(Main.parent, tr("A role based relation membership was copied to all new ways.\nYou should verify this and correct it when necessary."));
-
-		NameVisitor v = new NameVisitor();
-		v.visit(selectedWay);
-		Main.main.undoRedo.add(
-			new SequenceCommand(tr("Split way {0} into {1} parts",
-				v.name, wayChunks.size()),
-			commandList));
-		Main.ds.setSelected(newSelection);
-	}
-
-	/**
-	 * Enable the "split way" menu option if the selection looks like we could use it.
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		setEnabled(checkSelection(newSelection));
-	}
+            }
+            newWays.add(wayToAdd);
+            wayToAdd.nodes.addAll(chunkIt.next());
+            commandList.add(new AddCommand(wayToAdd));
+            //Main.debug("wayToAdd: " + wayToAdd);
+            newSelection.add(wayToAdd);
+
+        }
+        Boolean warnme=false;
+        // now copy all relations to new way also
+        for (Relation r : Main.ds.relations) {
+            if (r.deleted || r.incomplete) continue;
+            for (RelationMember rm : r.members) {
+                if (rm.member instanceof Way) {
+                    if (rm.member == selectedWay)
+                    {
+                        Relation c = new Relation(r);
+                        for(Way wayToAdd : newWays)
+                        {
+                            RelationMember em = new RelationMember();
+                            em.member = wayToAdd;
+                            em.role = rm.role;
+                            if(em.role.length() > 0)
+                                warnme = true;
+                            c.members.add(em);
+                        }
+                        commandList.add(new ChangeCommand(r, c));
+                        break;
+                    }
+                }
+            }
+        }
+        if(warnme)
+            JOptionPane.showMessageDialog(Main.parent, tr("A role based relation membership was copied to all new ways.\nYou should verify this and correct it when necessary."));
+
+        NameVisitor v = new NameVisitor();
+        v.visit(selectedWay);
+        Main.main.undoRedo.add(
+            new SequenceCommand(tr("Split way {0} into {1} parts",
+                v.name, wayChunks.size()),
+            commandList));
+        Main.ds.setSelected(newSelection);
+    }
+
+    /**
+     * Enable the "split way" menu option if the selection looks like we could use it.
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        setEnabled(checkSelection(newSelection));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ToggleGPXLinesAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ToggleGPXLinesAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ToggleGPXLinesAction.java	(revision 1169)
@@ -12,12 +12,12 @@
 public class ToggleGPXLinesAction extends JosmAction {
 
-	public ToggleGPXLinesAction() {
-		super(tr("Toggle GPX Lines"), "gps-lines", tr("Toggles the global setting ''{0}''.", tr("Draw lines between raw gps points.")),
-		Shortcut.registerShortcut("view:gpxlines", tr("View: {0}", tr("Toggle GPX Lines")), KeyEvent.VK_X, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
-	}
+    public ToggleGPXLinesAction() {
+        super(tr("Toggle GPX Lines"), "gps-lines", tr("Toggles the global setting ''{0}''.", tr("Draw lines between raw gps points.")),
+        Shortcut.registerShortcut("view:gpxlines", tr("View: {0}", tr("Toggle GPX Lines")), KeyEvent.VK_X, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Main.pref.put("draw.rawgps.lines", !Main.pref.getBoolean("draw.rawgps.lines"));
-		Main.map.mapView.repaint();
-	}
+    public void actionPerformed(ActionEvent e) {
+        Main.pref.put("draw.rawgps.lines", !Main.pref.getBoolean("draw.rawgps.lines"));
+        Main.map.mapView.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 1169)
@@ -36,300 +36,300 @@
 public class UnGlueAction extends JosmAction { //implements SelectionChangedListener {
 
-	private Node selectedNode;
-	private Way selectedWay;
-	private ArrayList<Node> selectedNodes;
-
-	/**
-	 * Create a new UnGlueAction.
-	 */
-	public UnGlueAction() {
-		super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."),
-		Shortcut.registerShortcut("tools:unglue", tr("Tool: {0}", tr("UnGlue Ways")), KeyEvent.VK_G, Shortcut.GROUP_EDIT), true);
-		//DataSet.selListeners.add(this);
-	}
-
-	/**
-	 * Called when the action is executed.
-	 *
-	 * This method does some checking on the selection and calls the matching unGlueWay method.
-	 */
-	public void actionPerformed(ActionEvent e) {
-
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-
-		if (checkSelection(selection)) {
-			int count = 0;
-			for (Way w : Main.ds.ways) {
-				if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
-				if (!w.nodes.contains(selectedNode)) continue;
-				count++;
-			}
-			if (count < 2) {
-				JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else."));
-			} else {
-				// and then do the work.
-				unglueWays();
-			}
-		} else if (checkSelection2(selection)) {
-			ArrayList<Node> tmpNodes = new ArrayList<Node>();
-			for (Node n : selectedNodes) {
-				int count = 0;
-				for (Way w : Main.ds.ways) {
-					if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
-					if (!w.nodes.contains(n)) continue;
-					count++;
-				}
-				if (count >= 2) {
-					tmpNodes.add(n);
-				}
-			}
-			if (tmpNodes.size() < 1) {
-				if (selection.size() > 1) {
-					JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else."));
-				} else {
-					JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else."));
-				}
-			} else {
-				// and then do the work.
-				selectedNodes = tmpNodes;
-				unglueWays2();
-			}
-		} else {
-			JOptionPane.showMessageDialog(Main.parent,
-				tr("The current selection cannot be used for unglueing.")+"\n"+
-				"\n"+
-				tr("Select either:")+"\n"+
-				tr("* One node that is used by more than one way, or")+"\n"+
-				tr("* One node that is used by more than one way and one of those ways, or")+"\n"+
-				tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+
-				tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+
-				"\n"+
-				tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+
-				   "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+
-				   "own copy and all nodes will be selected.")
-			);
-		}
-		selectedNode = null;
-		selectedWay = null;
-		selectedNodes = null;
-	}
-
-	/**
-	 * Checks if the selection consists of something we can work with.
-	 * Checks only if the number and type of items selected looks good;
-	 * does not check whether the selected items are really a valid
-	 * input for splitting (this would be too expensive to be carried
-	 * out from the selectionChanged listener).
-	 *
-	 * If this method returns "true", selectedNode and selectedWay will
-	 * be set.
-	 *
-	 * Returns true if either one node is selected or one node and one
-	 * way are selected and the node is part of the way.
-	 *
-	 * The way will be put into the object variable "selectedWay", the
-	 * node into "selectedNode".
-	 */
-	private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
-
-		int size = selection.size();
-		if (size < 1 || size > 2)
-			return false;
-
-		selectedNode = null;
-		selectedWay = null;
-
-		for (OsmPrimitive p : selection) {
-			if (p instanceof Node) {
-				selectedNode = (Node) p;
-				if (size == 1 || selectedWay != null)
-					return size == 1 || selectedWay.nodes.contains(selectedNode);
-			} else if (p instanceof Way) {
-				selectedWay = (Way) p;
-				if (size == 2 && selectedNode != null)
-					return selectedWay.nodes.contains(selectedNode);
-			}
-		}
-
-		return false;
-	}
-
-	/**
-	 * Checks if the selection consists of something we can work with.
-	 * Checks only if the number and type of items selected looks good;
-	 * does not check whether the selected items are really a valid
-	 * input for splitting (this would be too expensive to be carried
-	 * out from the selectionChanged listener).
-	 *
-	 * Returns true if one way and any number of nodes that are part of
-	 * that way are selected. Note: "any" can be none, then all nodes of
-	 * the way are used.
-	 *
-	 * The way will be put into the object variable "selectedWay", the
-	 * nodes into "selectedNodes".
-	 */
-	private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) {
-		if (selection.size() < 1)
-			return false;
-
-		selectedWay = null;
-		for (OsmPrimitive p : selection) {
-			if (p instanceof Way) {
-				if (selectedWay != null) {
-					return false;
-				}
-				selectedWay = (Way) p;
-			}
-		}
-		if (selectedWay == null) {
-			return false;
-		}
-
-		selectedNodes = new ArrayList<Node>();
-		for (OsmPrimitive p : selection) {
-			if (p instanceof Node) {
-				Node n = (Node) p;
-				if (!selectedWay.nodes.contains(n)) {
-					return false;
-				}
-				selectedNodes.add(n);
-			}
-		}
-
-		if (selectedNodes.size() < 1) {
-			selectedNodes.addAll(selectedWay.nodes);
-		}
-
-		return true;
-	}
-
-	/**
-	 * dupe the given node of the given way
-	 *
-	 * -> the new node will be put into the parameter newNodes.
-	 * -> the add-node command will be put into the parameter cmds.
-	 * -> the changed way will be returned and must be put into cmds by the caller!
-	 */
-	private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
-		ArrayList<Node> nn = new ArrayList<Node>();
-		for (Node pushNode : w.nodes) {
-			if (originalNode == pushNode) {
-				// clone the node for all other ways
-				pushNode = new Node(pushNode);
-				pushNode.id = 0;
-				newNodes.add(pushNode);
-				cmds.add(new AddCommand(pushNode));
-			}
-			nn.add(pushNode);
-		}
-		Way newWay = new Way(w);
-		newWay.nodes.clear();
-		newWay.nodes.addAll(nn);
-
-		return newWay;
-	}
-
-	/**
-	 * put all newNodes into the same relation(s) that originalNode is in
-	 */
-	private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
-		// modify all relations containing the node
-		Relation newRel = null;
-		HashSet<String> rolesToReAdd = null;
-		for (Relation r : Main.ds.relations) {
-			if (r.deleted || r.incomplete) continue;
-			newRel = null;
-			rolesToReAdd = null;
-			for (RelationMember rm : r.members) {
-				if (rm.member instanceof Node) {
-					if (rm.member == originalNode) {
-						if (newRel == null) {
-							newRel = new Relation(r);
-							newRel.members.clear();
-							rolesToReAdd = new HashSet<String>();
-						}
-						rolesToReAdd.add(rm.role);
-					}
-				}
-			}
-			if (newRel != null) {
-				for (RelationMember rm : r.members) {
-					//if (rm.member != selectedNode) {
-						newRel.members.add(rm);
-					//}
-				}
-				for (Node n : newNodes) {
-					for (String role : rolesToReAdd) {
-						newRel.members.add(new RelationMember(role, n));
-					}
-				}
-				cmds.add(new ChangeCommand(r, newRel));
-			}
-		}
-	}
-
-
-	/**
-	 * dupe a single node into as many nodes as there are ways using it, OR
-	 *
-	 * dupe a single node once, and put the copy on the selected way
-	 */
-	private void unglueWays() {
-		LinkedList<Command> cmds = new LinkedList<Command>();
-		List<Node> newNodes = new LinkedList<Node>();
-
-		if (selectedWay == null) {
-			boolean firstway = true;
-			// modify all ways containing the nodes
-			for (Way w : Main.ds.ways) {
-				if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
-				if (!w.nodes.contains(selectedNode)) continue;
-				if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
-				firstway = false;
-			}
-		} else {
-			cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));
-		}
-
-		fixRelations(selectedNode, cmds, newNodes);
-
-		Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds));
-		if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes
-			newNodes.add(selectedNode);
-		} // if a node and a way has been selected, new selection is only the new node that was added to the selected way
-		Main.ds.setSelected(newNodes);
-	}
-
-	/**
-	 * dupe all nodes that are selected, and put the copies on the selected way
-	 *
-	 */
-	private void unglueWays2() {
-		LinkedList<Command> cmds = new LinkedList<Command>();
-		List<Node> allNewNodes = new LinkedList<Node>();
-		Way tmpWay = selectedWay;
-
-		for (Node n : selectedNodes) {
-			List<Node> newNodes = new LinkedList<Node>();
-			tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
-			fixRelations(n, cmds, newNodes);
-			allNewNodes.addAll(newNodes);
-		}
-		cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen
-
-		Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
-		Main.ds.setSelected(allNewNodes);
-	}
+    private Node selectedNode;
+    private Way selectedWay;
+    private ArrayList<Node> selectedNodes;
+
+    /**
+     * Create a new UnGlueAction.
+     */
+    public UnGlueAction() {
+        super(tr("UnGlue Ways"), "unglueways", tr("Duplicate nodes that are used by multiple ways."),
+        Shortcut.registerShortcut("tools:unglue", tr("Tool: {0}", tr("UnGlue Ways")), KeyEvent.VK_G, Shortcut.GROUP_EDIT), true);
+        //DataSet.selListeners.add(this);
+    }
+
+    /**
+     * Called when the action is executed.
+     *
+     * This method does some checking on the selection and calls the matching unGlueWay method.
+     */
+    public void actionPerformed(ActionEvent e) {
+
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+
+        if (checkSelection(selection)) {
+            int count = 0;
+            for (Way w : Main.ds.ways) {
+                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
+                if (!w.nodes.contains(selectedNode)) continue;
+                count++;
+            }
+            if (count < 2) {
+                JOptionPane.showMessageDialog(Main.parent, tr("This node is not glued to anything else."));
+            } else {
+                // and then do the work.
+                unglueWays();
+            }
+        } else if (checkSelection2(selection)) {
+            ArrayList<Node> tmpNodes = new ArrayList<Node>();
+            for (Node n : selectedNodes) {
+                int count = 0;
+                for (Way w : Main.ds.ways) {
+                    if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
+                    if (!w.nodes.contains(n)) continue;
+                    count++;
+                }
+                if (count >= 2) {
+                    tmpNodes.add(n);
+                }
+            }
+            if (tmpNodes.size() < 1) {
+                if (selection.size() > 1) {
+                    JOptionPane.showMessageDialog(Main.parent, tr("None of these nodes is glued to anything else."));
+                } else {
+                    JOptionPane.showMessageDialog(Main.parent, tr("None of this way's nodes is glued to anything else."));
+                }
+            } else {
+                // and then do the work.
+                selectedNodes = tmpNodes;
+                unglueWays2();
+            }
+        } else {
+            JOptionPane.showMessageDialog(Main.parent,
+                tr("The current selection cannot be used for unglueing.")+"\n"+
+                "\n"+
+                tr("Select either:")+"\n"+
+                tr("* One node that is used by more than one way, or")+"\n"+
+                tr("* One node that is used by more than one way and one of those ways, or")+"\n"+
+                tr("* One way that has one or more nodes that are used by more than one way, or")+"\n"+
+                tr("* One way and one or more of its nodes that are used by more than one way.")+"\n"+
+                "\n"+
+                tr("Note: If a way is selected, this way will get fresh copies of the unglued\n"+
+                   "nodes and the new nodes will be selected. Otherwise, all ways will get their\n"+
+                   "own copy and all nodes will be selected.")
+            );
+        }
+        selectedNode = null;
+        selectedWay = null;
+        selectedNodes = null;
+    }
+
+    /**
+     * Checks if the selection consists of something we can work with.
+     * Checks only if the number and type of items selected looks good;
+     * does not check whether the selected items are really a valid
+     * input for splitting (this would be too expensive to be carried
+     * out from the selectionChanged listener).
+     *
+     * If this method returns "true", selectedNode and selectedWay will
+     * be set.
+     *
+     * Returns true if either one node is selected or one node and one
+     * way are selected and the node is part of the way.
+     *
+     * The way will be put into the object variable "selectedWay", the
+     * node into "selectedNode".
+     */
+    private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
+
+        int size = selection.size();
+        if (size < 1 || size > 2)
+            return false;
+
+        selectedNode = null;
+        selectedWay = null;
+
+        for (OsmPrimitive p : selection) {
+            if (p instanceof Node) {
+                selectedNode = (Node) p;
+                if (size == 1 || selectedWay != null)
+                    return size == 1 || selectedWay.nodes.contains(selectedNode);
+            } else if (p instanceof Way) {
+                selectedWay = (Way) p;
+                if (size == 2 && selectedNode != null)
+                    return selectedWay.nodes.contains(selectedNode);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks if the selection consists of something we can work with.
+     * Checks only if the number and type of items selected looks good;
+     * does not check whether the selected items are really a valid
+     * input for splitting (this would be too expensive to be carried
+     * out from the selectionChanged listener).
+     *
+     * Returns true if one way and any number of nodes that are part of
+     * that way are selected. Note: "any" can be none, then all nodes of
+     * the way are used.
+     *
+     * The way will be put into the object variable "selectedWay", the
+     * nodes into "selectedNodes".
+     */
+    private boolean checkSelection2(Collection<? extends OsmPrimitive> selection) {
+        if (selection.size() < 1)
+            return false;
+
+        selectedWay = null;
+        for (OsmPrimitive p : selection) {
+            if (p instanceof Way) {
+                if (selectedWay != null) {
+                    return false;
+                }
+                selectedWay = (Way) p;
+            }
+        }
+        if (selectedWay == null) {
+            return false;
+        }
+
+        selectedNodes = new ArrayList<Node>();
+        for (OsmPrimitive p : selection) {
+            if (p instanceof Node) {
+                Node n = (Node) p;
+                if (!selectedWay.nodes.contains(n)) {
+                    return false;
+                }
+                selectedNodes.add(n);
+            }
+        }
+
+        if (selectedNodes.size() < 1) {
+            selectedNodes.addAll(selectedWay.nodes);
+        }
+
+        return true;
+    }
+
+    /**
+     * dupe the given node of the given way
+     *
+     * -> the new node will be put into the parameter newNodes.
+     * -> the add-node command will be put into the parameter cmds.
+     * -> the changed way will be returned and must be put into cmds by the caller!
+     */
+    private Way modifyWay(Node originalNode, Way w, List<Command> cmds, List<Node> newNodes) {
+        ArrayList<Node> nn = new ArrayList<Node>();
+        for (Node pushNode : w.nodes) {
+            if (originalNode == pushNode) {
+                // clone the node for all other ways
+                pushNode = new Node(pushNode);
+                pushNode.id = 0;
+                newNodes.add(pushNode);
+                cmds.add(new AddCommand(pushNode));
+            }
+            nn.add(pushNode);
+        }
+        Way newWay = new Way(w);
+        newWay.nodes.clear();
+        newWay.nodes.addAll(nn);
+
+        return newWay;
+    }
+
+    /**
+     * put all newNodes into the same relation(s) that originalNode is in
+     */
+    private void fixRelations(Node originalNode, List<Command> cmds, List<Node> newNodes) {
+        // modify all relations containing the node
+        Relation newRel = null;
+        HashSet<String> rolesToReAdd = null;
+        for (Relation r : Main.ds.relations) {
+            if (r.deleted || r.incomplete) continue;
+            newRel = null;
+            rolesToReAdd = null;
+            for (RelationMember rm : r.members) {
+                if (rm.member instanceof Node) {
+                    if (rm.member == originalNode) {
+                        if (newRel == null) {
+                            newRel = new Relation(r);
+                            newRel.members.clear();
+                            rolesToReAdd = new HashSet<String>();
+                        }
+                        rolesToReAdd.add(rm.role);
+                    }
+                }
+            }
+            if (newRel != null) {
+                for (RelationMember rm : r.members) {
+                    //if (rm.member != selectedNode) {
+                        newRel.members.add(rm);
+                    //}
+                }
+                for (Node n : newNodes) {
+                    for (String role : rolesToReAdd) {
+                        newRel.members.add(new RelationMember(role, n));
+                    }
+                }
+                cmds.add(new ChangeCommand(r, newRel));
+            }
+        }
+    }
+
+
+    /**
+     * dupe a single node into as many nodes as there are ways using it, OR
+     *
+     * dupe a single node once, and put the copy on the selected way
+     */
+    private void unglueWays() {
+        LinkedList<Command> cmds = new LinkedList<Command>();
+        List<Node> newNodes = new LinkedList<Node>();
+
+        if (selectedWay == null) {
+            boolean firstway = true;
+            // modify all ways containing the nodes
+            for (Way w : Main.ds.ways) {
+                if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
+                if (!w.nodes.contains(selectedNode)) continue;
+                if (!firstway) cmds.add(new ChangeCommand(w, modifyWay(selectedNode, w, cmds, newNodes)));
+                firstway = false;
+            }
+        } else {
+            cmds.add(new ChangeCommand(selectedWay, modifyWay(selectedNode, selectedWay, cmds, newNodes)));
+        }
+
+        fixRelations(selectedNode, cmds, newNodes);
+
+        Main.main.undoRedo.add(new SequenceCommand(tr("Dupe into {0} nodes", newNodes.size()+1), cmds));
+        if (selectedWay == null) { // if a node has been selected, new selection is ALL nodes
+            newNodes.add(selectedNode);
+        } // if a node and a way has been selected, new selection is only the new node that was added to the selected way
+        Main.ds.setSelected(newNodes);
+    }
+
+    /**
+     * dupe all nodes that are selected, and put the copies on the selected way
+     *
+     */
+    private void unglueWays2() {
+        LinkedList<Command> cmds = new LinkedList<Command>();
+        List<Node> allNewNodes = new LinkedList<Node>();
+        Way tmpWay = selectedWay;
+
+        for (Node n : selectedNodes) {
+            List<Node> newNodes = new LinkedList<Node>();
+            tmpWay = modifyWay(n, tmpWay, cmds, newNodes);
+            fixRelations(n, cmds, newNodes);
+            allNewNodes.addAll(newNodes);
+        }
+        cmds.add(new ChangeCommand(selectedWay, tmpWay)); // only one changeCommand for a way, else garbage will happen
+
+        Main.main.undoRedo.add(new SequenceCommand(tr("Dupe {0} nodes into {1} nodes", selectedNodes.size(), selectedNodes.size()+allNewNodes.size()), cmds));
+        Main.ds.setSelected(allNewNodes);
+    }
 
 // Disabled because we have such a nice help text that would not be shown otherwise.
 //
-//	/**
-//	 * Enable the menu option if the selection looks like we could use it.
-//	 */
-//	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-//		setEnabled(checkSelection(newSelection) || checkSelection2(newSelection));
-//		selectedNode = null;
-//		selectedWay = null;
-//		selectedNodes = null;
-//	}
+//  /**
+//   * Enable the menu option if the selection looks like we could use it.
+//   */
+//  public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+//      setEnabled(checkSelection(newSelection) || checkSelection2(newSelection));
+//      selectedNode = null;
+//      selectedWay = null;
+//      selectedNodes = null;
+//  }
 }
Index: trunk/src/org/openstreetmap/josm/actions/UndoAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UndoAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/UndoAction.java	(revision 1169)
@@ -17,18 +17,18 @@
 public class UndoAction extends JosmAction {
 
-	/**
-	 * Construct the action with "Undo" as label.
-	 */
-	public UndoAction() {
-		super(tr("Undo"), "undo", tr("Undo the last action."),
-		Shortcut.registerShortcut("system:undo", tr("Edit: {0}", tr("Undo")), KeyEvent.VK_Z, Shortcut.GROUP_MENU), true);
-		setEnabled(false);
-	}
+    /**
+     * Construct the action with "Undo" as label.
+     */
+    public UndoAction() {
+        super(tr("Undo"), "undo", tr("Undo the last action."),
+        Shortcut.registerShortcut("system:undo", tr("Edit: {0}", tr("Undo")), KeyEvent.VK_Z, Shortcut.GROUP_MENU), true);
+        setEnabled(false);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		if (Main.map == null)
-			return;
-		Main.map.repaint();
-		Main.main.undoRedo.undo();
-	}
+    public void actionPerformed(ActionEvent e) {
+        if (Main.map == null)
+            return;
+        Main.map.repaint();
+        Main.main.undoRedo.undo();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/UnselectAllAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UnselectAllAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/UnselectAllAction.java	(revision 1169)
@@ -13,30 +13,30 @@
 public class UnselectAllAction extends JosmAction {
 
-	public UnselectAllAction() {
-		super(tr("Unselect All"), "unselectall", tr("Unselect all objects."),
-		Shortcut.registerShortcut("edit:unselectall", tr("Edit: {0}", tr("Unselect All")), KeyEvent.VK_U, Shortcut.GROUP_EDIT), true);
-		// this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put
-		// the correct group in
+    public UnselectAllAction() {
+        super(tr("Unselect All"), "unselectall", tr("Unselect all objects."),
+        Shortcut.registerShortcut("edit:unselectall", tr("Edit: {0}", tr("Unselect All")), KeyEvent.VK_U, Shortcut.GROUP_EDIT), true);
+        // this is not really GROUP_EDIT, but users really would complain if the yhad to reconfigure because we put
+        // the correct group in
 
-		// Add extra shortcut C-S-a
-		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-		Shortcut.registerShortcut("edit:unselectallfocus", tr("Edit: {0}", tr("Unselect All (Focus)")),
-		KeyEvent.VK_A, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT).getKeyStroke(),
-		tr("Unselect All"));
+        // Add extra shortcut C-S-a
+        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+        Shortcut.registerShortcut("edit:unselectallfocus", tr("Edit: {0}", tr("Unselect All (Focus)")),
+        KeyEvent.VK_A, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT).getKeyStroke(),
+        tr("Unselect All"));
 
-		// Add extra shortcut ESCAPE
-		/*
-		 * FIXME: this isn't optimal. In a better world the mapmode actions
-		 * would be able to capture keyboard events and react accordingly. But
-		 * for now this is a reasonable approximation.
-		 */
-		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-		Shortcut.registerShortcut("edit:unselectallescape", tr("Edit: {0}", tr("Unselect All (Escape)")),
-		KeyEvent.VK_ESCAPE, Shortcut.GROUP_DIRECT).getKeyStroke(),
-		tr("Unselect All"));
-	}
+        // Add extra shortcut ESCAPE
+        /*
+         * FIXME: this isn't optimal. In a better world the mapmode actions
+         * would be able to capture keyboard events and react accordingly. But
+         * for now this is a reasonable approximation.
+         */
+        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+        Shortcut.registerShortcut("edit:unselectallescape", tr("Edit: {0}", tr("Unselect All (Escape)")),
+        KeyEvent.VK_ESCAPE, Shortcut.GROUP_DIRECT).getKeyStroke(),
+        tr("Unselect All"));
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		Main.ds.setSelected();
-	}
+    public void actionPerformed(ActionEvent e) {
+        Main.ds.setSelected();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 1169)
@@ -35,129 +35,129 @@
 public class UploadAction extends JosmAction {
 
-	/** Upload Hook */
-	public interface UploadHook {
-		/**
-		 * Checks the upload.
-		 * @param add The added primitives
-		 * @param update The updated primitives
-		 * @param delete The deleted primitives
-		 * @return true, if the upload can continue
-		 */
-		public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete);
-	}
+    /** Upload Hook */
+    public interface UploadHook {
+        /**
+         * Checks the upload.
+         * @param add The added primitives
+         * @param update The updated primitives
+         * @param delete The deleted primitives
+         * @return true, if the upload can continue
+         */
+        public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete);
+    }
 
-	/**
-	 * The list of upload hooks. These hooks will be called one after the other
-	 * when the user wants to upload data. Plugins can insert their own hooks here
-	 * if they want to be able to veto an upload.
-	 *
-	 * Be default, the standard upload dialog is the only element in the list.
-	 * Plugins should normally insert their code before that, so that the upload
-	 * dialog is the last thing shown before upload really starts; on occasion
-	 * however, a plugin might also want to insert something after that.
-	 */
-	public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
+    /**
+     * The list of upload hooks. These hooks will be called one after the other
+     * when the user wants to upload data. Plugins can insert their own hooks here
+     * if they want to be able to veto an upload.
+     *
+     * Be default, the standard upload dialog is the only element in the list.
+     * Plugins should normally insert their code before that, so that the upload
+     * dialog is the last thing shown before upload really starts; on occasion
+     * however, a plugin might also want to insert something after that.
+     */
+    public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
 
-	public UploadAction() {
-		super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."),
-		Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM ...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
+    public UploadAction() {
+        super(tr("Upload to OSM ..."), "upload", tr("Upload all changes to the OSM server."),
+        Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM ...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
 
-		/**
-		 * Displays a screen where the actions that would be taken are displayed and
-		 * give the user the possibility to cancel the upload.
-		 */
-		uploadHooks.add(new UploadHook() {
-			public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
+        /**
+         * Displays a screen where the actions that would be taken are displayed and
+         * give the user the possibility to cancel the upload.
+         */
+        uploadHooks.add(new UploadHook() {
+            public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
 
-				JPanel p = new JPanel(new GridBagLayout());
+                JPanel p = new JPanel(new GridBagLayout());
 
-				OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
+                OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
 
-				if (!add.isEmpty()) {
-					p.add(new JLabel(tr("Objects to add:")), GBC.eol());
-					JList l = new JList(add.toArray());
-					l.setCellRenderer(renderer);
-					l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
-					p.add(new JScrollPane(l), GBC.eol().fill());
-				}
+                if (!add.isEmpty()) {
+                    p.add(new JLabel(tr("Objects to add:")), GBC.eol());
+                    JList l = new JList(add.toArray());
+                    l.setCellRenderer(renderer);
+                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+                    p.add(new JScrollPane(l), GBC.eol().fill());
+                }
 
-				if (!update.isEmpty()) {
-					p.add(new JLabel(tr("Objects to modify:")), GBC.eol());
-					JList l = new JList(update.toArray());
-					l.setCellRenderer(renderer);
-					l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
-					p.add(new JScrollPane(l), GBC.eol().fill());
-				}
+                if (!update.isEmpty()) {
+                    p.add(new JLabel(tr("Objects to modify:")), GBC.eol());
+                    JList l = new JList(update.toArray());
+                    l.setCellRenderer(renderer);
+                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+                    p.add(new JScrollPane(l), GBC.eol().fill());
+                }
 
-				if (!delete.isEmpty()) {
-					p.add(new JLabel(tr("Objects to delete:")), GBC.eol());
-					JList l = new JList(delete.toArray());
-					l.setCellRenderer(renderer);
-					l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
-					p.add(new JScrollPane(l), GBC.eol().fill());
-				}
+                if (!delete.isEmpty()) {
+                    p.add(new JLabel(tr("Objects to delete:")), GBC.eol());
+                    JList l = new JList(delete.toArray());
+                    l.setCellRenderer(renderer);
+                    l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+                    p.add(new JScrollPane(l), GBC.eol().fill());
+                }
 
-				return JOptionPane.showConfirmDialog(Main.parent, p, tr("Upload these changes?"),
-						JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
-			}
-		});
-	}
+                return JOptionPane.showConfirmDialog(Main.parent, p, tr("Upload these changes?"),
+                        JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
+            }
+        });
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		if (Main.map == null) {
-			JOptionPane.showMessageDialog(Main.parent,tr("Nothing to upload. Get some data first."));
-			return;
-		}
+    public void actionPerformed(ActionEvent e) {
+        if (Main.map == null) {
+            JOptionPane.showMessageDialog(Main.parent,tr("Nothing to upload. Get some data first."));
+            return;
+        }
 
-		if (!Main.map.conflictDialog.conflicts.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent,tr("There are unresolved conflicts. You have to resolve these first."));
-			Main.map.conflictDialog.action.button.setSelected(true);
-			Main.map.conflictDialog.action.actionPerformed(null);
-			return;
-		}
+        if (!Main.map.conflictDialog.conflicts.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent,tr("There are unresolved conflicts. You have to resolve these first."));
+            Main.map.conflictDialog.action.button.setSelected(true);
+            Main.map.conflictDialog.action.actionPerformed(null);
+            return;
+        }
 
-		final LinkedList<OsmPrimitive> add = new LinkedList<OsmPrimitive>();
-		final LinkedList<OsmPrimitive> update = new LinkedList<OsmPrimitive>();
-		final LinkedList<OsmPrimitive> delete = new LinkedList<OsmPrimitive>();
-		for (OsmPrimitive osm : Main.ds.allPrimitives()) {
-			if (osm.get("josm/ignore") != null)
-				continue;
-			if (osm.id == 0 && !osm.deleted)
-				add.addLast(osm);
-			else if (osm.modified && !osm.deleted)
-				update.addLast(osm);
-			else if (osm.deleted && osm.id != 0)
-				delete.addFirst(osm);
-		}
+        final LinkedList<OsmPrimitive> add = new LinkedList<OsmPrimitive>();
+        final LinkedList<OsmPrimitive> update = new LinkedList<OsmPrimitive>();
+        final LinkedList<OsmPrimitive> delete = new LinkedList<OsmPrimitive>();
+        for (OsmPrimitive osm : Main.ds.allPrimitives()) {
+            if (osm.get("josm/ignore") != null)
+                continue;
+            if (osm.id == 0 && !osm.deleted)
+                add.addLast(osm);
+            else if (osm.modified && !osm.deleted)
+                update.addLast(osm);
+            else if (osm.deleted && osm.id != 0)
+                delete.addFirst(osm);
+        }
 
-		if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent,tr("No changes to upload."));
-			return;
-		}
+        if (add.isEmpty() && update.isEmpty() && delete.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent,tr("No changes to upload."));
+            return;
+        }
 
-		// Call all upload hooks in sequence. The upload confirmation dialog
-		// is one of these.
-		for(UploadHook hook : uploadHooks)
-			if(!hook.checkUpload(add, update, delete))
-				return;
+        // Call all upload hooks in sequence. The upload confirmation dialog
+        // is one of these.
+        for(UploadHook hook : uploadHooks)
+            if(!hook.checkUpload(add, update, delete))
+                return;
 
-		final OsmServerWriter server = new OsmServerWriter();
-		final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
-		all.addAll(add);
-		all.addAll(update);
-		all.addAll(delete);
+        final OsmServerWriter server = new OsmServerWriter();
+        final Collection<OsmPrimitive> all = new LinkedList<OsmPrimitive>();
+        all.addAll(add);
+        all.addAll(update);
+        all.addAll(delete);
 
-		PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading data")){
-			@Override protected void realRun() throws SAXException {
-				server.uploadOsm(all);
-			}
-			@Override protected void finish() {
-				Main.main.editLayer().cleanData(server.processed, !add.isEmpty());
-			}
-			@Override protected void cancel() {
-				server.cancel();
-			}
-		};
-		Main.worker.execute(uploadTask);
-	}
+        PleaseWaitRunnable uploadTask = new PleaseWaitRunnable(tr("Uploading data")){
+            @Override protected void realRun() throws SAXException {
+                server.uploadOsm(all);
+            }
+            @Override protected void finish() {
+                Main.main.editLayer().cleanData(server.processed, !add.isEmpty());
+            }
+            @Override protected void cancel() {
+                server.cancel();
+            }
+        };
+        Main.worker.execute(uploadTask);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ZoomInAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ZoomInAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ZoomInAction.java	(revision 1169)
@@ -12,14 +12,14 @@
 public final class ZoomInAction extends JosmAction {
 
-	public ZoomInAction() {
-		super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"),
-		Shortcut.registerShortcut("view:zoomin", tr("View: {0}", tr("Zoom in")), KeyEvent.VK_PLUS, Shortcut.GROUP_DIRECT), true);
-		setEnabled(true);
-	}
+    public ZoomInAction() {
+        super(tr("Zoom in"), "dialogs/zoomin", tr("Zoom in"),
+        Shortcut.registerShortcut("view:zoomin", tr("View: {0}", tr("Zoom in")), KeyEvent.VK_PLUS, Shortcut.GROUP_DIRECT), true);
+        setEnabled(true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
+    public void actionPerformed(ActionEvent e) {
         if (Main.map == null) return;
-		double zoom = Main.map.mapView.getScale();
-		Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom * .9);
-	}
+        double zoom = Main.map.mapView.getScale();
+        Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom * .9);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/ZoomOutAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ZoomOutAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/ZoomOutAction.java	(revision 1169)
@@ -12,14 +12,14 @@
 public final class ZoomOutAction extends JosmAction {
 
-	public ZoomOutAction() {
-		super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"),
-		Shortcut.registerShortcut("view:zoomout", tr("View: {0}", tr("Zoom out")), KeyEvent.VK_MINUS, Shortcut.GROUP_DIRECT), true);
-		setEnabled(true);
-	}
+    public ZoomOutAction() {
+        super(tr("Zoom out"), "dialogs/zoomout", tr("Zoom out"),
+        Shortcut.registerShortcut("view:zoomout", tr("View: {0}", tr("Zoom out")), KeyEvent.VK_MINUS, Shortcut.GROUP_DIRECT), true);
+        setEnabled(true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
+    public void actionPerformed(ActionEvent e) {
         if (Main.map == null) return;
-		double zoom = Main.map.mapView.getScale();
-		Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom /.9);
-	}
+        double zoom = Main.map.mapView.getScale();
+        Main.map.mapView.zoomTo(Main.map.mapView.getCenter(), zoom /.9);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioBackAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioBackAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioBackAction.java	(revision 1169)
@@ -15,26 +15,26 @@
 public class AudioBackAction extends JosmAction {
 
-	private double amount; // note, normally negative, i.e. jump backwards in time
+    private double amount; // note, normally negative, i.e. jump backwards in time
 
-	public AudioBackAction() {
-		super(tr("Back"), "audio-back", tr("Jump back."),
-		Shortcut.registerShortcut("audio:back", tr("Audio: {0}", tr("Back")), KeyEvent.VK_F6, Shortcut.GROUP_DIRECT), true);
-		try {
-			amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
-		} catch (NumberFormatException e) {
-			amount = 10.0;
-		}
-		this.putValue("help", "Action/Back");
-	}
+    public AudioBackAction() {
+        super(tr("Back"), "audio-back", tr("Jump back."),
+        Shortcut.registerShortcut("audio:back", tr("Audio: {0}", tr("Back")), KeyEvent.VK_F6, Shortcut.GROUP_DIRECT), true);
+        try {
+            amount = - Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
+        } catch (NumberFormatException e) {
+            amount = 10.0;
+        }
+        this.putValue("help", "Action/Back");
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		try {
-			if (AudioPlayer.playing() || AudioPlayer.paused())
-				AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
-			else
-				MarkerLayer.playAudio();
-		} catch (Exception ex) {
-			AudioPlayer.audioMalfunction(ex);
-		}
-	}
+    public void actionPerformed(ActionEvent e) {
+        try {
+            if (AudioPlayer.playing() || AudioPlayer.paused())
+                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
+            else
+                MarkerLayer.playAudio();
+        } catch (Exception ex) {
+            AudioPlayer.audioMalfunction(ex);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioFastSlowAction.java	(revision 1169)
@@ -11,39 +11,39 @@
 abstract public class AudioFastSlowAction extends JosmAction {
 
-	private double multiplier;
+    private double multiplier;
 
-	public AudioFastSlowAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean fast) {
-		super(name, iconName, tooltip, shortcut, true);
-		try {
-			multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
-		} catch (NumberFormatException e) {
-			multiplier = 1.3;
-		}
-		if (! fast)
-			multiplier = 1.0 / multiplier;
-	}
+    public AudioFastSlowAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean fast) {
+        super(name, iconName, tooltip, shortcut, true);
+        try {
+            multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
+        } catch (NumberFormatException e) {
+            multiplier = 1.3;
+        }
+        if (! fast)
+            multiplier = 1.0 / multiplier;
+    }
 
-	@Deprecated
-	public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) {
-		super(name, iconName, tooltip, shortcut, modifier, true);
-		try {
-			multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
-		} catch (NumberFormatException e) {
-			multiplier = 1.3;
-		}
-		if (! fast)
-			multiplier = 1.0 / multiplier;
-	}
+    @Deprecated
+    public AudioFastSlowAction(String name, String iconName, String tooltip, int shortcut, int modifier, boolean fast) {
+        super(name, iconName, tooltip, shortcut, modifier, true);
+        try {
+            multiplier = Double.parseDouble(Main.pref.get("audio.fastfwdmultiplier","1.3"));
+        } catch (NumberFormatException e) {
+            multiplier = 1.3;
+        }
+        if (! fast)
+            multiplier = 1.0 / multiplier;
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		double speed = AudioPlayer.speed();
-		if (speed * multiplier <= 0.1)
-			return;
-		try {
-			if (AudioPlayer.playing() || AudioPlayer.paused())
-				AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position(), speed * multiplier);
-		} catch (Exception ex) {
-			AudioPlayer.audioMalfunction(ex);
-		}
-	}
+    public void actionPerformed(ActionEvent e) {
+        double speed = AudioPlayer.speed();
+        if (speed * multiplier <= 0.1)
+            return;
+        try {
+            if (AudioPlayer.playing() || AudioPlayer.paused())
+                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position(), speed * multiplier);
+        } catch (Exception ex) {
+            AudioPlayer.audioMalfunction(ex);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioFasterAction.java	(revision 1169)
@@ -9,7 +9,7 @@
 public class AudioFasterAction extends AudioFastSlowAction {
 
-	public AudioFasterAction() {
-		super(tr("Faster"), "audio-faster", tr("Faster Forward"),
-		Shortcut.registerShortcut("audio:faster", tr("Audio: {0}", tr("Faster")), KeyEvent.VK_F9, Shortcut.GROUP_DIRECT), true);
-	}
+    public AudioFasterAction() {
+        super(tr("Faster"), "audio-faster", tr("Faster Forward"),
+        Shortcut.registerShortcut("audio:faster", tr("Audio: {0}", tr("Faster")), KeyEvent.VK_F9, Shortcut.GROUP_DIRECT), true);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioFwdAction.java	(revision 1169)
@@ -15,25 +15,25 @@
 public class AudioFwdAction extends JosmAction {
 
-	private double amount;
+    private double amount;
 
-	public AudioFwdAction() {
-		super(tr("Forward"), "audio-fwd", tr("Jump forward"),
-		Shortcut.registerShortcut("audio:forward", tr("Audio: {0}", tr("Forward")), KeyEvent.VK_F7, Shortcut.GROUP_DIRECT), true);
-		try {
-			amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
-		} catch (NumberFormatException e) {
-			amount = 10.0;
-		}
-	}
+    public AudioFwdAction() {
+        super(tr("Forward"), "audio-fwd", tr("Jump forward"),
+        Shortcut.registerShortcut("audio:forward", tr("Audio: {0}", tr("Forward")), KeyEvent.VK_F7, Shortcut.GROUP_DIRECT), true);
+        try {
+            amount = Double.parseDouble(Main.pref.get("audio.forwardbackamount","10.0"));
+        } catch (NumberFormatException e) {
+            amount = 10.0;
+        }
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		try {
-			if (AudioPlayer.playing() || AudioPlayer.paused())
-				AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
-			else
-				MarkerLayer.playAudio();
-		} catch (Exception ex) {
-			AudioPlayer.audioMalfunction(ex);
-		}
-	}
+    public void actionPerformed(ActionEvent e) {
+        try {
+            if (AudioPlayer.playing() || AudioPlayer.paused())
+                AudioPlayer.play(AudioPlayer.url(), AudioPlayer.position() + amount);
+            else
+                MarkerLayer.playAudio();
+        } catch (Exception ex) {
+            AudioPlayer.audioMalfunction(ex);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioNextAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioNextAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioNextAction.java	(revision 1169)
@@ -13,11 +13,11 @@
 public class AudioNextAction extends JosmAction {
 
-	public AudioNextAction() {
-		super(tr("Next Marker"), "audio-next", tr("Play next marker."),
-		Shortcut.registerShortcut("audio:next", tr("Audio: {0}", tr("Next Marker")), KeyEvent.VK_F8, Shortcut.GROUP_DIRECT), true);
-	}
+    public AudioNextAction() {
+        super(tr("Next Marker"), "audio-next", tr("Play next marker."),
+        Shortcut.registerShortcut("audio:next", tr("Audio: {0}", tr("Next Marker")), KeyEvent.VK_F8, Shortcut.GROUP_DIRECT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		MarkerLayer.playNextMarker();
-	}
+    public void actionPerformed(ActionEvent e) {
+        MarkerLayer.playNextMarker();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioPlayPauseAction.java	(revision 1169)
@@ -15,26 +15,26 @@
 public class AudioPlayPauseAction extends JosmAction {
 
-	public AudioPlayPauseAction() {
-		super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."),
-		Shortcut.registerShortcut("audio:pause", tr("Audio: {0}", tr("Play/pause")), KeyEvent.VK_PERIOD, Shortcut.GROUP_DIRECT), true);
-	}
+    public AudioPlayPauseAction() {
+        super(tr("Play/pause"), "audio-playpause", tr("Play/pause audio."),
+        Shortcut.registerShortcut("audio:pause", tr("Audio: {0}", tr("Play/pause")), KeyEvent.VK_PERIOD, Shortcut.GROUP_DIRECT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		URL url = AudioPlayer.url();
-		try {
-			if (AudioPlayer.paused() && url != null) {
-				AudioPlayer.play(url);
-			} else if (AudioPlayer.playing()){
-				if (AudioPlayer.speed() != 1.0)
-					AudioPlayer.play(url, AudioPlayer.position());
-				else
-					AudioPlayer.pause();
-			} else {
-				// find first audio marker to play
-				MarkerLayer.playAudio();
-			}
-		} catch (Exception ex) {
-			AudioPlayer.audioMalfunction(ex);
-		}
-	}
+    public void actionPerformed(ActionEvent e) {
+        URL url = AudioPlayer.url();
+        try {
+            if (AudioPlayer.paused() && url != null) {
+                AudioPlayer.play(url);
+            } else if (AudioPlayer.playing()){
+                if (AudioPlayer.speed() != 1.0)
+                    AudioPlayer.play(url, AudioPlayer.position());
+                else
+                    AudioPlayer.pause();
+            } else {
+                // find first audio marker to play
+                MarkerLayer.playAudio();
+            }
+        } catch (Exception ex) {
+            AudioPlayer.audioMalfunction(ex);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioPrevAction.java	(revision 1169)
@@ -13,11 +13,11 @@
 public class AudioPrevAction extends JosmAction {
 
-	public AudioPrevAction() {
-		super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."),
-		Shortcut.registerShortcut("audio:prev", tr("Audio: {0}", tr("Previous Marker")), KeyEvent.VK_F5, Shortcut.GROUP_DIRECT), true);
-	}
+    public AudioPrevAction() {
+        super(tr("Previous Marker"), "audio-prev", tr("Play previous marker."),
+        Shortcut.registerShortcut("audio:prev", tr("Audio: {0}", tr("Previous Marker")), KeyEvent.VK_F5, Shortcut.GROUP_DIRECT), true);
+    }
 
-	public void actionPerformed(ActionEvent e) {
-		MarkerLayer.playPreviousMarker();
-	}
+    public void actionPerformed(ActionEvent e) {
+        MarkerLayer.playPreviousMarker();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/audio/AudioSlowerAction.java	(revision 1169)
@@ -9,7 +9,7 @@
 public class AudioSlowerAction extends AudioFastSlowAction {
 
-	public AudioSlowerAction() {
-		super(tr("Slower"), "audio-slower", tr("Slower Forward"),
-		Shortcut.registerShortcut("audio:slower", tr("Audio: {0}", tr("Slower")), KeyEvent.VK_F4, Shortcut.GROUP_DIRECT), true);
-	}
+    public AudioSlowerAction() {
+        super(tr("Slower"), "audio-slower", tr("Slower Forward"),
+        Shortcut.registerShortcut("audio:slower", tr("Audio: {0}", tr("Slower")), KeyEvent.VK_F4, Shortcut.GROUP_DIRECT), true);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 1169)
@@ -21,66 +21,66 @@
 public class DownloadGpsTask implements DownloadTask {
 
-	private static class Task extends PleaseWaitRunnable {
-		private BoundingBoxDownloader reader;
-		private GpxData rawData;
-		private final boolean newLayer;
+    private static class Task extends PleaseWaitRunnable {
+        private BoundingBoxDownloader reader;
+        private GpxData rawData;
+        private final boolean newLayer;
 
-		public Task(boolean newLayer, BoundingBoxDownloader reader) {
-			super(tr("Downloading GPS data"));
-			this.reader = reader;
-			this.newLayer = newLayer;
-		}
+        public Task(boolean newLayer, BoundingBoxDownloader reader) {
+            super(tr("Downloading GPS data"));
+            this.reader = reader;
+            this.newLayer = newLayer;
+        }
 
-		@Override public void realRun() throws IOException, SAXException {
-			rawData = reader.parseRawGps();
-		}
+        @Override public void realRun() throws IOException, SAXException {
+            rawData = reader.parseRawGps();
+        }
 
-		@Override protected void finish() {
-			if (rawData == null)
-				return;
+        @Override protected void finish() {
+            if (rawData == null)
+                return;
                         rawData.recalculateBounds();
                         Bounds b = rawData.bounds;
-						String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon();
-						GpxLayer layer = new GpxLayer(rawData, name);
-			if (newLayer || findMergeLayer() == null)
-	            Main.main.addLayer(layer);
-			else
-				findMergeLayer().mergeFrom(layer);
-		}
-
-		private Layer findMergeLayer() {
-			if (Main.map == null)
-				return null;
-	        Layer active = Main.map.mapView.getActiveLayer();
-	        if (active != null && active instanceof GpxLayer)
-	        	return active;
-	        for (Layer l : Main.map.mapView.getAllLayers())
-				if (l instanceof GpxLayer)
-	        		return l;
-	        return null;
+                        String name = b.min.lat() + " " + b.min.lon() + " x " + b.max.lat() + " " + b.max.lon();
+                        GpxLayer layer = new GpxLayer(rawData, name);
+            if (newLayer || findMergeLayer() == null)
+                Main.main.addLayer(layer);
+            else
+                findMergeLayer().mergeFrom(layer);
         }
 
-		@Override protected void cancel() {
-			if (reader != null)
-				reader.cancel();
-		}
-	}
+        private Layer findMergeLayer() {
+            if (Main.map == null)
+                return null;
+            Layer active = Main.map.mapView.getActiveLayer();
+            if (active != null && active instanceof GpxLayer)
+                return active;
+            for (Layer l : Main.map.mapView.getAllLayers())
+                if (l instanceof GpxLayer)
+                    return l;
+            return null;
+        }
 
-	private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data"));
-
-	public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
-		Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
-		Main.worker.execute(task);
-	}
-
-	public JCheckBox getCheckBox() {
-	    return checkBox;
+        @Override protected void cancel() {
+            if (reader != null)
+                reader.cancel();
+        }
     }
 
-	public String getPreferencesSuffix() {
-	    return "gps";
+    private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data"));
+
+    public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
+        Task task = new Task(action.dialog.newLayer.isSelected(), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
+        Main.worker.execute(task);
     }
 
-    public void loadUrl(boolean a,java.lang.String b) { 
+    public JCheckBox getCheckBox() {
+        return checkBox;
+    }
+
+    public String getPreferencesSuffix() {
+        return "gps";
+    }
+
+    public void loadUrl(boolean a,java.lang.String b) {
         // FIXME this is not currently used
     }
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 1169)
@@ -31,24 +31,24 @@
     private static Bounds currentBounds;
 
-	private static class Task extends PleaseWaitRunnable {
-		private OsmServerReader reader;
-		private DataSet dataSet;
-		private boolean newLayer;
+    private static class Task extends PleaseWaitRunnable {
+        private OsmServerReader reader;
+        private DataSet dataSet;
+        private boolean newLayer;
 
-		public Task(boolean newLayer, OsmServerReader reader) {
-			super(tr("Downloading data"));
-			this.reader = reader;
-			this.newLayer = newLayer;
-		}
+        public Task(boolean newLayer, OsmServerReader reader) {
+            super(tr("Downloading data"));
+            this.reader = reader;
+            this.newLayer = newLayer;
+        }
 
-		@Override public void realRun() throws IOException, SAXException {
-			dataSet = reader.parseOsm();
-		}
+        @Override public void realRun() throws IOException, SAXException {
+            dataSet = reader.parseOsm();
+        }
 
-		@Override protected void finish() {
-			if (dataSet == null)
-				return; // user cancelled download or error occoured
-			if (dataSet.allPrimitives().isEmpty()) {
-				errorMessage = tr("No data imported.");
+        @Override protected void finish() {
+            if (dataSet == null)
+                return; // user cancelled download or error occoured
+            if (dataSet.allPrimitives().isEmpty()) {
+                errorMessage = tr("No data imported.");
                 // need to synthesize a download bounds lest the visual indication of downloaded
                 // area doesn't work
@@ -56,48 +56,48 @@
             }
 
-			OsmDataLayer layer = new OsmDataLayer(dataSet, tr("Data Layer"), null);
-			if (newLayer)
-				Main.main.addLayer(layer);
-			else
-				Main.main.editLayer().mergeFrom(layer);
-		}
+            OsmDataLayer layer = new OsmDataLayer(dataSet, tr("Data Layer"), null);
+            if (newLayer)
+                Main.main.addLayer(layer);
+            else
+                Main.main.editLayer().mergeFrom(layer);
+        }
 
-		@Override protected void cancel() {
-			if (reader != null)
-				reader.cancel();
-		}
-	}
-	private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true);
+        @Override protected void cancel() {
+            if (reader != null)
+                reader.cancel();
+        }
+    }
+    private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true);
 
-	public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
-		// Swap min and max if user has specified them the wrong way round
-		// (easy to do if you are crossing 0, for example)
-		// FIXME should perhaps be done in download dialog?
-		if (minlat > maxlat) {
-			double t = minlat; minlat = maxlat; maxlat = t;
-		}
-		if (minlon > maxlon) {
-			double t = minlon; minlon = maxlon; maxlon = t;
-		}
-    
-		Task task = new Task(action != null && (action.dialog == null || action.dialog.newLayer.isSelected()), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
+    public void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon) {
+        // Swap min and max if user has specified them the wrong way round
+        // (easy to do if you are crossing 0, for example)
+        // FIXME should perhaps be done in download dialog?
+        if (minlat > maxlat) {
+            double t = minlat; minlat = maxlat; maxlat = t;
+        }
+        if (minlon > maxlon) {
+            double t = minlon; minlon = maxlon; maxlon = t;
+        }
+
+        Task task = new Task(action != null && (action.dialog == null || action.dialog.newLayer.isSelected()), new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon));
         currentBounds = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon));
-		Main.worker.execute(task);
+        Main.worker.execute(task);
     }
-    
+
     public void loadUrl(boolean new_layer, String url) {
         Task task = new Task(new_layer, new OsmServerLocationReader(url));
         Main.worker.execute(task);
     }
-    
-    
-    
 
-	public JCheckBox getCheckBox() {
-	    return checkBox;
+
+
+
+    public JCheckBox getCheckBox() {
+        return checkBox;
     }
 
-	public String getPreferencesSuffix() {
-	    return "osm";
+    public String getPreferencesSuffix() {
+        return "osm";
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 1169)
@@ -36,96 +36,96 @@
 public class DeleteAction extends MapMode {
 
-	/**
-	 * Construct a new DeleteAction. Mnemonic is the delete - key.
-	 * @param mapFrame The frame this action belongs to.
-	 */
-	public DeleteAction(MapFrame mapFrame) {
-		super(tr("Delete Mode"),
-				"delete",
-				tr("Delete nodes or ways."),
-				Shortcut.registerShortcut("mapmode:delete", tr("Mode: {0}",tr("Delete")), KeyEvent.VK_D, Shortcut.GROUP_EDIT),
-				mapFrame,
-				ImageProvider.getCursor("normal", "delete"));
-	}
+    /**
+     * Construct a new DeleteAction. Mnemonic is the delete - key.
+     * @param mapFrame The frame this action belongs to.
+     */
+    public DeleteAction(MapFrame mapFrame) {
+        super(tr("Delete Mode"),
+                "delete",
+                tr("Delete nodes or ways."),
+                Shortcut.registerShortcut("mapmode:delete", tr("Mode: {0}",tr("Delete")), KeyEvent.VK_D, Shortcut.GROUP_EDIT),
+                mapFrame,
+                ImageProvider.getCursor("normal", "delete"));
+    }
 
-	@Override public void enterMode() {
-		super.enterMode();
-		Main.map.mapView.addMouseListener(this);
-	}
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+    }
 
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-	}
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+    }
 
 
-	@Override public void actionPerformed(ActionEvent e) {
-		super.actionPerformed(e);
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		doActionPerformed(e);
-	}
+    @Override public void actionPerformed(ActionEvent e) {
+        super.actionPerformed(e);
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        doActionPerformed(e);
+    }
 
-	public void doActionPerformed(ActionEvent e) {
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+    public void doActionPerformed(ActionEvent e) {
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
 
-		Command c;
-		if (ctrl) {
-			c = DeleteCommand.deleteWithReferences(Main.ds.getSelected());
-		} else {
-			c = DeleteCommand.delete(Main.ds.getSelected(), !alt);
-		}
-		if (c != null) {
-			Main.main.undoRedo.add(c);
-		}
+        Command c;
+        if (ctrl) {
+            c = DeleteCommand.deleteWithReferences(Main.ds.getSelected());
+        } else {
+            c = DeleteCommand.delete(Main.ds.getSelected(), !alt);
+        }
+        if (c != null) {
+            Main.main.undoRedo.add(c);
+        }
 
-		Main.ds.setSelected();
-		Main.map.repaint();
-	}
+        Main.ds.setSelected();
+        Main.map.repaint();
+    }
 
-	/**
-	 * If user clicked with the left button, delete the nearest object.
-	 * position.
-	 */
-	@Override public void mouseClicked(MouseEvent e) {
-		if (e.getButton() != MouseEvent.BUTTON1)
-			return;
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-		boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+    /**
+     * If user clicked with the left button, delete the nearest object.
+     * position.
+     */
+    @Override public void mouseClicked(MouseEvent e) {
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
 
-		OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
-		Command c = null;
-		if (sel == null) {
-			WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
-			if (ws != null) {
-				if (shift) {
-					c = DeleteCommand.deleteWaySegment(ws);
-				} else if (ctrl) {
-					c = DeleteCommand.deleteWithReferences(Collections.singleton((OsmPrimitive)ws.way));
-				} else {
-					c = DeleteCommand.delete(Collections.singleton((OsmPrimitive)ws.way), !alt);
-				}
-			}
-		} else if (ctrl) {
-			c = DeleteCommand.deleteWithReferences(Collections.singleton(sel));
-		} else {
-			c = DeleteCommand.delete(Collections.singleton(sel), !alt);
-		}
-		if (c != null) {
-			Main.main.undoRedo.add(c);
-		}
+        OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
+        Command c = null;
+        if (sel == null) {
+            WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
+            if (ws != null) {
+                if (shift) {
+                    c = DeleteCommand.deleteWaySegment(ws);
+                } else if (ctrl) {
+                    c = DeleteCommand.deleteWithReferences(Collections.singleton((OsmPrimitive)ws.way));
+                } else {
+                    c = DeleteCommand.delete(Collections.singleton((OsmPrimitive)ws.way), !alt);
+                }
+            }
+        } else if (ctrl) {
+            c = DeleteCommand.deleteWithReferences(Collections.singleton(sel));
+        } else {
+            c = DeleteCommand.delete(Collections.singleton(sel), !alt);
+        }
+        if (c != null) {
+            Main.main.undoRedo.add(c);
+        }
 
-		Main.ds.setSelected();
-		Main.map.mapView.repaint();
-	}
+        Main.ds.setSelected();
+        Main.map.mapView.repaint();
+    }
 
-	@Override public String getModeHelpText() {
-		return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
-	}
+    @Override public String getModeHelpText() {
+        return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 1169)
@@ -58,578 +58,578 @@
 public class DrawAction extends MapMode implements MapViewPaintable, SelectionChangedListener, AWTEventListener {
 
-	private static Node lastUsedNode = null;
-	private double PHI=Math.toRadians(90);
-
-	private boolean ctrl;
-	private boolean alt;
-	private boolean shift;
-	private boolean mouseOnExistingNode;
-	private boolean drawHelperLine;
-	private Point mousePos;
-	private Color selectedColor;
-
-	private Node currentBaseNode;
-	private EastNorth currentMouseEastNorth;
-
-	public DrawAction(MapFrame mapFrame) {
-		super(tr("Draw"), "node/autonode", tr("Draw nodes"),
-				Shortcut.registerShortcut("mapmode:draw", tr("Mode: {0}", tr("Draw")), KeyEvent.VK_A, Shortcut.GROUP_EDIT),
-				mapFrame, getCursor());
-
-		// Add extra shortcut N
-		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-			Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT).getKeyStroke(), tr("Draw"));
-
-		//putValue("help", "Action/AddNode/Autnode");
-		selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
-
-		drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);
-	}
-
-	private static Cursor getCursor() {
-		try {
-	        return ImageProvider.getCursor("crosshair", null);
+    private static Node lastUsedNode = null;
+    private double PHI=Math.toRadians(90);
+
+    private boolean ctrl;
+    private boolean alt;
+    private boolean shift;
+    private boolean mouseOnExistingNode;
+    private boolean drawHelperLine;
+    private Point mousePos;
+    private Color selectedColor;
+
+    private Node currentBaseNode;
+    private EastNorth currentMouseEastNorth;
+
+    public DrawAction(MapFrame mapFrame) {
+        super(tr("Draw"), "node/autonode", tr("Draw nodes"),
+                Shortcut.registerShortcut("mapmode:draw", tr("Mode: {0}", tr("Draw")), KeyEvent.VK_A, Shortcut.GROUP_EDIT),
+                mapFrame, getCursor());
+
+        // Add extra shortcut N
+        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+            Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT).getKeyStroke(), tr("Draw"));
+
+        //putValue("help", "Action/AddNode/Autnode");
+        selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
+
+        drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);
+    }
+
+    private static Cursor getCursor() {
+        try {
+            return ImageProvider.getCursor("crosshair", null);
         } catch (Exception e) {
         }
-	    return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
-    }
-
-	@Override public void enterMode() {
-		super.enterMode();
-		Main.map.mapView.addMouseListener(this);
-		Main.map.mapView.addMouseMotionListener(this);
-		Main.map.mapView.addTemporaryLayer(this);
-		DataSet.selListeners.add(this);
-		try {
-			Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
-		} catch (SecurityException ex) {
-		}
-		// would like to but haven't got mouse position yet:
-		// computeHelperLine(false, false, false);
-	}
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-		Main.map.mapView.removeMouseMotionListener(this);
-		Main.map.mapView.removeTemporaryLayer(this);
-		DataSet.selListeners.remove(this);
-		try {
-			Toolkit.getDefaultToolkit().removeAWTEventListener(this);
-		} catch (SecurityException ex) {
-		}
-	}
-
-	/**
-	 * redraw to (possibly) get rid of helper line if selection changes.
-	 */
-	public void eventDispatched(AWTEvent event) {
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		InputEvent e = (InputEvent) event;
-		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-		computeHelperLine();
-	}
-	/**
-	 * redraw to (possibly) get rid of helper line if selection changes.
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		computeHelperLine();
-	}
-
-	/**
-	 * If user clicked with the left button, add a node at the current mouse
-	 * position.
-	 *
-	 * If in nodeway mode, insert the node into the way.
-	 */
-	@Override public void mouseClicked(MouseEvent e) {
-
-		if (e.getButton() != MouseEvent.BUTTON1)
-			return;
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-
-		// we copy ctrl/alt/shift from the event just in case our global
-		// AWTEvent didn't make it through the security manager. Unclear
-		// if that can ever happen but better be safe.
-		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-		mousePos = e.getPoint();
-
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-		Collection<Command> cmds = new LinkedList<Command>();
-
-		ArrayList<Way> reuseWays = new ArrayList<Way>(),
-			replacedWays = new ArrayList<Way>();
-		boolean newNode = false;
-		Node n = null;
-
-		if (!ctrl) {
-			n = Main.map.mapView.getNearestNode(mousePos);
-		}
-
-		if (n != null) {
-			// user clicked on node
-			if (shift || selection.isEmpty()) {
-				// select the clicked node and do nothing else
-				// (this is just a convenience option so that people don't
-				// have to switch modes)
-				Main.ds.setSelected(n);
-				return;
-			}
-
-		} else {
-			// no node found in clicked area
-			n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
-			if (n.coor.isOutSideWorld()) {
-				JOptionPane.showMessageDialog(Main.parent,
-					tr("Cannot add a node outside of the world."));
-				return;
-			}
-			newNode = true;
-
-			cmds.add(new AddCommand(n));
-
-			if (!ctrl) {
-				// Insert the node into all the nearby way segments
-				List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint());
-				Map<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
-				for (WaySegment ws : wss) {
-					List<Integer> is;
-					if (insertPoints.containsKey(ws.way)) {
-						is = insertPoints.get(ws.way);
-					} else {
-						is = new ArrayList<Integer>();
-						insertPoints.put(ws.way, is);
-					}
-
-					is.add(ws.lowerIndex);
-				}
-
-				Set<Pair<Node,Node>> segSet = new HashSet<Pair<Node,Node>>();
-
-				for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
-					Way w = insertPoint.getKey();
-					List<Integer> is = insertPoint.getValue();
-
-					Way wnew = new Way(w);
-
-					pruneSuccsAndReverse(is);
-					for (int i : is) segSet.add(
-						Pair.sort(new Pair<Node,Node>(w.nodes.get(i), w.nodes.get(i+1))));
-					for (int i : is) wnew.nodes.add(i + 1, n);
-
-					cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
-					replacedWays.add(insertPoint.getKey());
-					reuseWays.add(wnew);
-				}
-
-				adjustNode(segSet, n);
-			}
-		}
-
-		// This part decides whether or not a "segment" (i.e. a connection) is made to an
-		// existing node.
-
-		// For a connection to be made, the user must either have a node selected (connection
-		// is made to that node), or he must have a way selected *and* one of the endpoints
-		// of that way must be the last used node (connection is made to last used node), or
-		// he must have a way and a node selected (connection is made to the selected node).
-
-		boolean extendedWay = false;
-
-		if (!shift && selection.size() > 0 && selection.size() < 3) {
-
-			Node selectedNode = null;
-			Way selectedWay = null;
-
-			for (OsmPrimitive p : selection) {
-				if (p instanceof Node) {
-					if (selectedNode != null) return;
-					selectedNode = (Node) p;
-				} else if (p instanceof Way) {
-					if (selectedWay != null) return;
-					selectedWay = (Way) p;
-				}
-			}
-
-			// the node from which we make a connection
-			Node n0 = null;
-
-			if (selectedNode == null) {
-				if (selectedWay == null) return;
-				if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
-					n0 = lastUsedNode;
-				}
-			} else if (selectedWay == null) {
-				n0 = selectedNode;
-			} else {
-				if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
-					n0 = selectedNode;
-				}
-			}
-
-			if (n0 == null || n0 == n) {
-				return; // Don't create zero length way segments.
-			}
-
-			// Ok we know now that we'll insert a line segment, but will it connect to an
-			// existing way or make a new way of its own? The "alt" modifier means that the
-			// user wants a new way.
-
-			Way way = alt ? null : (selectedWay != null) ? selectedWay : getWayForNode(n0);
-			if (way == null) {
-				way = new Way();
-				way.nodes.add(n0);
-				cmds.add(new AddCommand(way));
-			} else {
-				int i;
-				if ((i = replacedWays.indexOf(way)) != -1) {
-					way = reuseWays.get(i);
-				} else {
-					Way wnew = new Way(way);
-					cmds.add(new ChangeCommand(way, wnew));
-					way = wnew;
-				}
-			}
-
-			if (way.nodes.get(way.nodes.size() - 1) == n0) {
-				way.nodes.add(n);
-			} else {
-				way.nodes.add(0, n);
-			}
-
-			extendedWay = true;
-			Main.ds.setSelected(way);
-		}
-
-		String title;
-		if (!extendedWay && !newNode) {
-			return; // We didn't do anything.
-		} else if (!extendedWay) {
-			if (reuseWays.isEmpty()) {
-				title = tr("Add node");
-			} else {
-				title = tr("Add node into way");
-			}
-			for (Way w : reuseWays) w.selected = false;
-			Main.ds.setSelected(n);
-		} else if (!newNode) {
-			title = tr("Connect existing way to node");
-		} else if (reuseWays.isEmpty()) {
-			title = tr("Add a new node to an existing way");
-		} else {
-			title = tr("Add node into way and connect");
-		}
-
-		Command c = new SequenceCommand(title, cmds);
-
-		Main.main.undoRedo.add(c);
-		lastUsedNode = n;
-		computeHelperLine();
-		Main.map.mapView.repaint();
-	}
-
-	@Override public void mouseMoved(MouseEvent e) {
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-
-		// we copy ctrl/alt/shift from the event just in case our global
-		// AWTEvent didn't make it through the security manager. Unclear
-		// if that can ever happen but better be safe.
-
-		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-		mousePos = e.getPoint();
-
-		computeHelperLine();
-	}
-
-	/**
-	 * This method prepares data required for painting the "helper line" from
-	 * the last used position to the mouse cursor. It duplicates some code from
-	 * mouseClicked() (FIXME).
-	 */
-	private void computeHelperLine() {
-		if (mousePos == null) {
-			// Don't draw the line.
-			currentMouseEastNorth = null;
-			currentBaseNode = null;
-			return;
-		}
-
-		double distance = -1;
-		double angle = -1;
-
-		Collection<OsmPrimitive> selection = Main.ds.getSelected();
-
-		Node selectedNode = null;
-		Way selectedWay = null;
-		Node currentMouseNode = null;
-		mouseOnExistingNode = false;
-
-		Main.map.statusLine.setAngle(-1);
-		Main.map.statusLine.setHeading(-1);
-		Main.map.statusLine.setDist(-1);
-
-		if (!ctrl && mousePos != null) {
-			currentMouseNode = Main.map.mapView.getNearestNode(mousePos);
-		}
-
-		if (currentMouseNode != null) {
-			// user clicked on node
-			if (selection.isEmpty()) return;
-			currentMouseEastNorth = currentMouseNode.eastNorth;
-			mouseOnExistingNode = true;
-		} else {
-			// no node found in clicked area
-			currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
-		}
-
-		for (OsmPrimitive p : selection) {
-			if (p instanceof Node) {
-				if (selectedNode != null) return;
-				selectedNode = (Node) p;
-			} else if (p instanceof Way) {
-				if (selectedWay != null) return;
-				selectedWay = (Way) p;
-			}
-		}
-
-		// the node from which we make a connection
-		currentBaseNode = null;
-		Node previousNode = null;
-
-		if (selectedNode == null) {
-			if (selectedWay == null) return;
-			if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
-				currentBaseNode = lastUsedNode;
-				if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) {
-					previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2);
-				}
-			}
-		} else if (selectedWay == null) {
-			currentBaseNode = selectedNode;
-		} else {
-			if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
-				currentBaseNode = selectedNode;
-			}
-		}
-
-		if (currentBaseNode == null || currentBaseNode == currentMouseNode) {
-			return; // Don't create zero length way segments.
-		}
-
-		// find out the distance, in metres, between the base point and the mouse cursor
-		LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth);
-		distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon);
-		double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon));
-		if (previousNode != null) {
-			angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor));
-			if (angle < 0) angle += 360;
-		}
-		Main.map.statusLine.setAngle(angle);
-		Main.map.statusLine.setHeading(hdg);
-		Main.map.statusLine.setDist(distance);
-		updateStatusLine();
-
-		if (!drawHelperLine) return;
-
-		Main.map.mapView.repaint();
-	}
-
-	/**
-	 * Repaint on mouse exit so that the helper line goes away.
-	 */
-	@Override public void mouseExited(MouseEvent e) {
-		if(!Main.map.mapView.isDrawableLayer())
-			return;
-		mousePos = e.getPoint();
-		Main.map.mapView.repaint();
-	}
-
-	/**
-	 * @return If the node is the end of exactly one way, return this.
-	 * 	<code>null</code> otherwise.
-	 */
-	public static Way getWayForNode(Node n) {
-		Way way = null;
-		for (Way w : Main.ds.ways) {
-			if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
-			Node firstNode = w.nodes.get(0);
-			Node lastNode = w.nodes.get(w.nodes.size() - 1);
-			if ((firstNode == n || lastNode == n) && (firstNode != lastNode)) {
-				if (way != null)
-					return null;
-				way = w;
-			}
-		}
-		return way;
-	}
-
-	private static void pruneSuccsAndReverse(List<Integer> is) {
-		//if (is.size() < 2) return;
-
-		HashSet<Integer> is2 = new HashSet<Integer>();
-		for (int i : is) {
-			if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
-				is2.add(i);
-			}
-		}
-		is.clear();
-		is.addAll(is2);
-		Collections.sort(is);
-		Collections.reverse(is);
-	}
-
-	/**
-	 * Adjusts the position of a node to lie on a segment (or a segment
-	 * intersection).
-	 *
-	 * If one or more than two segments are passed, the node is adjusted
-	 * to lie on the first segment that is passed.
-	 *
-	 * If two segments are passed, the node is adjusted to be at their
-	 * intersection.
-	 *
-	 * No action is taken if no segments are passed.
-	 *
-	 * @param segs the segments to use as a reference when adjusting
-	 * @param n the node to adjust
-	 */
-	private static void adjustNode(Collection<Pair<Node,Node>> segs, Node n) {
-
-		switch (segs.size()) {
-		case 0:
-			return;
-		case 2:
-			// This computes the intersection between
-			// the two segments and adjusts the node position. 
-			Iterator<Pair<Node,Node>> i = segs.iterator();
-			Pair<Node,Node> seg = i.next();
-			EastNorth A = seg.a.eastNorth;
-			EastNorth B = seg.b.eastNorth;
-			seg = i.next();
-			EastNorth C = seg.a.eastNorth;
-			EastNorth D = seg.b.eastNorth;
-
-			double u=det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
-			
-			// Check for parallel segments and do nothing if they are
-			// In practice this will probably only happen when a way has been duplicated
-			
-			if (u == 0) return;
-			
-			// q is a number between 0 and 1
-			// It is the point in the segment where the intersection occurs
-			// if the segment is scaled to lenght 1
-			
-			double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
-			EastNorth intersection = new EastNorth(
-					B.east() + q * (A.east() - B.east()),
-					B.north() + q * (A.north() - B.north()));
-
-			int snapToIntersectionThreshold=0;
-			try { snapToIntersectionThreshold = Integer.parseInt(Main.pref.get("edit.snap-intersection-threshold","10")); } catch (NumberFormatException x) {}
-
-			// only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
-			// fall through to default action.
-			// (for semi-parallel lines, intersection might be miles away!)
-			if (Main.map.mapView.getPoint(n.eastNorth).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
-				n.eastNorth = intersection;
-				return;
-			}
-
-		default:
-			EastNorth P = n.eastNorth;
-			seg = segs.iterator().next();
-			A = seg.a.eastNorth;
-			B = seg.b.eastNorth;
-			double a = P.distanceSq(B);
-			double b = P.distanceSq(A);
-			double c = A.distanceSq(B);
+        return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
+    }
+
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        Main.map.mapView.addTemporaryLayer(this);
+        DataSet.selListeners.add(this);
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+        } catch (SecurityException ex) {
+        }
+        // would like to but haven't got mouse position yet:
+        // computeHelperLine(false, false, false);
+    }
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        Main.map.mapView.removeTemporaryLayer(this);
+        DataSet.selListeners.remove(this);
+        try {
+            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+        } catch (SecurityException ex) {
+        }
+    }
+
+    /**
+     * redraw to (possibly) get rid of helper line if selection changes.
+     */
+    public void eventDispatched(AWTEvent event) {
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        InputEvent e = (InputEvent) event;
+        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        computeHelperLine();
+    }
+    /**
+     * redraw to (possibly) get rid of helper line if selection changes.
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        computeHelperLine();
+    }
+
+    /**
+     * If user clicked with the left button, add a node at the current mouse
+     * position.
+     *
+     * If in nodeway mode, insert the node into the way.
+     */
+    @Override public void mouseClicked(MouseEvent e) {
+
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+
+        // we copy ctrl/alt/shift from the event just in case our global
+        // AWTEvent didn't make it through the security manager. Unclear
+        // if that can ever happen but better be safe.
+        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        mousePos = e.getPoint();
+
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+        Collection<Command> cmds = new LinkedList<Command>();
+
+        ArrayList<Way> reuseWays = new ArrayList<Way>(),
+            replacedWays = new ArrayList<Way>();
+        boolean newNode = false;
+        Node n = null;
+
+        if (!ctrl) {
+            n = Main.map.mapView.getNearestNode(mousePos);
+        }
+
+        if (n != null) {
+            // user clicked on node
+            if (shift || selection.isEmpty()) {
+                // select the clicked node and do nothing else
+                // (this is just a convenience option so that people don't
+                // have to switch modes)
+                Main.ds.setSelected(n);
+                return;
+            }
+
+        } else {
+            // no node found in clicked area
+            n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
+            if (n.coor.isOutSideWorld()) {
+                JOptionPane.showMessageDialog(Main.parent,
+                    tr("Cannot add a node outside of the world."));
+                return;
+            }
+            newNode = true;
+
+            cmds.add(new AddCommand(n));
+
+            if (!ctrl) {
+                // Insert the node into all the nearby way segments
+                List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint());
+                Map<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
+                for (WaySegment ws : wss) {
+                    List<Integer> is;
+                    if (insertPoints.containsKey(ws.way)) {
+                        is = insertPoints.get(ws.way);
+                    } else {
+                        is = new ArrayList<Integer>();
+                        insertPoints.put(ws.way, is);
+                    }
+
+                    is.add(ws.lowerIndex);
+                }
+
+                Set<Pair<Node,Node>> segSet = new HashSet<Pair<Node,Node>>();
+
+                for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
+                    Way w = insertPoint.getKey();
+                    List<Integer> is = insertPoint.getValue();
+
+                    Way wnew = new Way(w);
+
+                    pruneSuccsAndReverse(is);
+                    for (int i : is) segSet.add(
+                        Pair.sort(new Pair<Node,Node>(w.nodes.get(i), w.nodes.get(i+1))));
+                    for (int i : is) wnew.nodes.add(i + 1, n);
+
+                    cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
+                    replacedWays.add(insertPoint.getKey());
+                    reuseWays.add(wnew);
+                }
+
+                adjustNode(segSet, n);
+            }
+        }
+
+        // This part decides whether or not a "segment" (i.e. a connection) is made to an
+        // existing node.
+
+        // For a connection to be made, the user must either have a node selected (connection
+        // is made to that node), or he must have a way selected *and* one of the endpoints
+        // of that way must be the last used node (connection is made to last used node), or
+        // he must have a way and a node selected (connection is made to the selected node).
+
+        boolean extendedWay = false;
+
+        if (!shift && selection.size() > 0 && selection.size() < 3) {
+
+            Node selectedNode = null;
+            Way selectedWay = null;
+
+            for (OsmPrimitive p : selection) {
+                if (p instanceof Node) {
+                    if (selectedNode != null) return;
+                    selectedNode = (Node) p;
+                } else if (p instanceof Way) {
+                    if (selectedWay != null) return;
+                    selectedWay = (Way) p;
+                }
+            }
+
+            // the node from which we make a connection
+            Node n0 = null;
+
+            if (selectedNode == null) {
+                if (selectedWay == null) return;
+                if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+                    n0 = lastUsedNode;
+                }
+            } else if (selectedWay == null) {
+                n0 = selectedNode;
+            } else {
+                if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+                    n0 = selectedNode;
+                }
+            }
+
+            if (n0 == null || n0 == n) {
+                return; // Don't create zero length way segments.
+            }
+
+            // Ok we know now that we'll insert a line segment, but will it connect to an
+            // existing way or make a new way of its own? The "alt" modifier means that the
+            // user wants a new way.
+
+            Way way = alt ? null : (selectedWay != null) ? selectedWay : getWayForNode(n0);
+            if (way == null) {
+                way = new Way();
+                way.nodes.add(n0);
+                cmds.add(new AddCommand(way));
+            } else {
+                int i;
+                if ((i = replacedWays.indexOf(way)) != -1) {
+                    way = reuseWays.get(i);
+                } else {
+                    Way wnew = new Way(way);
+                    cmds.add(new ChangeCommand(way, wnew));
+                    way = wnew;
+                }
+            }
+
+            if (way.nodes.get(way.nodes.size() - 1) == n0) {
+                way.nodes.add(n);
+            } else {
+                way.nodes.add(0, n);
+            }
+
+            extendedWay = true;
+            Main.ds.setSelected(way);
+        }
+
+        String title;
+        if (!extendedWay && !newNode) {
+            return; // We didn't do anything.
+        } else if (!extendedWay) {
+            if (reuseWays.isEmpty()) {
+                title = tr("Add node");
+            } else {
+                title = tr("Add node into way");
+            }
+            for (Way w : reuseWays) w.selected = false;
+            Main.ds.setSelected(n);
+        } else if (!newNode) {
+            title = tr("Connect existing way to node");
+        } else if (reuseWays.isEmpty()) {
+            title = tr("Add a new node to an existing way");
+        } else {
+            title = tr("Add node into way and connect");
+        }
+
+        Command c = new SequenceCommand(title, cmds);
+
+        Main.main.undoRedo.add(c);
+        lastUsedNode = n;
+        computeHelperLine();
+        Main.map.mapView.repaint();
+    }
+
+    @Override public void mouseMoved(MouseEvent e) {
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+
+        // we copy ctrl/alt/shift from the event just in case our global
+        // AWTEvent didn't make it through the security manager. Unclear
+        // if that can ever happen but better be safe.
+
+        ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+        shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        mousePos = e.getPoint();
+
+        computeHelperLine();
+    }
+
+    /**
+     * This method prepares data required for painting the "helper line" from
+     * the last used position to the mouse cursor. It duplicates some code from
+     * mouseClicked() (FIXME).
+     */
+    private void computeHelperLine() {
+        if (mousePos == null) {
+            // Don't draw the line.
+            currentMouseEastNorth = null;
+            currentBaseNode = null;
+            return;
+        }
+
+        double distance = -1;
+        double angle = -1;
+
+        Collection<OsmPrimitive> selection = Main.ds.getSelected();
+
+        Node selectedNode = null;
+        Way selectedWay = null;
+        Node currentMouseNode = null;
+        mouseOnExistingNode = false;
+
+        Main.map.statusLine.setAngle(-1);
+        Main.map.statusLine.setHeading(-1);
+        Main.map.statusLine.setDist(-1);
+
+        if (!ctrl && mousePos != null) {
+            currentMouseNode = Main.map.mapView.getNearestNode(mousePos);
+        }
+
+        if (currentMouseNode != null) {
+            // user clicked on node
+            if (selection.isEmpty()) return;
+            currentMouseEastNorth = currentMouseNode.eastNorth;
+            mouseOnExistingNode = true;
+        } else {
+            // no node found in clicked area
+            currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
+        }
+
+        for (OsmPrimitive p : selection) {
+            if (p instanceof Node) {
+                if (selectedNode != null) return;
+                selectedNode = (Node) p;
+            } else if (p instanceof Way) {
+                if (selectedWay != null) return;
+                selectedWay = (Way) p;
+            }
+        }
+
+        // the node from which we make a connection
+        currentBaseNode = null;
+        Node previousNode = null;
+
+        if (selectedNode == null) {
+            if (selectedWay == null) return;
+            if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+                currentBaseNode = lastUsedNode;
+                if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) {
+                    previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2);
+                }
+            }
+        } else if (selectedWay == null) {
+            currentBaseNode = selectedNode;
+        } else {
+            if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+                currentBaseNode = selectedNode;
+            }
+        }
+
+        if (currentBaseNode == null || currentBaseNode == currentMouseNode) {
+            return; // Don't create zero length way segments.
+        }
+
+        // find out the distance, in metres, between the base point and the mouse cursor
+        LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth);
+        distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon);
+        double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon));
+        if (previousNode != null) {
+            angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor));
+            if (angle < 0) angle += 360;
+        }
+        Main.map.statusLine.setAngle(angle);
+        Main.map.statusLine.setHeading(hdg);
+        Main.map.statusLine.setDist(distance);
+        updateStatusLine();
+
+        if (!drawHelperLine) return;
+
+        Main.map.mapView.repaint();
+    }
+
+    /**
+     * Repaint on mouse exit so that the helper line goes away.
+     */
+    @Override public void mouseExited(MouseEvent e) {
+        if(!Main.map.mapView.isDrawableLayer())
+            return;
+        mousePos = e.getPoint();
+        Main.map.mapView.repaint();
+    }
+
+    /**
+     * @return If the node is the end of exactly one way, return this.
+     *  <code>null</code> otherwise.
+     */
+    public static Way getWayForNode(Node n) {
+        Way way = null;
+        for (Way w : Main.ds.ways) {
+            if (w.deleted || w.incomplete || w.nodes.size() < 1) continue;
+            Node firstNode = w.nodes.get(0);
+            Node lastNode = w.nodes.get(w.nodes.size() - 1);
+            if ((firstNode == n || lastNode == n) && (firstNode != lastNode)) {
+                if (way != null)
+                    return null;
+                way = w;
+            }
+        }
+        return way;
+    }
+
+    private static void pruneSuccsAndReverse(List<Integer> is) {
+        //if (is.size() < 2) return;
+
+        HashSet<Integer> is2 = new HashSet<Integer>();
+        for (int i : is) {
+            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
+                is2.add(i);
+            }
+        }
+        is.clear();
+        is.addAll(is2);
+        Collections.sort(is);
+        Collections.reverse(is);
+    }
+
+    /**
+     * Adjusts the position of a node to lie on a segment (or a segment
+     * intersection).
+     *
+     * If one or more than two segments are passed, the node is adjusted
+     * to lie on the first segment that is passed.
+     *
+     * If two segments are passed, the node is adjusted to be at their
+     * intersection.
+     *
+     * No action is taken if no segments are passed.
+     *
+     * @param segs the segments to use as a reference when adjusting
+     * @param n the node to adjust
+     */
+    private static void adjustNode(Collection<Pair<Node,Node>> segs, Node n) {
+
+        switch (segs.size()) {
+        case 0:
+            return;
+        case 2:
+            // This computes the intersection between
+            // the two segments and adjusts the node position.
+            Iterator<Pair<Node,Node>> i = segs.iterator();
+            Pair<Node,Node> seg = i.next();
+            EastNorth A = seg.a.eastNorth;
+            EastNorth B = seg.b.eastNorth;
+            seg = i.next();
+            EastNorth C = seg.a.eastNorth;
+            EastNorth D = seg.b.eastNorth;
+
+            double u=det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
+
+            // Check for parallel segments and do nothing if they are
+            // In practice this will probably only happen when a way has been duplicated
+
+            if (u == 0) return;
+
+            // q is a number between 0 and 1
+            // It is the point in the segment where the intersection occurs
+            // if the segment is scaled to lenght 1
+
+            double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
+            EastNorth intersection = new EastNorth(
+                    B.east() + q * (A.east() - B.east()),
+                    B.north() + q * (A.north() - B.north()));
+
+            int snapToIntersectionThreshold=0;
+            try { snapToIntersectionThreshold = Integer.parseInt(Main.pref.get("edit.snap-intersection-threshold","10")); } catch (NumberFormatException x) {}
+
+            // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
+            // fall through to default action.
+            // (for semi-parallel lines, intersection might be miles away!)
+            if (Main.map.mapView.getPoint(n.eastNorth).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
+                n.eastNorth = intersection;
+                return;
+            }
+
+        default:
+            EastNorth P = n.eastNorth;
+            seg = segs.iterator().next();
+            A = seg.a.eastNorth;
+            B = seg.b.eastNorth;
+            double a = P.distanceSq(B);
+            double b = P.distanceSq(A);
+            double c = A.distanceSq(B);
             q = (a - b + c) / (2*c);
-			n.eastNorth = new EastNorth(
-				B.east() + q * (A.east() - B.east()),
-				B.north() + q * (A.north() - B.north()));
-		}
-	}
-
-	// helper for adjustNode
-	static double det(double a, double b, double c, double d)
-	{
-		return a * d - b * c;
-	}
-
-	public void paint(Graphics g, MapView mv) {
-
-		// don't draw line if disabled in prefs
-		if (!drawHelperLine) return;
-
-		// sanity checks
-		if (Main.map.mapView == null) return;
-		if (mousePos == null) return;
-
-		// if shift key is held ("no auto-connect"), don't draw a line
-		if (shift) return;
-
-		// don't draw line if we don't know where from or where to
-		if (currentBaseNode == null) return;
-		if (currentMouseEastNorth == null) return;
-
-		// don't draw line if mouse is outside window
-		if (!Main.map.mapView.getBounds().contains(mousePos)) return;
-
-		Graphics2D g2 = (Graphics2D) g;
-		g2.setColor(selectedColor);
-		g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-		GeneralPath b = new GeneralPath();
-		Point p1=mv.getPoint(currentBaseNode.eastNorth);
-		Point p2=mv.getPoint(currentMouseEastNorth);
-
-		double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
-
-		b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
-
-		// if alt key is held ("start new way"), draw a little perpendicular line
-		if (alt) {
-			b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
-			b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
-		}
-
-		g2.draw(b);
-		g2.setStroke(new BasicStroke(1));
-
-	}
-
-	@Override public String getModeHelpText() {
-		String rv;
-
-		if (currentBaseNode != null && !shift) {
-			if (mouseOnExistingNode) {
-				if (alt && /* FIXME: way exists */true)
-				    rv = tr("Click to create a new way to the existing node.");
-				else
-					rv =tr("Click to make a connection to the existing node.");
-			} else {
-				if (alt && /* FIXME: way exists */true)
-				    rv = tr("Click to insert a node and create a new way.");
-				else
-					rv = tr("Click to insert a new node and make a connection.");
-			}
-		}
-		else {
-			rv = tr("Click to insert a new node.");
-		}
-
-		//rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
-		//rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
-		return rv.toString();
-	}
+            n.eastNorth = new EastNorth(
+                B.east() + q * (A.east() - B.east()),
+                B.north() + q * (A.north() - B.north()));
+        }
+    }
+
+    // helper for adjustNode
+    static double det(double a, double b, double c, double d)
+    {
+        return a * d - b * c;
+    }
+
+    public void paint(Graphics g, MapView mv) {
+
+        // don't draw line if disabled in prefs
+        if (!drawHelperLine) return;
+
+        // sanity checks
+        if (Main.map.mapView == null) return;
+        if (mousePos == null) return;
+
+        // if shift key is held ("no auto-connect"), don't draw a line
+        if (shift) return;
+
+        // don't draw line if we don't know where from or where to
+        if (currentBaseNode == null) return;
+        if (currentMouseEastNorth == null) return;
+
+        // don't draw line if mouse is outside window
+        if (!Main.map.mapView.getBounds().contains(mousePos)) return;
+
+        Graphics2D g2 = (Graphics2D) g;
+        g2.setColor(selectedColor);
+        g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+        GeneralPath b = new GeneralPath();
+        Point p1=mv.getPoint(currentBaseNode.eastNorth);
+        Point p2=mv.getPoint(currentMouseEastNorth);
+
+        double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
+
+        b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
+
+        // if alt key is held ("start new way"), draw a little perpendicular line
+        if (alt) {
+            b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
+            b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
+        }
+
+        g2.draw(b);
+        g2.setStroke(new BasicStroke(1));
+
+    }
+
+    @Override public String getModeHelpText() {
+        String rv;
+
+        if (currentBaseNode != null && !shift) {
+            if (mouseOnExistingNode) {
+                if (alt && /* FIXME: way exists */true)
+                    rv = tr("Click to create a new way to the existing node.");
+                else
+                    rv =tr("Click to make a connection to the existing node.");
+            } else {
+                if (alt && /* FIXME: way exists */true)
+                    rv = tr("Click to insert a node and create a new way.");
+                else
+                    rv = tr("Click to insert a new node and make a connection.");
+            }
+        }
+        else {
+            rv = tr("Click to insert a new node.");
+        }
+
+        //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
+        //rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
+        return rv.toString();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 1169)
@@ -40,227 +40,227 @@
 public class ExtrudeAction extends MapMode implements MapViewPaintable {
 
-	enum Mode { EXTRUDE, rotate, select }
-	private Mode mode = null;
-	private long mouseDownTime = 0;
-	private WaySegment selectedSegment = null;
-	private Color selectedColor;
-
-	double xoff;
-	double yoff;
-	double distance;
-
-	/**
-	 * The old cursor before the user pressed the mouse button.
-	 */
-	private Cursor oldCursor;
-	/**
-	 * The current position of the mouse
-	 */
-	private Point mousePos;
-	/**
-	 * The position of the mouse cursor when the drag action was initiated.
-	 */
-	private Point initialMousePos;
-	/**
-	 * The time which needs to pass between click and release before something
-	 * counts as a move, in milliseconds
-	 */
-	private int initialMoveDelay = 200;
-
-	/**
-	 * Create a new SelectAction
-	 * @param mapFrame The MapFrame this action belongs to.
-	 */
-	public ExtrudeAction(MapFrame mapFrame) {
-		super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
-				Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT),
-			mapFrame,
-			getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR));
-		putValue("help", "Action/Extrude/Extrude");
-		initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
-		selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
-	}
-
-	private static Cursor getCursor(String name, String mod, int def) {
-		try {
-	        return ImageProvider.getCursor(name, mod);
+    enum Mode { EXTRUDE, rotate, select }
+    private Mode mode = null;
+    private long mouseDownTime = 0;
+    private WaySegment selectedSegment = null;
+    private Color selectedColor;
+
+    double xoff;
+    double yoff;
+    double distance;
+
+    /**
+     * The old cursor before the user pressed the mouse button.
+     */
+    private Cursor oldCursor;
+    /**
+     * The current position of the mouse
+     */
+    private Point mousePos;
+    /**
+     * The position of the mouse cursor when the drag action was initiated.
+     */
+    private Point initialMousePos;
+    /**
+     * The time which needs to pass between click and release before something
+     * counts as a move, in milliseconds
+     */
+    private int initialMoveDelay = 200;
+
+    /**
+     * Create a new SelectAction
+     * @param mapFrame The MapFrame this action belongs to.
+     */
+    public ExtrudeAction(MapFrame mapFrame) {
+        super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
+                Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT),
+            mapFrame,
+            getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR));
+        putValue("help", "Action/Extrude/Extrude");
+        initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
+        selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
+    }
+
+    private static Cursor getCursor(String name, String mod, int def) {
+        try {
+            return ImageProvider.getCursor(name, mod);
         } catch (Exception e) {
         }
-	    return Cursor.getPredefinedCursor(def);
-    }
-
-	private void setCursor(Cursor c) {
-		if (oldCursor == null) {
-			oldCursor = Main.map.mapView.getCursor();
-			Main.map.mapView.setCursor(c);
-		}
-	}
-
-	private void restoreCursor() {
-		if (oldCursor != null) {
-			Main.map.mapView.setCursor(oldCursor);
-			oldCursor = null;
-		}
-	}
-
-	@Override public void enterMode() {
-		super.enterMode();
-		Main.map.mapView.addMouseListener(this);
-		Main.map.mapView.addMouseMotionListener(this);
-	}
-
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-		Main.map.mapView.removeMouseMotionListener(this);
-		Main.map.mapView.removeTemporaryLayer(this);
-
-	}
-
-	/**
-	 * If the left mouse button is pressed, move all currently selected
-	 * objects (if one of them is under the mouse) or the current one under the
-	 * mouse (which will become selected).
-	 */
-	@Override public void mouseDragged(MouseEvent e) {
-		if (mode == Mode.select) return;
-
-		// do not count anything as a move if it lasts less than 100 milliseconds.
-		if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
-
-		if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
-			return;
-
-		if (mode == Mode.EXTRUDE) {
-			setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-		}
-
-		if (mousePos == null) {
-			mousePos = e.getPoint();
-			return;
-		}
-
-		Main.map.mapView.repaint();
-		mousePos = e.getPoint();
-
-	}
-
-	public void paint(Graphics g, MapView mv) {
-		if (selectedSegment != null) {
-			Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
-			Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
-
-			EastNorth en1 = n1.eastNorth;
-			EastNorth en2 = n2.eastNorth;
-			if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
-			EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
-
-			double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
-			// the point on the segment from which the distance to mouse pos is shortest
-			EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
-
-			// the distance, in projection units, between the base point and the mouse cursor
-			double len = base.distance(en3);
-
-			// find out the distance, in metres, between the base point and the mouse cursor
-			distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
-			Main.map.statusLine.setDist(distance);
-			updateStatusLine();
-
-			// compute the angle at which the segment is drawn
-			// and use it to compute the x and y offsets for the
-			// corner points.
-			double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
-
-			// this is a kludge because sometimes extrusion just goes the wrong direction
-			if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
-			xoff = sin_alpha * len;
-			yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
-
-			Graphics2D g2 = (Graphics2D) g;
-			g2.setColor(selectedColor);
-			g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-			GeneralPath b = new GeneralPath();
-			Point p1=mv.getPoint(en1);
-			Point p2=mv.getPoint(en2);
-			Point p3=mv.getPoint(en1.add(-xoff, -yoff));
-			Point p4=mv.getPoint(en2.add(-xoff, -yoff));
-
-			b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
-			b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
-			b.lineTo(p1.x,p1.y);
-			g2.draw(b);
-			g2.setStroke(new BasicStroke(1));
-		}
-	}
-
-	/**
-	 */
-	@Override public void mousePressed(MouseEvent e) {
-		if (!(Boolean)this.getValue("active")) return;
-		if (e.getButton() != MouseEvent.BUTTON1)
-			return;
-		// boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		// boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-		// boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-
-		mouseDownTime = System.currentTimeMillis();
-
-		selectedSegment =
-			Main.map.mapView.getNearestWaySegment(e.getPoint());
-
-		mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
-		oldCursor = Main.map.mapView.getCursor();
-
-		updateStatusLine();
-		Main.map.mapView.addTemporaryLayer(this);
-		Main.map.mapView.repaint();
-
-		mousePos = e.getPoint();
-		initialMousePos = e.getPoint();
-	}
-
-	/**
-	 * Restore the old mouse cursor.
-	 */
-	@Override public void mouseReleased(MouseEvent e) {
-		restoreCursor();
-		if (selectedSegment == null) return;
-		if (mousePos.distance(initialMousePos) > 10) {
-			Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
-			Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
-			EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
-			Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
-			EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
-			Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
-			Way wnew = new Way(selectedSegment.way);
-			wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
-			wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
-			if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
-			Collection<Command> cmds = new LinkedList<Command>();
-			cmds.add(new AddCommand(n4));
-			cmds.add(new AddCommand(n3));
-			cmds.add(new ChangeCommand(selectedSegment.way, wnew));
-			Command c = new SequenceCommand(tr("Extrude Way"), cmds);
-			Main.main.undoRedo.add(c);
-		}
-
-		Main.map.mapView.removeTemporaryLayer(this);
-		selectedSegment = null;
-		mode = null;
-		updateStatusLine();
-		Main.map.mapView.repaint();
-	}
-
-	@Override public String getModeHelpText() {
-		if (mode == Mode.select) {
-			return tr("Release the mouse button to select the objects in the rectangle.");
-		} else if (mode == Mode.EXTRUDE) {
-			return tr("Draw a rectangle of the desired size, then release the mouse button.");
-		} else if (mode == Mode.rotate) {
-			return tr("Release the mouse button to stop rotating.");
-		} else {
-			return tr("Drag a way segment to make a rectangle.");
-		}
-	}
+        return Cursor.getPredefinedCursor(def);
+    }
+
+    private void setCursor(Cursor c) {
+        if (oldCursor == null) {
+            oldCursor = Main.map.mapView.getCursor();
+            Main.map.mapView.setCursor(c);
+        }
+    }
+
+    private void restoreCursor() {
+        if (oldCursor != null) {
+            Main.map.mapView.setCursor(oldCursor);
+            oldCursor = null;
+        }
+    }
+
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+    }
+
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        Main.map.mapView.removeTemporaryLayer(this);
+
+    }
+
+    /**
+     * If the left mouse button is pressed, move all currently selected
+     * objects (if one of them is under the mouse) or the current one under the
+     * mouse (which will become selected).
+     */
+    @Override public void mouseDragged(MouseEvent e) {
+        if (mode == Mode.select) return;
+
+        // do not count anything as a move if it lasts less than 100 milliseconds.
+        if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
+
+        if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
+            return;
+
+        if (mode == Mode.EXTRUDE) {
+            setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+        }
+
+        if (mousePos == null) {
+            mousePos = e.getPoint();
+            return;
+        }
+
+        Main.map.mapView.repaint();
+        mousePos = e.getPoint();
+
+    }
+
+    public void paint(Graphics g, MapView mv) {
+        if (selectedSegment != null) {
+            Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
+            Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
+
+            EastNorth en1 = n1.eastNorth;
+            EastNorth en2 = n2.eastNorth;
+            if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
+            EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
+
+            double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
+            // the point on the segment from which the distance to mouse pos is shortest
+            EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
+
+            // the distance, in projection units, between the base point and the mouse cursor
+            double len = base.distance(en3);
+
+            // find out the distance, in metres, between the base point and the mouse cursor
+            distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
+            Main.map.statusLine.setDist(distance);
+            updateStatusLine();
+
+            // compute the angle at which the segment is drawn
+            // and use it to compute the x and y offsets for the
+            // corner points.
+            double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
+
+            // this is a kludge because sometimes extrusion just goes the wrong direction
+            if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
+            xoff = sin_alpha * len;
+            yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
+
+            Graphics2D g2 = (Graphics2D) g;
+            g2.setColor(selectedColor);
+            g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+            GeneralPath b = new GeneralPath();
+            Point p1=mv.getPoint(en1);
+            Point p2=mv.getPoint(en2);
+            Point p3=mv.getPoint(en1.add(-xoff, -yoff));
+            Point p4=mv.getPoint(en2.add(-xoff, -yoff));
+
+            b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
+            b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
+            b.lineTo(p1.x,p1.y);
+            g2.draw(b);
+            g2.setStroke(new BasicStroke(1));
+        }
+    }
+
+    /**
+     */
+    @Override public void mousePressed(MouseEvent e) {
+        if (!(Boolean)this.getValue("active")) return;
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        // boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+        // boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+
+        mouseDownTime = System.currentTimeMillis();
+
+        selectedSegment =
+            Main.map.mapView.getNearestWaySegment(e.getPoint());
+
+        mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
+        oldCursor = Main.map.mapView.getCursor();
+
+        updateStatusLine();
+        Main.map.mapView.addTemporaryLayer(this);
+        Main.map.mapView.repaint();
+
+        mousePos = e.getPoint();
+        initialMousePos = e.getPoint();
+    }
+
+    /**
+     * Restore the old mouse cursor.
+     */
+    @Override public void mouseReleased(MouseEvent e) {
+        restoreCursor();
+        if (selectedSegment == null) return;
+        if (mousePos.distance(initialMousePos) > 10) {
+            Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
+            Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
+            EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
+            Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
+            EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
+            Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
+            Way wnew = new Way(selectedSegment.way);
+            wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
+            wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
+            if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
+            Collection<Command> cmds = new LinkedList<Command>();
+            cmds.add(new AddCommand(n4));
+            cmds.add(new AddCommand(n3));
+            cmds.add(new ChangeCommand(selectedSegment.way, wnew));
+            Command c = new SequenceCommand(tr("Extrude Way"), cmds);
+            Main.main.undoRedo.add(c);
+        }
+
+        Main.map.mapView.removeTemporaryLayer(this);
+        selectedSegment = null;
+        mode = null;
+        updateStatusLine();
+        Main.map.mapView.repaint();
+    }
+
+    @Override public String getModeHelpText() {
+        if (mode == Mode.select) {
+            return tr("Release the mouse button to select the objects in the rectangle.");
+        } else if (mode == Mode.EXTRUDE) {
+            return tr("Draw a rectangle of the desired size, then release the mouse button.");
+        } else if (mode == Mode.rotate) {
+            return tr("Release the mouse button to stop rotating.");
+        } else {
+            return tr("Drag a way segment to make a rectangle.");
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 1169)
@@ -23,69 +23,69 @@
  */
 abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
-	private final Cursor cursor;
-	private Cursor oldCursor;
+    private final Cursor cursor;
+    private Cursor oldCursor;
 
-	/**
-	 * Constructor for mapmodes without an menu
-	 */
-	public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) {
-		super(name, "mapmode/"+iconName, tooltip, shortcut, false);
-		this.cursor = cursor;
-		putValue("active", false);
-	}
+    /**
+     * Constructor for mapmodes without an menu
+     */
+    public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) {
+        super(name, "mapmode/"+iconName, tooltip, shortcut, false);
+        this.cursor = cursor;
+        putValue("active", false);
+    }
 
-	/**
-	 * Constructor for mapmodes without an menu
-	 */
-	 @Deprecated
-	public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) {
-		super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false);
-		this.cursor = cursor;
-		putValue("active", false);
-	}
+    /**
+     * Constructor for mapmodes without an menu
+     */
+     @Deprecated
+    public MapMode(String name, String iconName, String tooltip, int keystroke, MapFrame mapFrame, Cursor cursor) {
+        super(name, "mapmode/"+iconName, tooltip, keystroke, 0, false);
+        this.cursor = cursor;
+        putValue("active", false);
+    }
 
-	/**
-	 * Constructor for mapmodes with an menu (no shortcut will be registered)
-	 */
-	public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) {
-		putValue(NAME, name);
-		putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName));
-		putValue(SHORT_DESCRIPTION, tooltip);
-		this.cursor = cursor;
-	}
+    /**
+     * Constructor for mapmodes with an menu (no shortcut will be registered)
+     */
+    public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) {
+        putValue(NAME, name);
+        putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName));
+        putValue(SHORT_DESCRIPTION, tooltip);
+        this.cursor = cursor;
+    }
 
-	public void enterMode() {
-		putValue("active", true);
-		oldCursor = Main.map.mapView.getCursor();
-		Main.map.mapView.setCursor(cursor);
-		updateStatusLine();
-	}
-	public void exitMode() {
-		putValue("active", false);
-		Main.map.mapView.setCursor(oldCursor);
-	}
+    public void enterMode() {
+        putValue("active", true);
+        oldCursor = Main.map.mapView.getCursor();
+        Main.map.mapView.setCursor(cursor);
+        updateStatusLine();
+    }
+    public void exitMode() {
+        putValue("active", false);
+        Main.map.mapView.setCursor(oldCursor);
+    }
 
-	protected void updateStatusLine() {
-		Main.map.statusLine.setHelpText(getModeHelpText());
-		Main.map.statusLine.repaint();
-	}
+    protected void updateStatusLine() {
+        Main.map.statusLine.setHelpText(getModeHelpText());
+        Main.map.statusLine.repaint();
+    }
 
-	public String getModeHelpText() {
-		return "";
-	}
-	/**
-	 * Call selectMapMode(this) on the parent mapFrame.
-	 */
-	public void actionPerformed(ActionEvent e) {
-		if (Main.map != null)
-			Main.map.selectMapMode(this);
-	}
+    public String getModeHelpText() {
+        return "";
+    }
+    /**
+     * Call selectMapMode(this) on the parent mapFrame.
+     */
+    public void actionPerformed(ActionEvent e) {
+        if (Main.map != null)
+            Main.map.selectMapMode(this);
+    }
 
-	public void mouseReleased(MouseEvent e) {}
-	public void mouseExited(MouseEvent e) {}
-	public void mousePressed(MouseEvent e) {}
-	public void mouseClicked(MouseEvent e) {}
-	public void mouseEntered(MouseEvent e) {}
-	public void mouseMoved(MouseEvent e) {}
-	public void mouseDragged(MouseEvent e) {}
+    public void mouseReleased(MouseEvent e) {}
+    public void mouseExited(MouseEvent e) {}
+    public void mousePressed(MouseEvent e) {}
+    public void mouseClicked(MouseEvent e) {}
+    public void mouseEntered(MouseEvent e) {}
+    public void mouseMoved(MouseEvent e) {}
+    public void mouseDragged(MouseEvent e) {}
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java	(revision 1169)
@@ -21,69 +21,69 @@
 public class PlayHeadDragMode extends MapMode {
 
-	private boolean dragging = false;
-	private Point mousePos = null;
-	private Point mouseStart = null;
-	private PlayHeadMarker playHeadMarker = null;
+    private boolean dragging = false;
+    private Point mousePos = null;
+    private Point mouseStart = null;
+    private PlayHeadMarker playHeadMarker = null;
 
-	public PlayHeadDragMode(PlayHeadMarker m) {
-		super("play head drag", "playheaddrag", "play head drag", null,
-		Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-		playHeadMarker = m;
-	}
+    public PlayHeadDragMode(PlayHeadMarker m) {
+        super("play head drag", "playheaddrag", "play head drag", null,
+        Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+        playHeadMarker = m;
+    }
 
-	@Override public void enterMode() {
-		super.enterMode();
-		Main.map.mapView.addMouseListener(this);
-		Main.map.mapView.addMouseMotionListener(this);
-	}
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+    }
 
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-		Main.map.mapView.removeMouseMotionListener(this);
-	}
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+    }
 
-	@Override public void mousePressed(MouseEvent ev) {
-		mouseStart = mousePos = ev.getPoint();
-	}
+    @Override public void mousePressed(MouseEvent ev) {
+        mouseStart = mousePos = ev.getPoint();
+    }
 
-	@Override public void mouseDragged(MouseEvent ev) {
-		if (mouseStart == null || mousePos == null) return;
-		if ((ev.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) return;
-		Point p = ev.getPoint();
-		if (p == null) return;
-		if (! dragging) {
-			if (p.distance(mouseStart) < 3) return;
-			playHeadMarker.startDrag();
-			dragging = true;
-		}
-		if (p.distance(mousePos) == 0) return;
-		playHeadMarker.drag(Main.map.mapView.getEastNorth(ev.getX(), ev.getY()));
-		mousePos = p;
-	}
+    @Override public void mouseDragged(MouseEvent ev) {
+        if (mouseStart == null || mousePos == null) return;
+        if ((ev.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0) return;
+        Point p = ev.getPoint();
+        if (p == null) return;
+        if (! dragging) {
+            if (p.distance(mouseStart) < 3) return;
+            playHeadMarker.startDrag();
+            dragging = true;
+        }
+        if (p.distance(mousePos) == 0) return;
+        playHeadMarker.drag(Main.map.mapView.getEastNorth(ev.getX(), ev.getY()));
+        mousePos = p;
+    }
 
-	@Override public void mouseReleased(MouseEvent ev) {
-		Point p = ev.getPoint();
-		mouseStart = null;
-		if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
-			return;
-		boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-		EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
-		if (! shift) {
-			playHeadMarker.reposition(en);
-		} else {
-			playHeadMarker.synchronize(en);
-		}
-		mousePos = null;
-		dragging = false;
+    @Override public void mouseReleased(MouseEvent ev) {
+        Point p = ev.getPoint();
+        mouseStart = null;
+        if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
+            return;
+        boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
+        if (! shift) {
+            playHeadMarker.reposition(en);
+        } else {
+            playHeadMarker.synchronize(en);
+        }
+        mousePos = null;
+        dragging = false;
 
-	/*
- 		boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-	 */
-	}
+    /*
+        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+     */
+    }
 
-	@Override public String getModeHelpText() {
-		return tr("Drag play head and release near track to play audio from there; SHIFT+release to synchronize audio at that point.");
-	}
+    @Override public String getModeHelpText() {
+        return tr("Drag play head and release near track to play audio from there; SHIFT+release to synchronize audio at that point.");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 1169)
@@ -30,50 +30,50 @@
 public class ZoomAction extends MapMode implements SelectionEnded {
 
-	/**
-	 * Shortcut to the mapview.
-	 */
-	private final MapView mv;
-	/**
-	 * Manager that manages the selection rectangle with the aspect ratio of the
-	 * MapView.
-	 */
-	private final SelectionManager selectionManager;
+    /**
+     * Shortcut to the mapview.
+     */
+    private final MapView mv;
+    /**
+     * Manager that manages the selection rectangle with the aspect ratio of the
+     * MapView.
+     */
+    private final SelectionManager selectionManager;
 
 
-	/**
-	 * Construct a ZoomAction without a label.
-	 * @param mapFrame The MapFrame, whose zoom mode should be enabled.
-	 */
-	public ZoomAction(MapFrame mapFrame) {
-		super(tr("Zoom"), "zoom", tr("Zoom and move map"),
-		Shortcut.registerShortcut("mapmode:zoom", tr("Mode: {0}", tr("Zoom")), KeyEvent.VK_Z, Shortcut.GROUP_EDIT),
-		mapFrame, ImageProvider.getCursor("normal", "zoom"));
-		mv = mapFrame.mapView;
-		selectionManager = new SelectionManager(this, true, mv);
-	}
+    /**
+     * Construct a ZoomAction without a label.
+     * @param mapFrame The MapFrame, whose zoom mode should be enabled.
+     */
+    public ZoomAction(MapFrame mapFrame) {
+        super(tr("Zoom"), "zoom", tr("Zoom and move map"),
+        Shortcut.registerShortcut("mapmode:zoom", tr("Mode: {0}", tr("Zoom")), KeyEvent.VK_Z, Shortcut.GROUP_EDIT),
+        mapFrame, ImageProvider.getCursor("normal", "zoom"));
+        mv = mapFrame.mapView;
+        selectionManager = new SelectionManager(this, true, mv);
+    }
 
-	/**
-	 * Zoom to the rectangle on the map.
-	 */
-	public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
-		if (r.width >= 3 && r.height >= 3) {
-			double scale = mv.getScale() * r.getWidth()/mv.getWidth();
-			EastNorth newCenter = mv.getEastNorth(r.x+r.width/2, r.y+r.height/2);
-			mv.zoomTo(newCenter, scale);
-		}
-	}
+    /**
+     * Zoom to the rectangle on the map.
+     */
+    public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
+        if (r.width >= 3 && r.height >= 3) {
+            double scale = mv.getScale() * r.getWidth()/mv.getWidth();
+            EastNorth newCenter = mv.getEastNorth(r.x+r.width/2, r.y+r.height/2);
+            mv.zoomTo(newCenter, scale);
+        }
+    }
 
-	@Override public void enterMode() {
-		super.enterMode();
-		selectionManager.register(mv);
-	}
+    @Override public void enterMode() {
+        super.enterMode();
+        selectionManager.register(mv);
+    }
 
-	@Override public void exitMode() {
-		super.exitMode();
-		selectionManager.unregister(mv);
-	}
+    @Override public void exitMode() {
+        super.exitMode();
+        selectionManager.unregister(mv);
+    }
 
-	@Override public String getModeHelpText() {
-		return tr("Zoom by dragging or Ctrl+. or Ctrl+,; move with Ctrl+up,left,down,right; move zoom with right button");
-	}
+    @Override public String getModeHelpText() {
+        return tr("Zoom by dragging or Ctrl+. or Ctrl+,; move with Ctrl+up,left,down,right; move zoom with right button");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(revision 1169)
@@ -7,100 +7,100 @@
 
 public class PushbackTokenizer {
-	private PushbackReader search;
+    private PushbackReader search;
 
-	private LinkedList<String> pushBackBuf = new LinkedList<String>();
+    private LinkedList<String> pushBackBuf = new LinkedList<String>();
 
-	public PushbackTokenizer(PushbackReader search) {
-		this.search = search;
-	}
+    public PushbackTokenizer(PushbackReader search) {
+        this.search = search;
+    }
 
-	/**
-	 * The token returned is <code>null</code> or starts with an identifier character:
-	 * - for an '-'. This will be the only character
-	 * : for an key. The value is the next token
-	 * | for "OR"
-	 * ' ' for anything else.
-	 * @return The next token in the stream.
-	 */
-	public String nextToken() {
-		if (!pushBackBuf.isEmpty()) {
-			return pushBackBuf.removeLast();
-		}
+    /**
+     * The token returned is <code>null</code> or starts with an identifier character:
+     * - for an '-'. This will be the only character
+     * : for an key. The value is the next token
+     * | for "OR"
+     * ' ' for anything else.
+     * @return The next token in the stream.
+     */
+    public String nextToken() {
+        if (!pushBackBuf.isEmpty()) {
+            return pushBackBuf.removeLast();
+        }
 
-		try {
-			int next;
-			char c = ' ';
-			while (c == ' ' || c == '\t' || c == '\n') {
-				next = search.read();
-				if (next == -1)
-					return null;
-				c = (char)next;
-			}
-			StringBuilder s;
-			switch (c) {
-			case ':':
-				next = search.read();
-				c = (char) next;
-				if (next == -1 || c == ' ' || c == '\t') {
-					pushBack(" ");
-				} else {
-					search.unread(next);
-				}
-				return ":";
-			case '-':
-				return "-";
-			case '(':
-				return "(";
-			case ')':
-				return ")";
-			case '|':
-				return "|";
-			case '"':
-				s = new StringBuilder(" ");
-				for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
-					s.append((char)nc);
-				return s.toString();
-			default:
-				s = new StringBuilder();
-			for (;;) {
-				s.append(c);
-				next = search.read();
-				if (next == -1) {
-					if (s.toString().equals("OR"))
-						return "|";
-					return " "+s.toString();
-				}
-				c = (char)next;
-				if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
-					search.unread(next);
-					if (s.toString().equals("OR"))
-						return "|";
-					return " "+s.toString();
-				}
-			}
-			}
-		} catch (IOException e) {
-			throw new RuntimeException(e.getMessage(), e);
-		}		
-	}
+        try {
+            int next;
+            char c = ' ';
+            while (c == ' ' || c == '\t' || c == '\n') {
+                next = search.read();
+                if (next == -1)
+                    return null;
+                c = (char)next;
+            }
+            StringBuilder s;
+            switch (c) {
+            case ':':
+                next = search.read();
+                c = (char) next;
+                if (next == -1 || c == ' ' || c == '\t') {
+                    pushBack(" ");
+                } else {
+                    search.unread(next);
+                }
+                return ":";
+            case '-':
+                return "-";
+            case '(':
+                return "(";
+            case ')':
+                return ")";
+            case '|':
+                return "|";
+            case '"':
+                s = new StringBuilder(" ");
+                for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
+                    s.append((char)nc);
+                return s.toString();
+            default:
+                s = new StringBuilder();
+            for (;;) {
+                s.append(c);
+                next = search.read();
+                if (next == -1) {
+                    if (s.toString().equals("OR"))
+                        return "|";
+                    return " "+s.toString();
+                }
+                c = (char)next;
+                if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
+                    search.unread(next);
+                    if (s.toString().equals("OR"))
+                        return "|";
+                    return " "+s.toString();
+                }
+            }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
 
-	public boolean readIfEqual(String tok) {
-		String nextTok = nextToken();
-		if (nextTok == null ? tok == null : nextTok.equals(tok)) 
-			return true;
-		pushBack(nextTok);
-		return false;
-	}
+    public boolean readIfEqual(String tok) {
+        String nextTok = nextToken();
+        if (nextTok == null ? tok == null : nextTok.equals(tok))
+            return true;
+        pushBack(nextTok);
+        return false;
+    }
 
-	public String readText() {
-		String nextTok = nextToken();
-		if (nextTok != null && nextTok.startsWith(" "))
-			return nextTok.substring(1);
-		pushBack(nextTok);
-		return null;
-	}
+    public String readText() {
+        String nextTok = nextToken();
+        if (nextTok != null && nextTok.startsWith(" "))
+            return nextTok.substring(1);
+        pushBack(nextTok);
+        return null;
+    }
 
-	public void pushBack(String tok) {
-		pushBackBuf.addLast(tok);
-	}
+    public void pushBack(String tok) {
+        pushBackBuf.addLast(tok);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 1169)
@@ -20,273 +20,273 @@
 public class SearchCompiler {
 
-	private boolean caseSensitive = false;
-	private PushbackTokenizer tokenizer;
-
-	public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) {
-		this.caseSensitive = caseSensitive;
-		this.tokenizer = tokenizer;
-	}
-	
-	abstract public static class Match {
-		abstract public boolean match(OsmPrimitive osm);
-	}
-
-	private static class Always extends Match {
-		@Override public boolean match(OsmPrimitive osm) {
-			return true;
-		}
-	}
-
-	private static class Not extends Match {
-		private final Match match;
-		public Not(Match match) {this.match = match;}
-		@Override public boolean match(OsmPrimitive osm) {
-			return !match.match(osm);
-		}
-		@Override public String toString() {return "!"+match;}
-	}
-
-	private static class And extends Match {
-		private Match lhs;
-		private Match rhs;
-		public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
-		@Override public boolean match(OsmPrimitive osm) {
-			return lhs.match(osm) && rhs.match(osm);
-		}
-		@Override public String toString() {return lhs+" && "+rhs;}
-	}
-
-	private static class Or extends Match {
-		private Match lhs;
-		private Match rhs;
-		public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
-		@Override public boolean match(OsmPrimitive osm) {
-			return lhs.match(osm) || rhs.match(osm);
-		}
-		@Override public String toString() {return lhs+" || "+rhs;}
-	}
-
-	private static class Id extends Match {
-		private long id;
-		public Id(long id) {this.id = id;}
-		@Override public boolean match(OsmPrimitive osm) {
-			return osm.id == id;
-		}
-		@Override public String toString() {return "id="+id;}
-	}
-
-	private class KeyValue extends Match {
-		private String key;
-		private String value;
-		public KeyValue(String key, String value) {this.key = key; this.value = value; }
-		@Override public boolean match(OsmPrimitive osm) {
-			String value = null;
-			if (key.equals("timestamp"))
-				value = osm.getTimeStr();
-			else
-				value = osm.get(key);
-			if (value == null)
-				return false;
-			String v1 = caseSensitive ? value : value.toLowerCase();
-			String v2 = caseSensitive ? this.value : this.value.toLowerCase();
-			// is not Java 1.5
- 			//v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
- 			//v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
-			return v1.indexOf(v2) != -1;
-		}
-		@Override public String toString() {return key+"="+value;}
-	}
-
-	private class Any extends Match {
-		private String s;
-		public Any(String s) {this.s = s;}
-		@Override public boolean match(OsmPrimitive osm) {
-			if (osm.keys == null)
-				return s.equals("");
-			String search = caseSensitive ? s : s.toLowerCase();
-			// is not Java 1.5
-			//search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);
-			for (Entry<String, String> e : osm.keys.entrySet()) {
-				String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
-				String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
-				// is not Java 1.5
-				//value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
-				if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
-					return true;
-			}
-			if (osm.user != null) {
-				String name = osm.user.name;
-				// is not Java 1.5
-				//String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC);
-				if (!caseSensitive)
-					name = name.toLowerCase();
-				if (name.indexOf(search) != -1)
-					return true;
-			}
-			return false;
-		}
-		@Override public String toString() {return s;}
-	}
-
-	private static class ExactType extends Match {
-		private String type;
-		public ExactType(String type) {this.type = type;}
-		@Override public boolean match(OsmPrimitive osm) {
-			if (osm instanceof Node)
-				return type.equals("node");
-			if (osm instanceof Way)
-				return type.equals("way");
-			if (osm instanceof Relation)
-				return type.equals("relation");
-			throw new IllegalStateException("unknown class "+osm.getClass());
-		}
-		@Override public String toString() {return "type="+type;}
-	}
-
-	private static class UserMatch extends Match {
-		private User user;
-		public UserMatch(String user) { this.user = User.get(user); }
-		@Override public boolean match(OsmPrimitive osm) {
-			return osm.user == user;
-		}
-		@Override public String toString() { return "user=" + user.name; }
-	}
-
-	private static class NodeCount extends Match {
-		private int count;
-		public NodeCount(int count) {this.count = count;}
-		@Override public boolean match(OsmPrimitive osm) {
-			return osm instanceof Way && ((Way) osm).nodes.size() == count;
-		}
-		@Override public String toString() {return "nodes="+count;}
-	}
-
-	private static class Modified extends Match {
-		@Override public boolean match(OsmPrimitive osm) {
-			return osm.modified || osm.id == 0;
-		}
-		@Override public String toString() {return "modified";}
-	}
-	
-	private static class Selected extends Match {
-		@Override public boolean match(OsmPrimitive osm) {
-			return osm.selected;
-		}
-		@Override public String toString() {return "selected";}
-	}
-
-	private static class Incomplete extends Match {
-		@Override public boolean match(OsmPrimitive osm) {
+    private boolean caseSensitive = false;
+    private PushbackTokenizer tokenizer;
+
+    public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) {
+        this.caseSensitive = caseSensitive;
+        this.tokenizer = tokenizer;
+    }
+
+    abstract public static class Match {
+        abstract public boolean match(OsmPrimitive osm);
+    }
+
+    private static class Always extends Match {
+        @Override public boolean match(OsmPrimitive osm) {
+            return true;
+        }
+    }
+
+    private static class Not extends Match {
+        private final Match match;
+        public Not(Match match) {this.match = match;}
+        @Override public boolean match(OsmPrimitive osm) {
+            return !match.match(osm);
+        }
+        @Override public String toString() {return "!"+match;}
+    }
+
+    private static class And extends Match {
+        private Match lhs;
+        private Match rhs;
+        public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
+        @Override public boolean match(OsmPrimitive osm) {
+            return lhs.match(osm) && rhs.match(osm);
+        }
+        @Override public String toString() {return lhs+" && "+rhs;}
+    }
+
+    private static class Or extends Match {
+        private Match lhs;
+        private Match rhs;
+        public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
+        @Override public boolean match(OsmPrimitive osm) {
+            return lhs.match(osm) || rhs.match(osm);
+        }
+        @Override public String toString() {return lhs+" || "+rhs;}
+    }
+
+    private static class Id extends Match {
+        private long id;
+        public Id(long id) {this.id = id;}
+        @Override public boolean match(OsmPrimitive osm) {
+            return osm.id == id;
+        }
+        @Override public String toString() {return "id="+id;}
+    }
+
+    private class KeyValue extends Match {
+        private String key;
+        private String value;
+        public KeyValue(String key, String value) {this.key = key; this.value = value; }
+        @Override public boolean match(OsmPrimitive osm) {
+            String value = null;
+            if (key.equals("timestamp"))
+                value = osm.getTimeStr();
+            else
+                value = osm.get(key);
+            if (value == null)
+                return false;
+            String v1 = caseSensitive ? value : value.toLowerCase();
+            String v2 = caseSensitive ? this.value : this.value.toLowerCase();
+            // is not Java 1.5
+            //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
+            //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
+            return v1.indexOf(v2) != -1;
+        }
+        @Override public String toString() {return key+"="+value;}
+    }
+
+    private class Any extends Match {
+        private String s;
+        public Any(String s) {this.s = s;}
+        @Override public boolean match(OsmPrimitive osm) {
+            if (osm.keys == null)
+                return s.equals("");
+            String search = caseSensitive ? s : s.toLowerCase();
+            // is not Java 1.5
+            //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);
+            for (Entry<String, String> e : osm.keys.entrySet()) {
+                String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
+                String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
+                // is not Java 1.5
+                //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
+                if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
+                    return true;
+            }
+            if (osm.user != null) {
+                String name = osm.user.name;
+                // is not Java 1.5
+                //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC);
+                if (!caseSensitive)
+                    name = name.toLowerCase();
+                if (name.indexOf(search) != -1)
+                    return true;
+            }
+            return false;
+        }
+        @Override public String toString() {return s;}
+    }
+
+    private static class ExactType extends Match {
+        private String type;
+        public ExactType(String type) {this.type = type;}
+        @Override public boolean match(OsmPrimitive osm) {
+            if (osm instanceof Node)
+                return type.equals("node");
+            if (osm instanceof Way)
+                return type.equals("way");
+            if (osm instanceof Relation)
+                return type.equals("relation");
+            throw new IllegalStateException("unknown class "+osm.getClass());
+        }
+        @Override public String toString() {return "type="+type;}
+    }
+
+    private static class UserMatch extends Match {
+        private User user;
+        public UserMatch(String user) { this.user = User.get(user); }
+        @Override public boolean match(OsmPrimitive osm) {
+            return osm.user == user;
+        }
+        @Override public String toString() { return "user=" + user.name; }
+    }
+
+    private static class NodeCount extends Match {
+        private int count;
+        public NodeCount(int count) {this.count = count;}
+        @Override public boolean match(OsmPrimitive osm) {
+            return osm instanceof Way && ((Way) osm).nodes.size() == count;
+        }
+        @Override public String toString() {return "nodes="+count;}
+    }
+
+    private static class Modified extends Match {
+        @Override public boolean match(OsmPrimitive osm) {
+            return osm.modified || osm.id == 0;
+        }
+        @Override public String toString() {return "modified";}
+    }
+
+    private static class Selected extends Match {
+        @Override public boolean match(OsmPrimitive osm) {
+            return osm.selected;
+        }
+        @Override public String toString() {return "selected";}
+    }
+
+    private static class Incomplete extends Match {
+        @Override public boolean match(OsmPrimitive osm) {
             return osm.incomplete;
-		}
-		@Override public String toString() {return "incomplete";}
-	}
-
-	public static class ParseError extends Exception {
-		public ParseError(String msg) {
-			super(msg);
-		}
-	}
-	
-	public static Match compile(String searchStr, boolean caseSensitive)
-			throws ParseError {
-		return new SearchCompiler(caseSensitive,
-				new PushbackTokenizer(
-					new PushbackReader(new StringReader(searchStr))))
-			.parse();
-	}
-
-	public Match parse() throws ParseError {
-		Match m = parseJuxta();
-		if (!tokenizer.readIfEqual(null)) {
-			throw new ParseError("Unexpected token: " + tokenizer.nextToken());
-		}
-		return m;
-	}
-
-	private Match parseJuxta() throws ParseError {
-		Match juxta = new Always();
-
-		Match m;
-		while ((m = parseOr()) != null) {
-			juxta = new And(m, juxta);
-		}
-
-		return juxta;
-	}
-
-	private Match parseOr() throws ParseError {
-		Match a = parseNot();
-		if (tokenizer.readIfEqual("|")) {
-			Match b = parseNot();
-			if (a == null || b == null) {
-				throw new ParseError(tr("Missing arguments for or."));
-			}
-			return new Or(a, b);
-		}
-		return a;
-	}
-
-	private Match parseNot() throws ParseError {
-		if (tokenizer.readIfEqual("-")) {
-			Match m = parseParens();
-			if (m == null) {
-				throw new ParseError(tr("Missing argument for not."));
-			}
-			return new Not(m);
-		}
-		return parseParens();
-	}
-
-	private Match parseParens() throws ParseError {
-		if (tokenizer.readIfEqual("(")) {
-			Match m = parseJuxta();
-			if (!tokenizer.readIfEqual(")")) {
-				throw new ParseError(tr("Expected closing parenthesis."));
-			}
-			return m;
-		}
-		return parsePat();
-	}
-
-	private Match parsePat() {
-		String tok = tokenizer.readText();
-
-		if (tokenizer.readIfEqual(":")) {
-			String tok2 = tokenizer.readText();
-			if (tok == null) tok = "";
-			if (tok2 == null) tok2 = "";
-			return parseKV(tok, tok2);
-		}
-
-		if (tok == null) {
-			return null;
-		} else if (tok.equals("modified")) {
-			return new Modified();
-		} else if (tok.equals("incomplete")) {
-			return new Incomplete();
-		} else if (tok.equals("selected")) {
-			return new Selected();
-		} else {
-			return new Any(tok);
-		}
-	}
-
-	private Match parseKV(String key, String value) {
-		if (key.equals("type")) {
-			return new ExactType(value);
-		} else if (key.equals("user")) {
-			return new UserMatch(value);
-		} else if (key.equals("nodes")) {
-			return new NodeCount(Integer.parseInt(value));
-		} else if (key.equals("id")) {
-			try {
-				return new Id(Long.parseLong(value));
-			} catch (NumberFormatException x) {
-				return new Id(0);
-			}
-		} else {
-			return new KeyValue(key, value);
-		}
-	}
+        }
+        @Override public String toString() {return "incomplete";}
+    }
+
+    public static class ParseError extends Exception {
+        public ParseError(String msg) {
+            super(msg);
+        }
+    }
+
+    public static Match compile(String searchStr, boolean caseSensitive)
+            throws ParseError {
+        return new SearchCompiler(caseSensitive,
+                new PushbackTokenizer(
+                    new PushbackReader(new StringReader(searchStr))))
+            .parse();
+    }
+
+    public Match parse() throws ParseError {
+        Match m = parseJuxta();
+        if (!tokenizer.readIfEqual(null)) {
+            throw new ParseError("Unexpected token: " + tokenizer.nextToken());
+        }
+        return m;
+    }
+
+    private Match parseJuxta() throws ParseError {
+        Match juxta = new Always();
+
+        Match m;
+        while ((m = parseOr()) != null) {
+            juxta = new And(m, juxta);
+        }
+
+        return juxta;
+    }
+
+    private Match parseOr() throws ParseError {
+        Match a = parseNot();
+        if (tokenizer.readIfEqual("|")) {
+            Match b = parseNot();
+            if (a == null || b == null) {
+                throw new ParseError(tr("Missing arguments for or."));
+            }
+            return new Or(a, b);
+        }
+        return a;
+    }
+
+    private Match parseNot() throws ParseError {
+        if (tokenizer.readIfEqual("-")) {
+            Match m = parseParens();
+            if (m == null) {
+                throw new ParseError(tr("Missing argument for not."));
+            }
+            return new Not(m);
+        }
+        return parseParens();
+    }
+
+    private Match parseParens() throws ParseError {
+        if (tokenizer.readIfEqual("(")) {
+            Match m = parseJuxta();
+            if (!tokenizer.readIfEqual(")")) {
+                throw new ParseError(tr("Expected closing parenthesis."));
+            }
+            return m;
+        }
+        return parsePat();
+    }
+
+    private Match parsePat() {
+        String tok = tokenizer.readText();
+
+        if (tokenizer.readIfEqual(":")) {
+            String tok2 = tokenizer.readText();
+            if (tok == null) tok = "";
+            if (tok2 == null) tok2 = "";
+            return parseKV(tok, tok2);
+        }
+
+        if (tok == null) {
+            return null;
+        } else if (tok.equals("modified")) {
+            return new Modified();
+        } else if (tok.equals("incomplete")) {
+            return new Incomplete();
+        } else if (tok.equals("selected")) {
+            return new Selected();
+        } else {
+            return new Any(tok);
+        }
+    }
+
+    private Match parseKV(String key, String value) {
+        if (key.equals("type")) {
+            return new ExactType(value);
+        } else if (key.equals("user")) {
+            return new UserMatch(value);
+        } else if (key.equals("nodes")) {
+            return new NodeCount(Integer.parseInt(value));
+        } else if (key.equals("id")) {
+            try {
+                return new Id(Long.parseLong(value));
+            } catch (NumberFormatException x) {
+                return new Id(0);
+            }
+        } else {
+            return new KeyValue(key, value);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java	(revision 1169)
@@ -1,5 +1,5 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 /**
- * 
+ *
  */
 package org.openstreetmap.josm.actions.search;
@@ -26,46 +26,46 @@
 
 public class SelectionWebsiteLoader extends PleaseWaitRunnable {
-	public final URL url;
-	public Collection<OsmPrimitive> sel;
-	private final SearchAction.SearchMode mode;
-	private OsmIdReader idReader = new OsmIdReader();
-	public SelectionWebsiteLoader(String urlStr, SearchAction.SearchMode mode) {
-		super(tr("Load Selection"));
-		this.mode = mode;
-		URL u = null;
-		try {u = new URL(urlStr);} catch (MalformedURLException e) {}
-		this.url = u;
-	}
-	@Override protected void realRun() {
-		Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost()));
-		sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives();
-		try {
-			URLConnection con = url.openConnection();
-			InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg);
-			Main.pleaseWaitDlg.currentAction.setText(tr("Downloading..."));
-			Map<Long, String> ids = idReader.parseIds(in);
-			for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
-				if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) {
-					if (mode == SearchAction.SearchMode.remove)
-						sel.remove(osm);
-					else
-						sel.add(osm);
-				}
-			}
-		} catch (IOException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not read from url: \"{0}\"",url));
-		} catch (SAXException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent,tr("Parsing error in url: \"{0}\"",url));
-		}
-	}
-	@Override protected void cancel() {
-		sel = null;
-		idReader.cancel();
-	}
-	@Override protected void finish() {
-		if (sel != null)
-			Main.ds.setSelected(sel);
-	}
+    public final URL url;
+    public Collection<OsmPrimitive> sel;
+    private final SearchAction.SearchMode mode;
+    private OsmIdReader idReader = new OsmIdReader();
+    public SelectionWebsiteLoader(String urlStr, SearchAction.SearchMode mode) {
+        super(tr("Load Selection"));
+        this.mode = mode;
+        URL u = null;
+        try {u = new URL(urlStr);} catch (MalformedURLException e) {}
+        this.url = u;
+    }
+    @Override protected void realRun() {
+        Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost()));
+        sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives();
+        try {
+            URLConnection con = url.openConnection();
+            InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg);
+            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading..."));
+            Map<Long, String> ids = idReader.parseIds(in);
+            for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
+                if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) {
+                    if (mode == SearchAction.SearchMode.remove)
+                        sel.remove(osm);
+                    else
+                        sel.add(osm);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not read from url: \"{0}\"",url));
+        } catch (SAXException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent,tr("Parsing error in url: \"{0}\"",url));
+        }
+    }
+    @Override protected void cancel() {
+        sel = null;
+        idReader.cancel();
+    }
+    @Override protected void finish() {
+        if (sel != null)
+            Main.ds.setSelected(sel);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/command/AddCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/AddCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/AddCommand.java	(revision 1169)
@@ -22,48 +22,48 @@
  * A command that adds an osm primitive to a dataset. Keys cannot be added this
  * way.
- * 
+ *
  * See {@link ChangeCommand ChangeCommand} for comments on relation back references.
- * 
+ *
  * @author imi
  */
 public class AddCommand extends Command {
 
-	/**
-	 * The primitive to add to the dataset.
-	 */
-	private final OsmPrimitive osm;
-	
-	private DataSet ds;
+    /**
+     * The primitive to add to the dataset.
+     */
+    private final OsmPrimitive osm;
 
-	/**
-	 * Create the command and specify the element to add.
-	 */
-	public AddCommand(OsmPrimitive osm) {
-		this.osm = osm;
-		this.ds = Main.main.editLayer().data;
-	}
+    private DataSet ds;
 
-	@Override public boolean executeCommand() {
-		osm.visit(new AddVisitor(ds));
-		return true;
-	}
-
-	@Override public void undoCommand() {
-		osm.visit(new DeleteVisitor(ds));
-	}
-
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		added.add(osm);
-	}
-
-	// faster implementation
-	@Override public boolean invalidBecauselayerRemoved(Layer oldLayer) {
-	    return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds;
+    /**
+     * Create the command and specify the element to add.
+     */
+    public AddCommand(OsmPrimitive osm) {
+        this.osm = osm;
+        this.ds = Main.main.editLayer().data;
     }
 
-	@Override public MutableTreeNode description() {
-		NameVisitor v = new NameVisitor();
-		osm.visit(v);
-		return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
+    @Override public boolean executeCommand() {
+        osm.visit(new AddVisitor(ds));
+        return true;
+    }
+
+    @Override public void undoCommand() {
+        osm.visit(new DeleteVisitor(ds));
+    }
+
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        added.add(osm);
+    }
+
+    // faster implementation
+    @Override public boolean invalidBecauselayerRemoved(Layer oldLayer) {
+        return oldLayer instanceof OsmDataLayer && ((OsmDataLayer)oldLayer).data == ds;
+    }
+
+    @Override public MutableTreeNode description() {
+        NameVisitor v = new NameVisitor();
+        osm.visit(v);
+        return new DefaultMutableTreeNode(new JLabel(tr("Add")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/ChangeCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/ChangeCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/ChangeCommand.java	(revision 1169)
@@ -14,34 +14,34 @@
 
 /**
- * Command that basically replaces one OSM primitive by another of the 
+ * Command that basically replaces one OSM primitive by another of the
  * same type.
- *  
+ *
  * @author Imi
  */
 public class ChangeCommand extends Command {
 
-	private final OsmPrimitive osm;
-	private final OsmPrimitive newOsm;
+    private final OsmPrimitive osm;
+    private final OsmPrimitive newOsm;
 
-	public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) {
-		this.osm = osm;
-		this.newOsm = newOsm;
+    public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) {
+        this.osm = osm;
+        this.newOsm = newOsm;
     }
 
-	@Override public boolean executeCommand() {
-	    super.executeCommand();
-	    osm.cloneFrom(newOsm);
-	    osm.modified = true;
-		return true;
+    @Override public boolean executeCommand() {
+        super.executeCommand();
+        osm.cloneFrom(newOsm);
+        osm.modified = true;
+        return true;
     }
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		modified.add(osm);
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        modified.add(osm);
     }
 
-	@Override public MutableTreeNode description() {
-		NameVisitor v = new NameVisitor();
-		osm.visit(v);
-		return new DefaultMutableTreeNode(new JLabel(tr("Change")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
+    @Override public MutableTreeNode description() {
+        NameVisitor v = new NameVisitor();
+        osm.visit(v);
+        return new DefaultMutableTreeNode(new JLabel(tr("Change")+" "+tr(v.className)+" "+v.name, v.icon, JLabel.HORIZONTAL));
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java	(revision 1169)
@@ -20,89 +20,89 @@
  * Command that manipulate the key/value structure of several objects. Manages deletion,
  * adding and modify of values and keys.
- * 
+ *
  * @author imi
  */
 public class ChangePropertyCommand extends Command {
-	/**
-	 * All primitives that are affected with this command.
-	 */
-	private final List<OsmPrimitive> objects;
-	/**
-	 * The key that is subject to change.
-	 */
-	private final String key;
-	/**
-	 * The key value. If it is <code>null</code>, delete all key references with the given
-	 * key. Otherwise, change the properties of all objects to the given value or create keys of
-	 * those objects that do not have the key yet.
-	 */
-	private final String value;
-	
-	public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) {
-		this.objects = new LinkedList<OsmPrimitive>();
-		this.key = key;
-		this.value = value;
-		if (value == null) {
-			for (OsmPrimitive osm : objects) {
-				if(osm.get(key) != null)
-					this.objects.add(osm);
-			}
-		} else {
-			for (OsmPrimitive osm : objects) {
-				String val = osm.get(key);
-				if (val == null || !value.equals(val)) {
-					this.objects.add(osm);
-				}
-			}
-		}
-	}
+    /**
+     * All primitives that are affected with this command.
+     */
+    private final List<OsmPrimitive> objects;
+    /**
+     * The key that is subject to change.
+     */
+    private final String key;
+    /**
+     * The key value. If it is <code>null</code>, delete all key references with the given
+     * key. Otherwise, change the properties of all objects to the given value or create keys of
+     * those objects that do not have the key yet.
+     */
+    private final String value;
 
-	public ChangePropertyCommand(OsmPrimitive object, String key, String value) {
-		this.objects = new LinkedList<OsmPrimitive>();
-		this.key = key;
-		this.value = value;
-		String val = object.get(key);
-		if ((value == null && val != null)
-		|| (value != null && (val == null || !value.equals(val))))
-			this.objects.add(object);
-	}
-	
-	@Override public boolean executeCommand() {
-		super.executeCommand(); // save old
-		if (value == null) {
-			for (OsmPrimitive osm : objects) {
-				osm.modified = true;
-				osm.remove(key);
-			}
-		} else {
-			for (OsmPrimitive osm : objects) {
-				osm.modified = true;
-				osm.put(key, value);
-			}
-		}
-		return true;
-	}
+    public ChangePropertyCommand(Collection<? extends OsmPrimitive> objects, String key, String value) {
+        this.objects = new LinkedList<OsmPrimitive>();
+        this.key = key;
+        this.value = value;
+        if (value == null) {
+            for (OsmPrimitive osm : objects) {
+                if(osm.get(key) != null)
+                    this.objects.add(osm);
+            }
+        } else {
+            for (OsmPrimitive osm : objects) {
+                String val = osm.get(key);
+                if (val == null || !value.equals(val)) {
+                    this.objects.add(osm);
+                }
+            }
+        }
+    }
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		modified.addAll(objects);
-	}
+    public ChangePropertyCommand(OsmPrimitive object, String key, String value) {
+        this.objects = new LinkedList<OsmPrimitive>();
+        this.key = key;
+        this.value = value;
+        String val = object.get(key);
+        if ((value == null && val != null)
+        || (value != null && (val == null || !value.equals(val))))
+            this.objects.add(object);
+    }
 
-	@Override public MutableTreeNode description() {
-		String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value);
-		if (objects.size() == 1) {
-			NameVisitor v = new NameVisitor();
-			objects.iterator().next().visit(v);
-			text += " "+tr(v.className)+" "+v.name;
-		} else
-			text += " "+objects.size()+" "+trn("object","objects",objects.size());
-		DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
-		if (objects.size() == 1)
-			return root;
-		NameVisitor v = new NameVisitor();
-		for (OsmPrimitive osm : objects) {
-			osm.visit(v);
-			root.add(new DefaultMutableTreeNode(v.toLabel()));
-		}
-		return root;
+    @Override public boolean executeCommand() {
+        super.executeCommand(); // save old
+        if (value == null) {
+            for (OsmPrimitive osm : objects) {
+                osm.modified = true;
+                osm.remove(key);
+            }
+        } else {
+            for (OsmPrimitive osm : objects) {
+                osm.modified = true;
+                osm.put(key, value);
+            }
+        }
+        return true;
+    }
+
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        modified.addAll(objects);
+    }
+
+    @Override public MutableTreeNode description() {
+        String text = value == null ? tr( "Remove \"{0}\" for", key) : tr("Set {0}={1} for",key,value);
+        if (objects.size() == 1) {
+            NameVisitor v = new NameVisitor();
+            objects.iterator().next().visit(v);
+            text += " "+tr(v.className)+" "+v.name;
+        } else
+            text += " "+objects.size()+" "+trn("object","objects",objects.size());
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode(new JLabel(text, ImageProvider.get("data", "key"), JLabel.HORIZONTAL));
+        if (objects.size() == 1)
+            return root;
+        NameVisitor v = new NameVisitor();
+        for (OsmPrimitive osm : objects) {
+            osm.visit(v);
+            root.add(new DefaultMutableTreeNode(v.toLabel()));
+        }
+        return root;
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/Command.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/Command.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/Command.java	(revision 1169)
@@ -25,5 +25,5 @@
  * one atomic action on a specific dataset, such as move or delete.
  *
- * Remember that the command must be executable and undoable, even if the 
+ * Remember that the command must be executable and undoable, even if the
  * Main.ds has changed, so the command must save the dataset it operates on
  * if necessary.
@@ -47,5 +47,5 @@
    }
 
-   private CloneVisitor orig; 
+   private CloneVisitor orig;
 
    protected DataSet ds;
@@ -70,8 +70,8 @@
 
    /**
-    * Undoes the command. 
+    * Undoes the command.
     * It can be assumed that all objects are in the same state they were before.
     * It can also be assumed that executeCommand was called exactly once before.
-    * 
+    *
     * This implementation undoes all objects stored by a former call to executeCommand.
     */
@@ -122,5 +122,5 @@
     * Fill in the changed data this command operates on.
     * Add to the lists, don't clear them.
-    * 
+    *
     * @param modified The modified primitives
     * @param deleted The deleted primitives
Index: trunk/src/org/openstreetmap/josm/command/ConflictResolveCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/ConflictResolveCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/ConflictResolveCommand.java	(revision 1169)
@@ -25,56 +25,56 @@
 public class ConflictResolveCommand extends Command {
 
-	private final Collection<ConflictItem> conflicts;
-	private final Map<OsmPrimitive, OsmPrimitive> resolved;
-	private Map<OsmPrimitive, OsmPrimitive> origAllConflicts;
-	private final ConflictDialog conflictDialog;
+    private final Collection<ConflictItem> conflicts;
+    private final Map<OsmPrimitive, OsmPrimitive> resolved;
+    private Map<OsmPrimitive, OsmPrimitive> origAllConflicts;
+    private final ConflictDialog conflictDialog;
 
-	public ConflictResolveCommand(List<ConflictItem> conflicts, Map<OsmPrimitive, OsmPrimitive> resolved) {
-		this.conflicts = conflicts;
-		this.resolved = resolved;
-		conflictDialog = Main.map.conflictDialog;
-	}
+    public ConflictResolveCommand(List<ConflictItem> conflicts, Map<OsmPrimitive, OsmPrimitive> resolved) {
+        this.conflicts = conflicts;
+        this.resolved = resolved;
+        conflictDialog = Main.map.conflictDialog;
+    }
 
-	@Override public boolean executeCommand() {
-		super.executeCommand();
+    @Override public boolean executeCommand() {
+        super.executeCommand();
 
-		origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts);
-		
-		Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet());
-		for (ConflictItem ci : conflicts) {
-			for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) {
-				if (ci.resolution == ConflictResolver.Resolution.THEIR)
-					ci.apply(e.getKey(), e.getValue());
-				else if (ci.resolution == ConflictResolver.Resolution.MY)
-					ci.apply(e.getValue(), e.getKey());
-				else if (ci.hasConflict(e.getKey(), e.getValue()))
-					completed.remove(e.getKey());
-			}
-		}
-		if (!completed.isEmpty()) {
-			for (OsmPrimitive k : completed)
-				conflictDialog.conflicts.remove(k);
-			conflictDialog.rebuildList();
- 		}
-		return true;
-	}
+        origAllConflicts = new HashMap<OsmPrimitive, OsmPrimitive>(conflictDialog.conflicts);
 
-	@Override public void undoCommand() {
-		super.undoCommand();
-		Main.map.conflictDialog.conflicts.clear();
-		Main.map.conflictDialog.conflicts.putAll(origAllConflicts);
-		Main.map.conflictDialog.rebuildList();
-	}
+        Set<OsmPrimitive> completed = new HashSet<OsmPrimitive>(resolved.keySet());
+        for (ConflictItem ci : conflicts) {
+            for (Entry<OsmPrimitive, OsmPrimitive> e : resolved.entrySet()) {
+                if (ci.resolution == ConflictResolver.Resolution.THEIR)
+                    ci.apply(e.getKey(), e.getValue());
+                else if (ci.resolution == ConflictResolver.Resolution.MY)
+                    ci.apply(e.getValue(), e.getKey());
+                else if (ci.hasConflict(e.getKey(), e.getValue()))
+                    completed.remove(e.getKey());
+            }
+        }
+        if (!completed.isEmpty()) {
+            for (OsmPrimitive k : completed)
+                conflictDialog.conflicts.remove(k);
+            conflictDialog.rebuildList();
+        }
+        return true;
+    }
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		modified.addAll(resolved.keySet());
-	}
+    @Override public void undoCommand() {
+        super.undoCommand();
+        Main.map.conflictDialog.conflicts.clear();
+        Main.map.conflictDialog.conflicts.putAll(origAllConflicts);
+        Main.map.conflictDialog.rebuildList();
+    }
 
-	@Override public MutableTreeNode description() {
-		int i = 0;
-		for (ConflictItem c : conflicts)
-			if (c.resolution != null)
-				i++;
-		return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL));
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        modified.addAll(resolved.keySet());
+    }
+
+    @Override public MutableTreeNode description() {
+        int i = 0;
+        for (ConflictItem c : conflicts)
+            if (c.resolution != null)
+                i++;
+        return new DefaultMutableTreeNode(new JLabel(tr("Resolve {0} conflicts in {1} objects",i,resolved.size()), ImageProvider.get("data", "object"), JLabel.HORIZONTAL));
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 1169)
@@ -105,12 +105,12 @@
     /**
      * Delete the primitives and everything they reference.
-     * 
+     *
      * If a node is deleted, the node and all ways and relations the node is part of are deleted as
      * well.
-     * 
+     *
      * If a way is deleted, all relations the way is member of are also deleted.
-     * 
+     *
      * If a way is deleted, only the way and no nodes are deleted.
-     * 
+     *
      * @param selection The list of all object to be deleted.
      * @return command A command to perform the deletions, or null of there is nothing to delete.
@@ -130,11 +130,11 @@
     /**
      * Try to delete all given primitives.
-     * 
+     *
      * If a node is used by a way, it's removed from that way. If a node or a way is used by a
      * relation, inform the user and do not delete.
-     * 
+     *
      * If this would cause ways with less than 2 nodes to be created, delete these ways instead. If
      * they are part of a relation, inform the user and do not delete.
-     * 
+     *
      * @param selection The objects to delete.
      * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well
@@ -341,7 +341,7 @@
                             // leave message in one tr() as there is a grammatical connection.
                             tr("You are about to delete nodes outside of the area you have downloaded." +
-                            "<br>" + 
+                            "<br>" +
                             "This can cause problems because other objects (that you don't see) might use them." +
-                            "<br>" + 
+                            "<br>" +
                             "Do you really want to delete?") + "</html>"));
                         return DontShowAgainInfo.show("delete_outside_nodes", msg, false, JOptionPane.YES_NO_OPTION, JOptionPane.YES_OPTION);
Index: trunk/src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 1169)
@@ -26,99 +26,99 @@
  * MoveCommand moves a set of OsmPrimitives along the map. It can be moved again
  * to collect several MoveCommands into one command.
- * 
+ *
  * @author imi
  */
 public class MoveCommand extends Command {
-	/**
-	 * The objects that should be moved.
-	 */
-	public Collection<Node> objects = new LinkedList<Node>();
-	/**
-	 * x difference movement. Coordinates are in northern/eastern 
-	 */
-	private double x;
-	/**
-	 * y difference movement. Coordinates are in northern/eastern 
-	 */
-	private double y;
+    /**
+     * The objects that should be moved.
+     */
+    public Collection<Node> objects = new LinkedList<Node>();
+    /**
+     * x difference movement. Coordinates are in northern/eastern
+     */
+    private double x;
+    /**
+     * y difference movement. Coordinates are in northern/eastern
+     */
+    private double y;
 
-	/**
-	 * Small helper for holding the interesting part of the old data state of the
-	 * objects. 
-	 */
-	public static class OldState {
-		LatLon latlon;
-		EastNorth eastNorth;
-		boolean modified;
-	}
-	
-	/**
-	 * List of all old states of the objects.
-	 */
-	private List<OldState> oldState = new LinkedList<OldState>();
+    /**
+     * Small helper for holding the interesting part of the old data state of the
+     * objects.
+     */
+    public static class OldState {
+        LatLon latlon;
+        EastNorth eastNorth;
+        boolean modified;
+    }
 
-	
-	public MoveCommand(OsmPrimitive osm, double x, double y) {
-		this(Collections.singleton(osm), x, y);
-	}
-	/**
-	 * Create a MoveCommand and assign the initial object set and movement vector.
-	 */
-	public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
-		this.x = x;
-		this.y = y;
-		this.objects = AllNodesVisitor.getAllNodes(objects);
-		for (Node n : this.objects) {
-			OldState os = new OldState();
-			os.eastNorth = n.eastNorth;
-			os.latlon = n.coor;
-			os.modified = n.modified;
-			oldState.add(os);
-		}
-	}
+    /**
+     * List of all old states of the objects.
+     */
+    private List<OldState> oldState = new LinkedList<OldState>();
 
-	/**
-	 * Move the same set of objects again by the specified vector. The vectors
-	 * are added together and so the resulting will be moved to the previous
-	 * vector plus this one.
-	 * 
-	 * The move is immediately executed and any undo will undo both vectors to
-	 * the original position the objects had before first moving.
-	 */
-	public void moveAgain(double x, double y) {
-		for (Node n : objects) {
-			n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
-			n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
-		}
-		this.x += x;
-		this.y += y;
-	}
-	
-	@Override public boolean executeCommand() {
-		for (Node n : objects) {
-			n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
-			n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
-			n.modified = true;
-		}
-		return true;
-	}
 
-	@Override public void undoCommand() {
-		Iterator<OldState> it = oldState.iterator();
-		for (Node n : objects) {
-			OldState os = it.next();
-			n.eastNorth = os.eastNorth;
-			n.coor = os.latlon;
-			n.modified = os.modified;
-		}
-	}
+    public MoveCommand(OsmPrimitive osm, double x, double y) {
+        this(Collections.singleton(osm), x, y);
+    }
+    /**
+     * Create a MoveCommand and assign the initial object set and movement vector.
+     */
+    public MoveCommand(Collection<OsmPrimitive> objects, double x, double y) {
+        this.x = x;
+        this.y = y;
+        this.objects = AllNodesVisitor.getAllNodes(objects);
+        for (Node n : this.objects) {
+            OldState os = new OldState();
+            os.eastNorth = n.eastNorth;
+            os.latlon = n.coor;
+            os.modified = n.modified;
+            oldState.add(os);
+        }
+    }
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		for (OsmPrimitive osm : objects)
-			modified.add(osm);
-	}
+    /**
+     * Move the same set of objects again by the specified vector. The vectors
+     * are added together and so the resulting will be moved to the previous
+     * vector plus this one.
+     *
+     * The move is immediately executed and any undo will undo both vectors to
+     * the original position the objects had before first moving.
+     */
+    public void moveAgain(double x, double y) {
+        for (Node n : objects) {
+            n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
+            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
+        }
+        this.x += x;
+        this.y += y;
+    }
 
-	@Override public MutableTreeNode description() {
-		return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
+    @Override public boolean executeCommand() {
+        for (Node n : objects) {
+            n.eastNorth = new EastNorth(n.eastNorth.east()+x, n.eastNorth.north()+y);
+            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
+            n.modified = true;
+        }
+        return true;
+    }
+
+    @Override public void undoCommand() {
+        Iterator<OldState> it = oldState.iterator();
+        for (Node n : objects) {
+            OldState os = it.next();
+            n.eastNorth = os.eastNorth;
+            n.coor = os.latlon;
+            n.modified = os.modified;
+        }
+    }
+
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        for (OsmPrimitive osm : objects)
+            modified.add(osm);
+    }
+
+    @Override public MutableTreeNode description() {
+        return new DefaultMutableTreeNode(new JLabel(tr("Move")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/RotateCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/RotateCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/RotateCommand.java	(revision 1169)
@@ -23,115 +23,115 @@
 /**
  * RotateCommand rotates a number of objects around their centre.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  */
 public class RotateCommand extends Command {
-	
-	/**
-	 * The objects to rotate.
-	 */
-	public Collection<Node> objects = new LinkedList<Node>();
-	
-	/**
-	 * pivot point
-	 */
-	private Node pivot;
-	
-	/**
-	 * angle of rotation starting click to pivot
-	 */
-	private double startAngle;
-	
-	/**
-	 * computed rotation angle between starting click and current mouse pos
-	 */
-	private double rotationAngle;
-	
-	/**
-	 * List of all old states of the objects.
-	 */
-	private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();
-	
-	/**
-	 * Creates a RotateCommand.
-	 * Assign the initial object set, compute pivot point and rotation angle.
-	 * Computation of pivot point is done by the same rules that are used in 
-	 * the "align nodes in circle" action.
-	 */
-	public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
 
-		this.objects = AllNodesVisitor.getAllNodes(objects);
-		pivot = new Node(new LatLon(0,0));
-		pivot.eastNorth = new EastNorth(0,0);
+    /**
+     * The objects to rotate.
+     */
+    public Collection<Node> objects = new LinkedList<Node>();
 
-		for (Node n : this.objects) {
-			MoveCommand.OldState os = new MoveCommand.OldState();
-			os.eastNorth = n.eastNorth;
-			os.latlon = n.coor;
-			os.modified = n.modified;
-			oldState.put(n, os);
-			pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north());
-		}
-		pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size());
-		pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);
+    /**
+     * pivot point
+     */
+    private Node pivot;
 
-		rotationAngle = Math.PI/2;
-		rotateAgain(start, end);
-	}
+    /**
+     * angle of rotation starting click to pivot
+     */
+    private double startAngle;
 
-	/**
-	 * Rotate the same set of objects again, by the angle between given 
-	 * start and end nodes. Internally this is added to the existing
-	 * rotation so a later undo will undo the whole rotation.
-	 */
-	public void rotateAgain(EastNorth start, EastNorth end) {
-		// compute angle
-		startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north());
-		double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north());
-		rotationAngle += startAngle - endAngle;
-		rotateNodes(false);
-	}
+    /**
+     * computed rotation angle between starting click and current mouse pos
+     */
+    private double rotationAngle;
 
-	/**
-	 * Helper for actually rotationg the nodes.
-	 * @param setModified - true if rotated nodes should be flagged "modified"
-	 */
-	private void rotateNodes(boolean setModified) {
-		for (Node n : objects) {
-			double cosPhi = Math.cos(rotationAngle);
-			double sinPhi = Math.sin(rotationAngle);
-			EastNorth oldEastNorth = oldState.get(n).eastNorth;
-			double x = oldEastNorth.east() - pivot.eastNorth.east();
-			double y = oldEastNorth.north() - pivot.eastNorth.north();
-			double nx =  sinPhi * x + cosPhi * y + pivot.eastNorth.east();
-			double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north();
-			n.eastNorth = new EastNorth(nx, ny);
-			n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
-			if (setModified)
-				n.modified = true;	
-		}
-	}
-	
-	@Override public boolean executeCommand() {
-		rotateNodes(true);
-		return true;
-	}
+    /**
+     * List of all old states of the objects.
+     */
+    private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();
 
-	@Override public void undoCommand() {
-		for (Node n : objects) {
-			MoveCommand.OldState os = oldState.get(n);
-			n.eastNorth = os.eastNorth;
-			n.coor = os.latlon;
-			n.modified = os.modified;
-		}
-	}
+    /**
+     * Creates a RotateCommand.
+     * Assign the initial object set, compute pivot point and rotation angle.
+     * Computation of pivot point is done by the same rules that are used in
+     * the "align nodes in circle" action.
+     */
+    public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		for (OsmPrimitive osm : objects)
-			modified.add(osm);
-	}
+        this.objects = AllNodesVisitor.getAllNodes(objects);
+        pivot = new Node(new LatLon(0,0));
+        pivot.eastNorth = new EastNorth(0,0);
 
-	@Override public MutableTreeNode description() {
-		return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
+        for (Node n : this.objects) {
+            MoveCommand.OldState os = new MoveCommand.OldState();
+            os.eastNorth = n.eastNorth;
+            os.latlon = n.coor;
+            os.modified = n.modified;
+            oldState.put(n, os);
+            pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north());
+        }
+        pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size());
+        pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);
+
+        rotationAngle = Math.PI/2;
+        rotateAgain(start, end);
+    }
+
+    /**
+     * Rotate the same set of objects again, by the angle between given
+     * start and end nodes. Internally this is added to the existing
+     * rotation so a later undo will undo the whole rotation.
+     */
+    public void rotateAgain(EastNorth start, EastNorth end) {
+        // compute angle
+        startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north());
+        double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north());
+        rotationAngle += startAngle - endAngle;
+        rotateNodes(false);
+    }
+
+    /**
+     * Helper for actually rotationg the nodes.
+     * @param setModified - true if rotated nodes should be flagged "modified"
+     */
+    private void rotateNodes(boolean setModified) {
+        for (Node n : objects) {
+            double cosPhi = Math.cos(rotationAngle);
+            double sinPhi = Math.sin(rotationAngle);
+            EastNorth oldEastNorth = oldState.get(n).eastNorth;
+            double x = oldEastNorth.east() - pivot.eastNorth.east();
+            double y = oldEastNorth.north() - pivot.eastNorth.north();
+            double nx =  sinPhi * x + cosPhi * y + pivot.eastNorth.east();
+            double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north();
+            n.eastNorth = new EastNorth(nx, ny);
+            n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
+            if (setModified)
+                n.modified = true;
+        }
+    }
+
+    @Override public boolean executeCommand() {
+        rotateNodes(true);
+        return true;
+    }
+
+    @Override public void undoCommand() {
+        for (Node n : objects) {
+            MoveCommand.OldState os = oldState.get(n);
+            n.eastNorth = os.eastNorth;
+            n.coor = os.latlon;
+            n.modified = os.modified;
+        }
+    }
+
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        for (OsmPrimitive osm : objects)
+            modified.add(osm);
+    }
+
+    @Override public MutableTreeNode description() {
+        return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/SequenceCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/SequenceCommand.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/command/SequenceCommand.java	(revision 1169)
@@ -20,74 +20,74 @@
 public class SequenceCommand extends Command {
 
-	/**
-	 * The command sequenz to be executed.
-	 */
-	private Command[] sequence;
-	private boolean sequence_complete;
-	private final String name;
-	public boolean continueOnError = false;
+    /**
+     * The command sequenz to be executed.
+     */
+    private Command[] sequence;
+    private boolean sequence_complete;
+    private final String name;
+    public boolean continueOnError = false;
 
-	/**
-	 * Create the command by specifying the list of commands to execute.
-	 * @param sequenz The sequence that should be executed.
-	 */
-	public SequenceCommand(String name, Collection<Command> sequenz) {
-		this.name = name;
-		this.sequence = new Command[sequenz.size()];
-		this.sequence = sequenz.toArray(this.sequence);
-	}
+    /**
+     * Create the command by specifying the list of commands to execute.
+     * @param sequenz The sequence that should be executed.
+     */
+    public SequenceCommand(String name, Collection<Command> sequenz) {
+        this.name = name;
+        this.sequence = new Command[sequenz.size()];
+        this.sequence = sequenz.toArray(this.sequence);
+    }
 
-	/**
-	 * Convenient constructor, if the commands are known at compile time.
-	 */
-	public SequenceCommand(String name, Command... sequenz) {
-		this(name, Arrays.asList(sequenz));
-	}
-	
-	public int executed_commands = 0;
-	@Override public boolean executeCommand() {
-		for (int i=0; i < sequence.length; i++) {
-			Command c = sequence[i];
-			boolean result = c.executeCommand();
-			if (!result)
-				Main.debug("SequenceCommand, executing command[" + i + "] " +  c + " result: " + result);
-			if (!result && !continueOnError) {
-				this.undoCommands(i-1);
-				return false;
-			}
-		}
-		sequence_complete = true;
-		return true;
-	}
+    /**
+     * Convenient constructor, if the commands are known at compile time.
+     */
+    public SequenceCommand(String name, Command... sequenz) {
+        this(name, Arrays.asList(sequenz));
+    }
 
-	public Command getLastCommand() {
-		if(sequence.length == 0)
-			return null;
-		return sequence[sequence.length-1];
-	}
-	private void undoCommands(int start) {
-		// We probably aborted this halfway though the
-		// execution sequence because of a sub-command
-		// error.  We already undid the sub-commands.
-		if (!sequence_complete)
-			return;
-		for (int i = start; i >= 0; --i)
-			sequence[i].undoCommand();
-	}
+    public int executed_commands = 0;
+    @Override public boolean executeCommand() {
+        for (int i=0; i < sequence.length; i++) {
+            Command c = sequence[i];
+            boolean result = c.executeCommand();
+            if (!result)
+                Main.debug("SequenceCommand, executing command[" + i + "] " +  c + " result: " + result);
+            if (!result && !continueOnError) {
+                this.undoCommands(i-1);
+                return false;
+            }
+        }
+        sequence_complete = true;
+        return true;
+    }
 
-	@Override public void undoCommand() {
-		this.undoCommands(sequence.length-1);
-	}
+    public Command getLastCommand() {
+        if(sequence.length == 0)
+            return null;
+        return sequence[sequence.length-1];
+    }
+    private void undoCommands(int start) {
+        // We probably aborted this halfway though the
+        // execution sequence because of a sub-command
+        // error.  We already undid the sub-commands.
+        if (!sequence_complete)
+            return;
+        for (int i = start; i >= 0; --i)
+            sequence[i].undoCommand();
+    }
 
-	@Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
-		for (Command c : sequence)
-			c.fillModifiedData(modified, deleted, added);
-	}
+    @Override public void undoCommand() {
+        this.undoCommands(sequence.length-1);
+    }
 
-	@Override public MutableTreeNode description() {
-		DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name);
-		for (Command c : sequence)
-			root.add(c.description());
-	    return root;
+    @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
+        for (Command c : sequence)
+            c.fillModifiedData(modified, deleted, added);
+    }
+
+    @Override public MutableTreeNode description() {
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode(tr("Sequence")+": "+name);
+        for (Command c : sequence)
+            root.add(c.description());
+        return root;
     }
 }
Index: trunk/src/org/openstreetmap/josm/corrector/CorrectionTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/CorrectionTable.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/CorrectionTable.java	(revision 1169)
@@ -13,50 +13,50 @@
         extends JTable {
 
-	private static final int MAX_VISIBLE_LINES = 10;
+    private static final int MAX_VISIBLE_LINES = 10;
 
     public static class BoldRenderer extends JLabel implements
-	        TableCellRenderer {
+            TableCellRenderer {
 
-		public Component getTableCellRendererComponent(JTable table,
-		        Object value, boolean isSelected, boolean hasFocus, int row,
-		        int column) {
+        public Component getTableCellRendererComponent(JTable table,
+                Object value, boolean isSelected, boolean hasFocus, int row,
+                int column) {
 
-			Font f = getFont();
-			setFont(new Font(f.getName(), f.getStyle() | Font.BOLD, f.getSize()));
+            Font f = getFont();
+            setFont(new Font(f.getName(), f.getStyle() | Font.BOLD, f.getSize()));
 
-			setText((String)value);
+            setText((String)value);
 
-			return this;
-		}
-	}
+            return this;
+        }
+    }
 
-	private static BoldRenderer boldRenderer = null;
+    private static BoldRenderer boldRenderer = null;
 
-	protected CorrectionTable(TM correctionTableModel) {
-		super(correctionTableModel);
+    protected CorrectionTable(TM correctionTableModel) {
+        super(correctionTableModel);
 
-		final int correctionsSize = correctionTableModel.getCorrections().size();
-		final int lines = correctionsSize > MAX_VISIBLE_LINES ? MAX_VISIBLE_LINES
+        final int correctionsSize = correctionTableModel.getCorrections().size();
+        final int lines = correctionsSize > MAX_VISIBLE_LINES ? MAX_VISIBLE_LINES
                 : correctionsSize;
-		setPreferredScrollableViewportSize(new Dimension(400, lines
-		        * getRowHeight()));
-		getColumnModel().getColumn(correctionTableModel.getApplyColumn())
+        setPreferredScrollableViewportSize(new Dimension(400, lines
+                * getRowHeight()));
+        getColumnModel().getColumn(correctionTableModel.getApplyColumn())
                 .setPreferredWidth(40);
-		setRowSelectionAllowed(false);
-	}
+        setRowSelectionAllowed(false);
+    }
 
-	public TableCellRenderer getCellRenderer(int row, int column) {
-		if (getCorrectionTableModel().isBoldCell(row, column)) {
-			if (boldRenderer == null)
-				boldRenderer = new BoldRenderer();
-			return boldRenderer;
-		}
-		return super.getCellRenderer(row, column);
-	}
+    public TableCellRenderer getCellRenderer(int row, int column) {
+        if (getCorrectionTableModel().isBoldCell(row, column)) {
+            if (boldRenderer == null)
+                boldRenderer = new BoldRenderer();
+            return boldRenderer;
+        }
+        return super.getCellRenderer(row, column);
+    }
 
-	@SuppressWarnings("unchecked")
+    @SuppressWarnings("unchecked")
     public TM getCorrectionTableModel() {
-		return (TM)getModel();
-	}
+        return (TM)getModel();
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/corrector/CorrectionTableModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/CorrectionTableModel.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/CorrectionTableModel.java	(revision 1169)
@@ -12,69 +12,69 @@
         AbstractTableModel {
 
-	private List<C> corrections;
-	private boolean[] apply;
-	private int applyColumn;
+    private List<C> corrections;
+    private boolean[] apply;
+    private int applyColumn;
 
-	public CorrectionTableModel(List<C> corrections) {
-		super();
-		this.corrections = corrections;
-		apply = new boolean[this.corrections.size()];
-		Arrays.fill(apply, true);
-		applyColumn = getColumnCount() - 1; 
-	}
-
-	abstract public int getColumnCount();
-
-	abstract protected boolean isBoldCell(int row, int column);
-	abstract public String getCorrectionColumnName(int colIndex);
-	abstract public Object getCorrectionValueAt(int rowIndex, int colIndex);
-
-	public List<C> getCorrections() {
-		return corrections;
-	}
-	
-	public int getApplyColumn() {
-		return applyColumn;
-	}
-	
-    public boolean getApply(int i) {
-    	return apply[i];
+    public CorrectionTableModel(List<C> corrections) {
+        super();
+        this.corrections = corrections;
+        apply = new boolean[this.corrections.size()];
+        Arrays.fill(apply, true);
+        applyColumn = getColumnCount() - 1;
     }
 
-	public int getRowCount() {
-    	return corrections.size();
+    abstract public int getColumnCount();
+
+    abstract protected boolean isBoldCell(int row, int column);
+    abstract public String getCorrectionColumnName(int colIndex);
+    abstract public Object getCorrectionValueAt(int rowIndex, int colIndex);
+
+    public List<C> getCorrections() {
+        return corrections;
     }
 
-	@Override
-    public Class<?> getColumnClass(int columnIndex) {
-    	if (columnIndex == applyColumn)
-    		return Boolean.class;
-    	return String.class;
+    public int getApplyColumn() {
+        return applyColumn;
     }
 
-	@Override
-	public String getColumnName(int columnIndex) {
-    	if (columnIndex == applyColumn)
-    		return tr("Apply?");
-		
-		return getCorrectionColumnName(columnIndex);
-	}
-
-	@Override
-    public boolean isCellEditable(int rowIndex, int columnIndex) {
-    	return columnIndex == applyColumn;
+    public boolean getApply(int i) {
+        return apply[i];
     }
 
-	@Override
+    public int getRowCount() {
+        return corrections.size();
+    }
+
+    @Override
+    public Class<?> getColumnClass(int columnIndex) {
+        if (columnIndex == applyColumn)
+            return Boolean.class;
+        return String.class;
+    }
+
+    @Override
+    public String getColumnName(int columnIndex) {
+        if (columnIndex == applyColumn)
+            return tr("Apply?");
+
+        return getCorrectionColumnName(columnIndex);
+    }
+
+    @Override
+    public boolean isCellEditable(int rowIndex, int columnIndex) {
+        return columnIndex == applyColumn;
+    }
+
+    @Override
     public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
-    	if (columnIndex == applyColumn && aValue instanceof Boolean)
-    		apply[rowIndex] = (Boolean)aValue;
+        if (columnIndex == applyColumn && aValue instanceof Boolean)
+            apply[rowIndex] = (Boolean)aValue;
     }
 
     public Object getValueAt(int rowIndex, int colIndex) {
-    	if (colIndex == applyColumn)
-    		return apply[rowIndex];
-    	
-    	return getCorrectionValueAt(rowIndex, colIndex);
-	}
+        if (colIndex == applyColumn)
+            return apply[rowIndex];
+
+        return getCorrectionValueAt(rowIndex, colIndex);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java	(revision 1169)
@@ -22,14 +22,14 @@
 public class ReverseWayTagCorrector extends TagCorrector<Way> {
 
-	private static class PrefixSuffixSwitcher {
+    private static class PrefixSuffixSwitcher {
 
-		private final String a;
-		private final String b;
-		private final Pattern startPattern;
-		private final Pattern endPattern;
+        private final String a;
+        private final String b;
+        private final Pattern startPattern;
+        private final Pattern endPattern;
 
-		private final String SEPARATOR = "[:_]?";
-		
-		public PrefixSuffixSwitcher(String a, String b) {
+        private final String SEPARATOR = "[:_]?";
+
+        public PrefixSuffixSwitcher(String a, String b) {
             this.a = a;
             this.b = b;
@@ -40,101 +40,101 @@
                     SEPARATOR + "(" + a + "|" + b + ")$",
                     Pattern.CASE_INSENSITIVE);
-		}
+        }
 
-		public String apply(String text) {
-			Matcher m = startPattern.matcher(text);
-			if (!m.lookingAt())
-				m = endPattern.matcher(text);
+        public String apply(String text) {
+            Matcher m = startPattern.matcher(text);
+            if (!m.lookingAt())
+                m = endPattern.matcher(text);
 
-			if (m.lookingAt()) {
-				String leftRight = m.group(1).toLowerCase();
+            if (m.lookingAt()) {
+                String leftRight = m.group(1).toLowerCase();
 
-				StringBuilder result = new StringBuilder();
-				result.append(text.substring(0, m.start(1)));
-				result.append(leftRight.equals(a) ? b : a);
-				result.append(text.substring(m.end(1)));
-				
-				return result.toString();
-			}
-			return text;
-		}
-	}
+                StringBuilder result = new StringBuilder();
+                result.append(text.substring(0, m.start(1)));
+                result.append(leftRight.equals(a) ? b : a);
+                result.append(text.substring(m.end(1)));
 
-	private static PrefixSuffixSwitcher[] prefixSuffixSwitchers = 
-	        new PrefixSuffixSwitcher[] {
-	            new PrefixSuffixSwitcher("left", "right"),
-	            new PrefixSuffixSwitcher("forward", "backward") 
-	        };
+                return result.toString();
+            }
+            return text;
+        }
+    }
 
-	@Override
-	public Collection<Command> execute(Way way) throws UserCancelException {
-		Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap = 
-		        new HashMap<OsmPrimitive, List<TagCorrection>>();
+    private static PrefixSuffixSwitcher[] prefixSuffixSwitchers =
+            new PrefixSuffixSwitcher[] {
+                new PrefixSuffixSwitcher("left", "right"),
+                new PrefixSuffixSwitcher("forward", "backward")
+            };
 
-		ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
-		primitives.add(way);
-		primitives.addAll(way.nodes);
+    @Override
+    public Collection<Command> execute(Way way) throws UserCancelException {
+        Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap =
+                new HashMap<OsmPrimitive, List<TagCorrection>>();
 
-		for (OsmPrimitive primitive : primitives) {
-			tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>());
+        ArrayList<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
+        primitives.add(way);
+        primitives.addAll(way.nodes);
 
-			for (String key : primitive.keySet()) {
-				String newKey = key;
-				String value = primitive.get(key);
-				String newValue = value;
+        for (OsmPrimitive primitive : primitives) {
+            tagCorrectionsMap.put(primitive, new ArrayList<TagCorrection>());
 
-				if (key.equals("oneway")) {
-					if (value.equals("-1"))
-						newValue = OsmUtils.trueval;
-					else {
-						Boolean boolValue = OsmUtils.getOsmBoolean(value);
-						if (boolValue != null && boolValue.booleanValue()) {
-							newValue = "-1";
-						}
-					}
-				} else {
-					for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
-						newKey = prefixSuffixSwitcher.apply(key);
-						if (!key.equals(newKey))
-							break;
-					}
-				}
+            for (String key : primitive.keySet()) {
+                String newKey = key;
+                String value = primitive.get(key);
+                String newValue = value;
 
-				if (!key.equals(newKey) || !value.equals(newValue))
-					tagCorrectionsMap.get(primitive).add(
-					        new TagCorrection(key, value, newKey, newValue));
-			}
-		}
+                if (key.equals("oneway")) {
+                    if (value.equals("-1"))
+                        newValue = OsmUtils.trueval;
+                    else {
+                        Boolean boolValue = OsmUtils.getOsmBoolean(value);
+                        if (boolValue != null && boolValue.booleanValue()) {
+                            newValue = "-1";
+                        }
+                    }
+                } else {
+                    for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
+                        newKey = prefixSuffixSwitcher.apply(key);
+                        if (!key.equals(newKey))
+                            break;
+                    }
+                }
 
-		Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap = 
-		        new HashMap<OsmPrimitive, List<RoleCorrection>>();
-		roleCorrectionMap.put(way, new ArrayList<RoleCorrection>());
+                if (!key.equals(newKey) || !value.equals(newValue))
+                    tagCorrectionsMap.get(primitive).add(
+                            new TagCorrection(key, value, newKey, newValue));
+            }
+        }
 
-		for (Relation relation : Main.ds.relations) {
-			for (RelationMember member : relation.members) {
-				if (!member.member.realEqual(way, true)
-				        || member.role.length() == 0)
-					continue;
+        Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap =
+                new HashMap<OsmPrimitive, List<RoleCorrection>>();
+        roleCorrectionMap.put(way, new ArrayList<RoleCorrection>());
 
-				boolean found = false;
-				String newRole = null;
-				for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
-					newRole = prefixSuffixSwitcher.apply(member.role);
-					if (!newRole.equals(member.role)) {
-						found = true;
-						break;
-					}
-				}
+        for (Relation relation : Main.ds.relations) {
+            for (RelationMember member : relation.members) {
+                if (!member.member.realEqual(way, true)
+                        || member.role.length() == 0)
+                    continue;
 
-				if (found)
-					roleCorrectionMap.get(way).add(
-					        new RoleCorrection(relation, member, newRole));
-			}
-		}
+                boolean found = false;
+                String newRole = null;
+                for (PrefixSuffixSwitcher prefixSuffixSwitcher : prefixSuffixSwitchers) {
+                    newRole = prefixSuffixSwitcher.apply(member.role);
+                    if (!newRole.equals(member.role)) {
+                        found = true;
+                        break;
+                    }
+                }
 
-		return applyCorrections(tagCorrectionsMap, roleCorrectionMap,
-		        tr("When reverting this way, following changes to properties "
-		                + "of the way and its nodes are suggested in order "
-		                + "to maintain data consistency."));
-	}
+                if (found)
+                    roleCorrectionMap.get(way).add(
+                            new RoleCorrection(relation, member, newRole));
+            }
+        }
+
+        return applyCorrections(tagCorrectionsMap, roleCorrectionMap,
+                tr("When reverting this way, following changes to properties "
+                        + "of the way and its nodes are suggested in order "
+                        + "to maintain data consistency."));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrection.java	(revision 1169)
@@ -4,23 +4,23 @@
 public class TagCorrection implements Correction {
 
-	public final String oldKey;
-	public final String newKey;
-	public final String oldValue;
-	public final String newValue;
+    public final String oldKey;
+    public final String newKey;
+    public final String oldValue;
+    public final String newValue;
 
-	public TagCorrection(String oldKey, String oldValue, String newKey,
+    public TagCorrection(String oldKey, String oldValue, String newKey,
             String newValue) {
-		this.oldKey = oldKey;
-		this.oldValue = oldValue;
-		this.newKey = newKey;
-		this.newValue = newValue;
-	}
+        this.oldKey = oldKey;
+        this.oldValue = oldValue;
+        this.newKey = newKey;
+        this.newValue = newValue;
+    }
 
-	public boolean isKeyChanged() {
-		return !newKey.equals(oldKey);
-	}
+    public boolean isKeyChanged() {
+        return !newKey.equals(oldKey);
+    }
 
-	public boolean isValueChanged() {
-		return !newValue.equals(oldValue);
-	}
+    public boolean isValueChanged() {
+        return !newValue.equals(oldValue);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTable.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTable.java	(revision 1169)
@@ -7,7 +7,7 @@
         CorrectionTable<TagCorrectionTableModel> {
 
-	public TagCorrectionTable(List<TagCorrection> tagCorrections) {
-		super(new TagCorrectionTableModel(tagCorrections));
-	}
+    public TagCorrectionTable(List<TagCorrection> tagCorrections) {
+        super(new TagCorrectionTableModel(tagCorrections));
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTableModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTableModel.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrectionTableModel.java	(revision 1169)
@@ -8,49 +8,49 @@
 public class TagCorrectionTableModel extends CorrectionTableModel<TagCorrection> {
 
-	public TagCorrectionTableModel(List<TagCorrection> tagCorrections) {
-		super(tagCorrections);
-	}
+    public TagCorrectionTableModel(List<TagCorrection> tagCorrections) {
+        super(tagCorrections);
+    }
 
-	@Override
-	public int getColumnCount() {
-		return 5;
-	}
+    @Override
+    public int getColumnCount() {
+        return 5;
+    }
 
-	@Override
-	public String getCorrectionColumnName(int colIndex) {
-		switch (colIndex) {
-		case 0:
-			return tr("Old key");
-		case 1:
-			return tr("Old value");
-		case 2:
-			return tr("New key");
-		case 3:
-			return tr("New value");
-		}
-		return null;
-	}
+    @Override
+    public String getCorrectionColumnName(int colIndex) {
+        switch (colIndex) {
+        case 0:
+            return tr("Old key");
+        case 1:
+            return tr("Old value");
+        case 2:
+            return tr("New key");
+        case 3:
+            return tr("New value");
+        }
+        return null;
+    }
 
     public Object getCorrectionValueAt(int rowIndex, int colIndex) {
-		TagCorrection tagCorrection = getCorrections().get(rowIndex);
+        TagCorrection tagCorrection = getCorrections().get(rowIndex);
 
-		switch (colIndex) {
-		case 0:
-			return tagCorrection.oldKey;
-		case 1:
-			return tagCorrection.oldValue;
-		case 2:
-			return tagCorrection.newKey;
-		case 3:
-			return tagCorrection.newValue;
-		}
-		return null;
-	}
+        switch (colIndex) {
+        case 0:
+            return tagCorrection.oldKey;
+        case 1:
+            return tagCorrection.oldValue;
+        case 2:
+            return tagCorrection.newKey;
+        case 3:
+            return tagCorrection.newValue;
+        }
+        return null;
+    }
 
-	protected boolean isBoldCell(int row, int column) {
-		TagCorrection tagCorrection = getCorrections().get(row);
-		return (column == 2 && tagCorrection.isKeyChanged())
-		        || (column == 3 && tagCorrection.isValueChanged());
-	}
+    protected boolean isBoldCell(int row, int column) {
+        TagCorrection tagCorrection = getCorrections().get(row);
+        return (column == 2 && tagCorrection.isKeyChanged())
+                || (column == 3 && tagCorrection.isValueChanged());
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/corrector/TagCorrector.java	(revision 1169)
@@ -33,113 +33,113 @@
 public abstract class TagCorrector<P extends OsmPrimitive> {
 
-	public abstract Collection<Command> execute(P primitive) 
-	    throws UserCancelException;
+    public abstract Collection<Command> execute(P primitive)
+        throws UserCancelException;
 
-    private String[] applicationOptions = new String[] { 
-        tr("Apply selected changes"), 
-        tr("Don't apply changes"), 
-        tr("Cancel") 
+    private String[] applicationOptions = new String[] {
+        tr("Apply selected changes"),
+        tr("Don't apply changes"),
+        tr("Cancel")
     };
-    
-	protected Collection<Command> applyCorrections(
-	        Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,
-	        Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,
-	        String description) throws UserCancelException {
 
-		boolean hasCorrections = false;
-		for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) {
-			if (!tagCorrectionList.isEmpty()) {
-				hasCorrections = true;
-				break;
-			}
-		}
+    protected Collection<Command> applyCorrections(
+            Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,
+            Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,
+            String description) throws UserCancelException {
 
-		if (!hasCorrections)
-			for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap
-			        .values()) {
-				if (!roleCorrectionList.isEmpty()) {
-					hasCorrections = true;
-					break;
-				}
-			}
+        boolean hasCorrections = false;
+        for (List<TagCorrection> tagCorrectionList : tagCorrectionsMap.values()) {
+            if (!tagCorrectionList.isEmpty()) {
+                hasCorrections = true;
+                break;
+            }
+        }
 
-		if (hasCorrections) {
-			Collection<Command> commands = new ArrayList<Command>();
-			Map<OsmPrimitive, TagCorrectionTable> tagTableMap = 
-			    new HashMap<OsmPrimitive, TagCorrectionTable>();
-			Map<OsmPrimitive, RoleCorrectionTable> roleTableMap = 
-			    new HashMap<OsmPrimitive, RoleCorrectionTable>();
+        if (!hasCorrections)
+            for (List<RoleCorrection> roleCorrectionList : roleCorrectionMap
+                    .values()) {
+                if (!roleCorrectionList.isEmpty()) {
+                    hasCorrections = true;
+                    break;
+                }
+            }
 
-			NameVisitor nameVisitor = new NameVisitor();
+        if (hasCorrections) {
+            Collection<Command> commands = new ArrayList<Command>();
+            Map<OsmPrimitive, TagCorrectionTable> tagTableMap =
+                new HashMap<OsmPrimitive, TagCorrectionTable>();
+            Map<OsmPrimitive, RoleCorrectionTable> roleTableMap =
+                new HashMap<OsmPrimitive, RoleCorrectionTable>();
 
-			final JPanel p = new JPanel(new GridBagLayout());
+            NameVisitor nameVisitor = new NameVisitor();
 
-			final JMultilineLabel label1 = new JMultilineLabel(description);
-			label1.setMaxWidth(400);
-			p.add(label1, GBC.eop());
+            final JPanel p = new JPanel(new GridBagLayout());
 
-			final JMultilineLabel label2 = new JMultilineLabel(
-			        tr("Please select which property changes you want to apply."));
-			label2.setMaxWidth(400);
-			p.add(label2, GBC.eop());
+            final JMultilineLabel label1 = new JMultilineLabel(description);
+            label1.setMaxWidth(400);
+            p.add(label1, GBC.eop());
 
-			for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
-				final List<TagCorrection> tagCorrections = tagCorrectionsMap
-				        .get(primitive);
+            final JMultilineLabel label2 = new JMultilineLabel(
+                    tr("Please select which property changes you want to apply."));
+            label2.setMaxWidth(400);
+            p.add(label2, GBC.eop());
 
-				if (tagCorrections.isEmpty())
-					continue;
+            for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
+                final List<TagCorrection> tagCorrections = tagCorrectionsMap
+                        .get(primitive);
 
-				primitive.visit(nameVisitor);
+                if (tagCorrections.isEmpty())
+                    continue;
 
-				final JLabel propertiesLabel = new JLabel(tr("Properties of "));
-				p.add(propertiesLabel, GBC.std());
+                primitive.visit(nameVisitor);
 
-				final JLabel primitiveLabel = new JLabel(
-				        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
-				p.add(primitiveLabel, GBC.eol());
+                final JLabel propertiesLabel = new JLabel(tr("Properties of "));
+                p.add(propertiesLabel, GBC.std());
 
-				final TagCorrectionTable table = new TagCorrectionTable(
-				        tagCorrections);
-				final JScrollPane scrollPane = new JScrollPane(table);
-				p.add(scrollPane, GBC.eop());
+                final JLabel primitiveLabel = new JLabel(
+                        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
+                p.add(primitiveLabel, GBC.eol());
 
-				tagTableMap.put(primitive, table);
-			}
+                final TagCorrectionTable table = new TagCorrectionTable(
+                        tagCorrections);
+                final JScrollPane scrollPane = new JScrollPane(table);
+                p.add(scrollPane, GBC.eop());
 
-			for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
-				final List<RoleCorrection> roleCorrections = roleCorrectionMap
-				        .get(primitive);
-				if (roleCorrections.isEmpty())
-					continue;
+                tagTableMap.put(primitive, table);
+            }
 
-				primitive.visit(nameVisitor);
+            for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
+                final List<RoleCorrection> roleCorrections = roleCorrectionMap
+                        .get(primitive);
+                if (roleCorrections.isEmpty())
+                    continue;
 
-				final JLabel rolesLabel = new JLabel(
-				        tr("Roles in relations referring to"));
-				p.add(rolesLabel, GBC.std());
+                primitive.visit(nameVisitor);
 
-				final JLabel primitiveLabel = new JLabel(
-				        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
-				p.add(primitiveLabel, GBC.eol());
+                final JLabel rolesLabel = new JLabel(
+                        tr("Roles in relations referring to"));
+                p.add(rolesLabel, GBC.std());
 
-				final RoleCorrectionTable table = new RoleCorrectionTable(
-				        roleCorrections);
-				final JScrollPane scrollPane = new JScrollPane(table);
-				p.add(scrollPane, GBC.eop());
+                final JLabel primitiveLabel = new JLabel(
+                        nameVisitor.name + ":", nameVisitor.icon, JLabel.LEFT);
+                p.add(primitiveLabel, GBC.eol());
 
-				roleTableMap.put(primitive, table);
-			}
+                final RoleCorrectionTable table = new RoleCorrectionTable(
+                        roleCorrections);
+                final JScrollPane scrollPane = new JScrollPane(table);
+                p.add(scrollPane, GBC.eop());
 
-			int answer = JOptionPane.showOptionDialog(Main.parent, p,
+                roleTableMap.put(primitive, table);
+            }
+
+            int answer = JOptionPane.showOptionDialog(Main.parent, p,
                     tr("Automatic tag correction"), JOptionPane.YES_NO_CANCEL_OPTION,
-                    JOptionPane.PLAIN_MESSAGE, null, 
+                    JOptionPane.PLAIN_MESSAGE, null,
                     applicationOptions, applicationOptions[0]);
 
-			if (answer == JOptionPane.YES_OPTION) {
-				for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
-					List<TagCorrection> tagCorrections = 
+            if (answer == JOptionPane.YES_OPTION) {
+                for (OsmPrimitive primitive : tagCorrectionsMap.keySet()) {
+                    List<TagCorrection> tagCorrections =
                         tagCorrectionsMap.get(primitive);
-                    
+
                     // create the clone
                     OsmPrimitive clone = null;
@@ -147,47 +147,47 @@
                     else if (primitive instanceof Node) clone = new Node((Node)primitive);
                     else if (primitive instanceof Relation) clone = new Relation((Relation)primitive);
-                    
+
                     // use this structure to remember keys that have been set already so that
                     // they're not dropped by a later step
                     Set<String> keysChanged = new HashSet<String>();
-                    
+
                     // apply all changes to this clone
-					for (int i = 0; i < tagCorrections.size(); i++) {
-						if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
-							TagCorrection tagCorrection = tagCorrections.get(i);
-							if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) clone.remove(tagCorrection.oldKey);
-							clone.put(tagCorrection.newKey, tagCorrection.newValue);
-							keysChanged.add(tagCorrection.newKey);
-						}
-					}
-                    
+                    for (int i = 0; i < tagCorrections.size(); i++) {
+                        if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
+                            TagCorrection tagCorrection = tagCorrections.get(i);
+                            if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) clone.remove(tagCorrection.oldKey);
+                            clone.put(tagCorrection.newKey, tagCorrection.newValue);
+                            keysChanged.add(tagCorrection.newKey);
+                        }
+                    }
+
                     // save the clone
                     if (!keysChanged.isEmpty()) commands.add(new ChangeCommand(primitive, clone));
-				}
-				for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
-					List<RoleCorrection> roleCorrections = roleCorrectionMap
-					        .get(primitive);
-					for (int i = 0; i < roleCorrections.size(); i++) {
-						if (roleTableMap.get(primitive)
-						        .getCorrectionTableModel().getApply(i)) {
-							RoleCorrection roleCorrection = roleCorrections
-							        .get(i);
-							Relation newRelation = new Relation(
-							        roleCorrection.relation);
-							for (RelationMember member : newRelation.members)
-								if (member.equals(roleCorrection.member))
-									member.role = roleCorrection.newRole;
-							commands.add(new ChangeCommand(
-							        roleCorrection.relation, newRelation));
-						}
-					}
-				}
-			} else if (answer != JOptionPane.NO_OPTION) {
-			    throw new UserCancelException();
-			}
-			return commands;
-		}
+                }
+                for (OsmPrimitive primitive : roleCorrectionMap.keySet()) {
+                    List<RoleCorrection> roleCorrections = roleCorrectionMap
+                            .get(primitive);
+                    for (int i = 0; i < roleCorrections.size(); i++) {
+                        if (roleTableMap.get(primitive)
+                                .getCorrectionTableModel().getApply(i)) {
+                            RoleCorrection roleCorrection = roleCorrections
+                                    .get(i);
+                            Relation newRelation = new Relation(
+                                    roleCorrection.relation);
+                            for (RelationMember member : newRelation.members)
+                                if (member.equals(roleCorrection.member))
+                                    member.role = roleCorrection.newRole;
+                            commands.add(new ChangeCommand(
+                                    roleCorrection.relation, newRelation));
+                        }
+                    }
+                }
+            } else if (answer != JOptionPane.NO_OPTION) {
+                throw new UserCancelException();
+            }
+            return commands;
+        }
 
-		return Collections.emptyList();
-	}
+        return Collections.emptyList();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 1169)
@@ -8,72 +8,72 @@
 
 /**
- * This is a simple data class for "rectangular" areas of the world, given in 
+ * This is a simple data class for "rectangular" areas of the world, given in
  * lat/lon min/max values.
- * 
+ *
  * @author imi
  */
 public class Bounds {
-	/**
-	 * The minimum and maximum coordinates.
-	 */
-	public LatLon min, max;
+    /**
+     * The minimum and maximum coordinates.
+     */
+    public LatLon min, max;
 
-	/**
-	 * Construct bounds out of two points
-	 */
-	public Bounds(LatLon min, LatLon max) {
-		this.min = min;
-		this.max = max;
-	}
+    /**
+     * Construct bounds out of two points
+     */
+    public Bounds(LatLon min, LatLon max) {
+        this.min = min;
+        this.max = max;
+    }
 
-	/**
-	 * Construct bounds that span the whole world.
-	 */
-	public Bounds() {
-		min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON);
-		max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON);
-	}
-	
-	@Override public String toString() {
-		return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]";
-	}
+    /**
+     * Construct bounds that span the whole world.
+     */
+    public Bounds() {
+        min = new LatLon(-Projection.MAX_LAT, -Projection.MAX_LON);
+        max = new LatLon(Projection.MAX_LAT, Projection.MAX_LON);
+    }
 
-	/**
-	 * @return Center of the bounding box.
-	 */
-	public LatLon center() {
-		// FIXME: not sure whether this calculation is right; maybe there is some
-		// more complex calculation needed to get a center of a spherical
-		// dimension?
-		return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2);
-	}
-	
-	/**
-	 * Extend the bounds if necessary to include the given point.
-	 */
-	public void extend(LatLon ll) {
-		if (ll.lat() < min.lat() || ll.lon() < min.lon())
-			min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon()));
-		if (ll.lat() > max.lat() || ll.lon() > max.lon())
-			max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon()));
-	}
-	/**
-	 * Is the given point within this bounds?
-	 */
-	public boolean contains(LatLon ll) {
-		if (ll.lat() < min.lat() || ll.lon() < min.lon())
-			return false;
-		if (ll.lat() > max.lat() || ll.lon() > max.lon())
-			return false;
-		return true;
-	}
-	
-	/**
-	 * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
-	 * @return the bounding box to Rectangle2D.Double
-	 */
-	public Rectangle2D.Double asRect() {
-		return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat());
-	}
+    @Override public String toString() {
+        return "Bounds["+min.lat()+","+min.lon()+","+max.lat()+","+max.lon()+"]";
+    }
+
+    /**
+     * @return Center of the bounding box.
+     */
+    public LatLon center() {
+        // FIXME: not sure whether this calculation is right; maybe there is some
+        // more complex calculation needed to get a center of a spherical
+        // dimension?
+        return new LatLon((min.lat()+max.lat())/2, (min.lon()+max.lon())/2);
+    }
+
+    /**
+     * Extend the bounds if necessary to include the given point.
+     */
+    public void extend(LatLon ll) {
+        if (ll.lat() < min.lat() || ll.lon() < min.lon())
+            min = new LatLon(Math.min(ll.lat(), min.lat()), Math.min(ll.lon(), min.lon()));
+        if (ll.lat() > max.lat() || ll.lon() > max.lon())
+            max = new LatLon(Math.max(ll.lat(), max.lat()), Math.max(ll.lon(), max.lon()));
+    }
+    /**
+     * Is the given point within this bounds?
+     */
+    public boolean contains(LatLon ll) {
+        if (ll.lat() < min.lat() || ll.lon() < min.lon())
+            return false;
+        if (ll.lat() > max.lat() || ll.lon() > max.lon())
+            return false;
+        return true;
+    }
+
+    /**
+     * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
+     * @return the bounding box to Rectangle2D.Double
+     */
+    public Rectangle2D.Double asRect() {
+        return new Rectangle2D.Double(min.lon(), min.lat(), max.lon()-min.lon(), max.lat()-min.lat());
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/data/DataSetChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/DataSetChecker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/DataSetChecker.java	(revision 1169)
@@ -14,30 +14,30 @@
 public class DataSetChecker {
 
-	public static void check() {
-		if (Main.map == null)
-			return;
+    public static void check() {
+        if (Main.map == null)
+            return;
 
-		Set<OsmPrimitive> s = new HashSet<OsmPrimitive>();
-		for (Layer l : Main.map.mapView.getAllLayers()) {
-			if (l instanceof OsmDataLayer) {
-				for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) {
-					if (s.contains(osm)) {
-		                JOptionPane.showMessageDialog(Main.parent, "cross references");
-		                return;
-					}
-					s.add(osm);
-				}
-			}
-		}
-		
-		if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-			OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-			if (l.data != Main.ds) {
-				JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch");
-				return;
-			}
-		}
+        Set<OsmPrimitive> s = new HashSet<OsmPrimitive>();
+        for (Layer l : Main.map.mapView.getAllLayers()) {
+            if (l instanceof OsmDataLayer) {
+                for (OsmPrimitive osm : ((OsmDataLayer)l).data.allPrimitives()) {
+                    if (s.contains(osm)) {
+                        JOptionPane.showMessageDialog(Main.parent, "cross references");
+                        return;
+                    }
+                    s.add(osm);
+                }
+            }
+        }
 
-		JOptionPane.showMessageDialog(Main.parent, "working");
-	}
+        if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
+            OsmDataLayer l = (OsmDataLayer)Main.map.mapView.getActiveLayer();
+            if (l.data != Main.ds) {
+                JOptionPane.showMessageDialog(Main.parent, "Main.ds / active layer mismatch");
+                return;
+            }
+        }
+
+        JOptionPane.showMessageDialog(Main.parent, "working");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 1169)
@@ -35,61 +35,61 @@
  */
 public class Preferences {
-    
-    /**
-    * Internal storage for the preferenced directory. 
+
+    /**
+    * Internal storage for the preferenced directory.
     * Do not access this variable directly!
     * @see #getPreferencesDirFile()
     */
     private File preferencesDirFile = null;
-     
-	public static interface PreferenceChangedListener {
-		void preferenceChanged(String key, String newValue);
-	}
-
-	/**
-	 * Class holding one bookmarkentry.
-	 * @author imi
-	 */
-	public static class Bookmark implements Comparable<Bookmark> {
-		public String name;
-		public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon
-		@Override public String toString() {
-			return name;
-		}
-		public int compareTo(Bookmark b) {
-			return name.toLowerCase().compareTo(b.name.toLowerCase());
-		}
-	}
-
-	public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>();
-
-	/**
-	 * Map the property name to the property object.
-	 */
-	protected final SortedMap<String, String> properties = new TreeMap<String, String>();
-	protected final SortedMap<String, String> defaults = new TreeMap<String, String>();
-
-	/**
-	 * Override some values on read. This is intended to be used for technology previews
-	 * where we want to temporarily modify things without changing the user's preferences
-	 * file.
-	 */
-	protected static final SortedMap<String, String> override = new TreeMap<String, String>();
-	static {
-		//override.put("osm-server.version", "0.5");
-		//override.put("osm-server.additional-versions", "");
-		//override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
-		//override.put("plugins", null);
-	}
-
-	/**
-	 * Return the location of the user defined preferences file
-	 */
-	public String getPreferencesDir() {
-		final String path = getPreferencesDirFile().getPath();
-		if (path.endsWith(File.separator))
-			return path;
-		return path + File.separator;
-	}
+
+    public static interface PreferenceChangedListener {
+        void preferenceChanged(String key, String newValue);
+    }
+
+    /**
+     * Class holding one bookmarkentry.
+     * @author imi
+     */
+    public static class Bookmark implements Comparable<Bookmark> {
+        public String name;
+        public double[] latlon = new double[4]; // minlat, minlon, maxlat, maxlon
+        @Override public String toString() {
+            return name;
+        }
+        public int compareTo(Bookmark b) {
+            return name.toLowerCase().compareTo(b.name.toLowerCase());
+        }
+    }
+
+    public final ArrayList<PreferenceChangedListener> listener = new ArrayList<PreferenceChangedListener>();
+
+    /**
+     * Map the property name to the property object.
+     */
+    protected final SortedMap<String, String> properties = new TreeMap<String, String>();
+    protected final SortedMap<String, String> defaults = new TreeMap<String, String>();
+
+    /**
+     * Override some values on read. This is intended to be used for technology previews
+     * where we want to temporarily modify things without changing the user's preferences
+     * file.
+     */
+    protected static final SortedMap<String, String> override = new TreeMap<String, String>();
+    static {
+        //override.put("osm-server.version", "0.5");
+        //override.put("osm-server.additional-versions", "");
+        //override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
+        //override.put("plugins", null);
+    }
+
+    /**
+     * Return the location of the user defined preferences file
+     */
+    public String getPreferencesDir() {
+        final String path = getPreferencesDirFile().getPath();
+        if (path.endsWith(File.separator))
+            return path;
+        return path + File.separator;
+    }
 
     public File getPreferencesDirFile() {
@@ -110,371 +110,371 @@
         return preferencesDirFile;
     }
-    
-	public File getPluginsDirFile() {
-		return new File(getPreferencesDirFile(), "plugins");
-	}
-
-	/**
-	 * @return A list of all existing directories where resources could be stored.
-	 */
-	public Collection<String> getAllPossiblePreferenceDirs() {
-		LinkedList<String> locations = new LinkedList<String>();
-		locations.add(Main.pref.getPreferencesDir());
-		String s;
-		if ((s = System.getenv("JOSM_RESOURCES")) != null) {
-			if (!s.endsWith(File.separator))
-				s = s + File.separator;
-			locations.add(s);
-		}
-		if ((s = System.getProperty("josm.resources")) != null) {
-			if (!s.endsWith(File.separator))
-				s = s + File.separator;
-			locations.add(s);
-		}
-		String appdata = System.getenv("APPDATA");
-		if (System.getenv("ALLUSERSPROFILE") != null && appdata != null
-		        && appdata.lastIndexOf(File.separator) != -1) {
-			appdata = appdata.substring(appdata.lastIndexOf(File.separator));
-			locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"),
-			        appdata), "JOSM").getPath());
-		}
-		locations.add("/usr/local/share/josm/");
-		locations.add("/usr/local/lib/josm/");
-		locations.add("/usr/share/josm/");
-		locations.add("/usr/lib/josm/");
-		return locations;
-	}
-
-	synchronized public boolean hasKey(final String key) {
-		return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
-	}
-
-	synchronized public String get(final String key) {
-		putDefault(key, null);
-		if (override.containsKey(key))
-			return override.get(key);
-		if (!properties.containsKey(key))
-			return "";
-		return properties.get(key);
-	}
-
-	synchronized public String get(final String key, final String def) {
-		putDefault(key, def);
-		if (override.containsKey(key))
-			return override.get(key);
-		final String prop = properties.get(key);
-		if (prop == null || prop.equals(""))
-			return def;
-		return prop;
-	}
-
-	synchronized public Map<String, String> getAllPrefix(final String prefix) {
-		final Map<String,String> all = new TreeMap<String,String>();
-		for (final Entry<String,String> e : properties.entrySet())
-			if (e.getKey().startsWith(prefix))
-				all.put(e.getKey(), e.getValue());
-		for (final Entry<String,String> e : override.entrySet())
-			if (e.getKey().startsWith(prefix))
-				if (e.getValue() == null)
-					all.remove(e.getKey());
-				else
-					all.put(e.getKey(), e.getValue());
-		return all;
-	}
-
-	synchronized public Map<String, String> getDefaults() {
-		return defaults;
-	}
-
-	synchronized public void putDefault(final String key, final String def) {
-		if(!defaults.containsKey(key) || defaults.get(key) == null)
-			defaults.put(key, def);
-		else if(def != null && !defaults.get(key).equals(def))
-			System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key));
-	}
-
-	synchronized public boolean getBoolean(final String key) {
-		putDefault(key, null);
-		if (override.containsKey(key))
-			return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key));
-		return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
-	}
-
-	synchronized public boolean getBoolean(final String key, final boolean def) {
-		putDefault(key, Boolean.toString(def));
-		if (override.containsKey(key))
-			return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
-		return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
-	}
-
-	synchronized public void put(final String key, String value) {
-		String oldvalue = properties.get(key);
-		if(value != null && value.length() == 0)
-			value = null;
-		if(!((oldvalue == null && value == null) || (value != null
-		&& oldvalue != null && oldvalue.equals(value))))
-		{
-			if (value == null)
-				properties.remove(key);
-			else
-				properties.put(key, value);
-			save();
-			firePreferenceChanged(key, value);
-		}
-	}
-
-	synchronized public void put(final String key, final boolean value) {
-		put(key, Boolean.toString(value));
-	}
-
-	private final void firePreferenceChanged(final String key, final String value) {
-		for (final PreferenceChangedListener l : listener)
-			l.preferenceChanged(key, value);
-	}
-
-	/**
-	 * Called after every put. In case of a problem, do nothing but output the error
-	 * in log.
-	 */
-	public void save() {
-		try {
-			setSystemProperties();
-			final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false);
-			for (final Entry<String, String> e : properties.entrySet()) {
-				out.println(e.getKey() + "=" + e.getValue());
-			}
-			out.close();
-		} catch (final IOException e) {
-			e.printStackTrace();
-			// do not message anything, since this can be called from strange
-			// places.
-		}
-	}
-
-	public void load() throws IOException {
-		properties.clear();
-		final BufferedReader in = new BufferedReader(new FileReader(getPreferencesDir()+"preferences"));
-		int lineNumber = 0;
-		ArrayList<Integer> errLines = new ArrayList<Integer>();
-		for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) {
-			final int i = line.indexOf('=');
-			if (i == -1 || i == 0) {
-				errLines.add(lineNumber);
-				continue;
-			}
-			properties.put(line.substring(0,i), line.substring(i+1));
-		}
-		if (!errLines.isEmpty()) {
-			throw new IOException("Malformed config file at lines " + errLines);
-		}
-		setSystemProperties();
-	}
-
-	public final void resetToDefault() {
-		properties.clear();
-		properties.put("projection", "org.openstreetmap.josm.data.projection.Epsg4326");
-		properties.put("draw.segment.direction", "true");
-		properties.put("draw.wireframe", "false");
-		properties.put("layerlist.visible", "true");
-		properties.put("propertiesdialog.visible", "true");
-		properties.put("selectionlist.visible", "true");
-		properties.put("commandstack.visible", "true");
-		properties.put("osm-server.url", "http://www.openstreetmap.org/api");
-		if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
-			properties.put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
-		} else {
-			properties.put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
-		}
-		save();
-	}
-
-	public Collection<Bookmark> loadBookmarks() throws IOException {
-		File bookmarkFile = new File(getPreferencesDir()+"bookmarks");
-		if (!bookmarkFile.exists())
-			bookmarkFile.createNewFile();
-		BufferedReader in = new BufferedReader(new FileReader(bookmarkFile));
-
-		LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
-		// use pattern matches to scan text, as text may contain a "," itself
-		for (String line = in.readLine(); line != null; line = in.readLine()) {
-			Matcher m = Pattern.compile("^(.+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+)$").matcher(line);
-			if(m.matches())
-			{
-				Bookmark b = new Bookmark();
-				b.name = m.group(1);
-				for (int i = 0; i < b.latlon.length; ++i)
-					b.latlon[i] = Double.parseDouble(m.group(i+2));
-				bookmarks.add(b);
-			}
-		}
-		in.close();
-		Collections.sort(bookmarks);
-		return bookmarks;
-	}
-
-	public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException {
-		File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks");
-		if (!bookmarkFile.exists())
-			bookmarkFile.createNewFile();
-		PrintWriter out = new PrintWriter(new FileWriter(bookmarkFile));
-		for (Bookmark b : bookmarks) {
-			out.print(b.name+",");
-			for (int i = 0; i < b.latlon.length; ++i)
-				out.print(b.latlon[i]+(i<b.latlon.length-1?",":""));
-			out.println();
-		}
-		out.close();
-	}
-
-	/**
-	 * Convenience method for accessing colour preferences.
-	 *
-	 * @param colName name of the colour
-	 * @param def default value
-	 * @return a Color object for the configured colour, or the default value if none configured.
-	 */
-	synchronized public Color getColor(String colName, Color def) {
-		String colStr = get("color."+colName);
-		if (colStr.equals("")) {
-			put("color."+colName, ColorHelper.color2html(def));
-			return def;
-		}
-		return ColorHelper.html2color(colStr);
-	}
-
-	// only for compatibility. Don't use any more.
-	@Deprecated
-	public static Color getPreferencesColor(String colName, Color def)
-	{
-		return Main.pref.getColor(colName, def);
-	}
-
-	/**
-	 * Convenience method for accessing colour preferences.
-	 *
-	 * @param colName name of the colour
-	 * @param specName name of the special colour settings
-	 * @param def default value
-	 * @return a Color object for the configured colour, or the default value if none configured.
-	 */
-	synchronized public Color getColor(String colName, String specName, Color def) {
-		String colStr = get("color."+specName);
-		if(colStr.equals(""))
-		{
-			colStr = get("color."+colName);
-			if (colStr.equals("")) {
-				put("color."+colName, ColorHelper.color2html(def));
-				return def;
-			}
-		}
-		putDefault("color."+colName, ColorHelper.color2html(def));
-		return ColorHelper.html2color(colStr);
-	}
-
-	synchronized public void putColor(String colName, Color val) {
-		put("color."+colName, val != null ? ColorHelper.color2html(val) : null);
-	}
-
-	synchronized public int getInteger(String key, int def) {
-		putDefault(key, Integer.toString(def));
-		String v = get(key);
-		if(null == v)
-			return def;
-
-		try {
-			return Integer.parseInt(v);
-		} catch(NumberFormatException e) {
-			// fall out
-		}
-		return def;
-	}
-
-	synchronized public long getLong(String key, long def) {
-		putDefault(key, Long.toString(def));
-		String v = get(key);
-		if(null == v)
-			return def;
-
-		try {
-			return Long.parseLong(v);
-		} catch(NumberFormatException e) {
-			// fall out
-		}
-		return def;
-	}
-
-	synchronized public double getDouble(String key, double def) {
-		putDefault(key, Double.toString(def));
-		String v = get(key);
-		if(null == v)
-			return def;
-
-		try {
-			return Double.parseDouble(v);
-		} catch(NumberFormatException e) {
-			// fall out
-		}
-		return def;
-	}
-
-	synchronized public Collection<String> getCollection(String key, Collection<String> def) {
-		String s = get(key);
-		if(s != null && s.length() != 0)
-		{
-			/* handle old comma separated stuff - remove in future */
-			if(s.indexOf(',') >= 0)
-				return Arrays.asList(s.split(","));
-			/* handle space separated stuff - remove in future */
-			else if(s.indexOf(' ') >= 0)
-				return Arrays.asList(s.split(","));
-			else
-				return Arrays.asList(s.split(";"));
-		}
-		else if(def != null)
-			return def;
-		return null;
-	}
-	synchronized public void removeFromCollection(String key, String value) {
-		ArrayList<String> a = new ArrayList<String>(getCollection(key, null));
-		if(a != null)
-		{
-			a.remove(value);
-			putCollection(key, a);
-		}
-	}
-	synchronized public void putCollection(String key, Collection<String> val) {
-		String s = null;
-		if(val != null)
-		{
-			for(String a : val)
-			{
-				if(s != null)
-					s += ";" + a;
-				else
-					s = a;
-			}
-		}
-
-		put(key, s);
-	}
-
-	private void setSystemProperties() {
-		Properties sysProp = System.getProperties();
-		if (getBoolean(ProxyPreferences.PROXY_ENABLE)) {
-			sysProp.put("proxySet", "true");
-			sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST));
-			sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT));
-			if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) {
-				sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER));
-				sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS));
-			}
-		}/* else {
-			sysProp.put("proxySet", "false");
-			sysProp.remove("http.proxyHost");
-			sysProp.remove("proxyPort");
-			sysProp.remove("proxyUser");
-			sysProp.remove("proxyPassword");
-		}*/
-		System.setProperties(sysProp);
-	}
+
+    public File getPluginsDirFile() {
+        return new File(getPreferencesDirFile(), "plugins");
+    }
+
+    /**
+     * @return A list of all existing directories where resources could be stored.
+     */
+    public Collection<String> getAllPossiblePreferenceDirs() {
+        LinkedList<String> locations = new LinkedList<String>();
+        locations.add(Main.pref.getPreferencesDir());
+        String s;
+        if ((s = System.getenv("JOSM_RESOURCES")) != null) {
+            if (!s.endsWith(File.separator))
+                s = s + File.separator;
+            locations.add(s);
+        }
+        if ((s = System.getProperty("josm.resources")) != null) {
+            if (!s.endsWith(File.separator))
+                s = s + File.separator;
+            locations.add(s);
+        }
+        String appdata = System.getenv("APPDATA");
+        if (System.getenv("ALLUSERSPROFILE") != null && appdata != null
+                && appdata.lastIndexOf(File.separator) != -1) {
+            appdata = appdata.substring(appdata.lastIndexOf(File.separator));
+            locations.add(new File(new File(System.getenv("ALLUSERSPROFILE"),
+                    appdata), "JOSM").getPath());
+        }
+        locations.add("/usr/local/share/josm/");
+        locations.add("/usr/local/lib/josm/");
+        locations.add("/usr/share/josm/");
+        locations.add("/usr/lib/josm/");
+        return locations;
+    }
+
+    synchronized public boolean hasKey(final String key) {
+        return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
+    }
+
+    synchronized public String get(final String key) {
+        putDefault(key, null);
+        if (override.containsKey(key))
+            return override.get(key);
+        if (!properties.containsKey(key))
+            return "";
+        return properties.get(key);
+    }
+
+    synchronized public String get(final String key, final String def) {
+        putDefault(key, def);
+        if (override.containsKey(key))
+            return override.get(key);
+        final String prop = properties.get(key);
+        if (prop == null || prop.equals(""))
+            return def;
+        return prop;
+    }
+
+    synchronized public Map<String, String> getAllPrefix(final String prefix) {
+        final Map<String,String> all = new TreeMap<String,String>();
+        for (final Entry<String,String> e : properties.entrySet())
+            if (e.getKey().startsWith(prefix))
+                all.put(e.getKey(), e.getValue());
+        for (final Entry<String,String> e : override.entrySet())
+            if (e.getKey().startsWith(prefix))
+                if (e.getValue() == null)
+                    all.remove(e.getKey());
+                else
+                    all.put(e.getKey(), e.getValue());
+        return all;
+    }
+
+    synchronized public Map<String, String> getDefaults() {
+        return defaults;
+    }
+
+    synchronized public void putDefault(final String key, final String def) {
+        if(!defaults.containsKey(key) || defaults.get(key) == null)
+            defaults.put(key, def);
+        else if(def != null && !defaults.get(key).equals(def))
+            System.out.println("Defaults for " + key + " differ: " + def + " != " + defaults.get(key));
+    }
+
+    synchronized public boolean getBoolean(final String key) {
+        putDefault(key, null);
+        if (override.containsKey(key))
+            return override.get(key) == null ? false : Boolean.parseBoolean(override.get(key));
+        return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : false;
+    }
+
+    synchronized public boolean getBoolean(final String key, final boolean def) {
+        putDefault(key, Boolean.toString(def));
+        if (override.containsKey(key))
+            return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
+        return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
+    }
+
+    synchronized public void put(final String key, String value) {
+        String oldvalue = properties.get(key);
+        if(value != null && value.length() == 0)
+            value = null;
+        if(!((oldvalue == null && value == null) || (value != null
+        && oldvalue != null && oldvalue.equals(value))))
+        {
+            if (value == null)
+                properties.remove(key);
+            else
+                properties.put(key, value);
+            save();
+            firePreferenceChanged(key, value);
+        }
+    }
+
+    synchronized public void put(final String key, final boolean value) {
+        put(key, Boolean.toString(value));
+    }
+
+    private final void firePreferenceChanged(final String key, final String value) {
+        for (final PreferenceChangedListener l : listener)
+            l.preferenceChanged(key, value);
+    }
+
+    /**
+     * Called after every put. In case of a problem, do nothing but output the error
+     * in log.
+     */
+    public void save() {
+        try {
+            setSystemProperties();
+            final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false);
+            for (final Entry<String, String> e : properties.entrySet()) {
+                out.println(e.getKey() + "=" + e.getValue());
+            }
+            out.close();
+        } catch (final IOException e) {
+            e.printStackTrace();
+            // do not message anything, since this can be called from strange
+            // places.
+        }
+    }
+
+    public void load() throws IOException {
+        properties.clear();
+        final BufferedReader in = new BufferedReader(new FileReader(getPreferencesDir()+"preferences"));
+        int lineNumber = 0;
+        ArrayList<Integer> errLines = new ArrayList<Integer>();
+        for (String line = in.readLine(); line != null; line = in.readLine(), lineNumber++) {
+            final int i = line.indexOf('=');
+            if (i == -1 || i == 0) {
+                errLines.add(lineNumber);
+                continue;
+            }
+            properties.put(line.substring(0,i), line.substring(i+1));
+        }
+        if (!errLines.isEmpty()) {
+            throw new IOException("Malformed config file at lines " + errLines);
+        }
+        setSystemProperties();
+    }
+
+    public final void resetToDefault() {
+        properties.clear();
+        properties.put("projection", "org.openstreetmap.josm.data.projection.Epsg4326");
+        properties.put("draw.segment.direction", "true");
+        properties.put("draw.wireframe", "false");
+        properties.put("layerlist.visible", "true");
+        properties.put("propertiesdialog.visible", "true");
+        properties.put("selectionlist.visible", "true");
+        properties.put("commandstack.visible", "true");
+        properties.put("osm-server.url", "http://www.openstreetmap.org/api");
+        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
+            properties.put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
+        } else {
+            properties.put("laf", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+        }
+        save();
+    }
+
+    public Collection<Bookmark> loadBookmarks() throws IOException {
+        File bookmarkFile = new File(getPreferencesDir()+"bookmarks");
+        if (!bookmarkFile.exists())
+            bookmarkFile.createNewFile();
+        BufferedReader in = new BufferedReader(new FileReader(bookmarkFile));
+
+        LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
+        // use pattern matches to scan text, as text may contain a "," itself
+        for (String line = in.readLine(); line != null; line = in.readLine()) {
+            Matcher m = Pattern.compile("^(.+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+),(-?\\d+.\\d+)$").matcher(line);
+            if(m.matches())
+            {
+                Bookmark b = new Bookmark();
+                b.name = m.group(1);
+                for (int i = 0; i < b.latlon.length; ++i)
+                    b.latlon[i] = Double.parseDouble(m.group(i+2));
+                bookmarks.add(b);
+            }
+        }
+        in.close();
+        Collections.sort(bookmarks);
+        return bookmarks;
+    }
+
+    public void saveBookmarks(Collection<Bookmark> bookmarks) throws IOException {
+        File bookmarkFile = new File(Main.pref.getPreferencesDir()+"bookmarks");
+        if (!bookmarkFile.exists())
+            bookmarkFile.createNewFile();
+        PrintWriter out = new PrintWriter(new FileWriter(bookmarkFile));
+        for (Bookmark b : bookmarks) {
+            out.print(b.name+",");
+            for (int i = 0; i < b.latlon.length; ++i)
+                out.print(b.latlon[i]+(i<b.latlon.length-1?",":""));
+            out.println();
+        }
+        out.close();
+    }
+
+    /**
+     * Convenience method for accessing colour preferences.
+     *
+     * @param colName name of the colour
+     * @param def default value
+     * @return a Color object for the configured colour, or the default value if none configured.
+     */
+    synchronized public Color getColor(String colName, Color def) {
+        String colStr = get("color."+colName);
+        if (colStr.equals("")) {
+            put("color."+colName, ColorHelper.color2html(def));
+            return def;
+        }
+        return ColorHelper.html2color(colStr);
+    }
+
+    // only for compatibility. Don't use any more.
+    @Deprecated
+    public static Color getPreferencesColor(String colName, Color def)
+    {
+        return Main.pref.getColor(colName, def);
+    }
+
+    /**
+     * Convenience method for accessing colour preferences.
+     *
+     * @param colName name of the colour
+     * @param specName name of the special colour settings
+     * @param def default value
+     * @return a Color object for the configured colour, or the default value if none configured.
+     */
+    synchronized public Color getColor(String colName, String specName, Color def) {
+        String colStr = get("color."+specName);
+        if(colStr.equals(""))
+        {
+            colStr = get("color."+colName);
+            if (colStr.equals("")) {
+                put("color."+colName, ColorHelper.color2html(def));
+                return def;
+            }
+        }
+        putDefault("color."+colName, ColorHelper.color2html(def));
+        return ColorHelper.html2color(colStr);
+    }
+
+    synchronized public void putColor(String colName, Color val) {
+        put("color."+colName, val != null ? ColorHelper.color2html(val) : null);
+    }
+
+    synchronized public int getInteger(String key, int def) {
+        putDefault(key, Integer.toString(def));
+        String v = get(key);
+        if(null == v)
+            return def;
+
+        try {
+            return Integer.parseInt(v);
+        } catch(NumberFormatException e) {
+            // fall out
+        }
+        return def;
+    }
+
+    synchronized public long getLong(String key, long def) {
+        putDefault(key, Long.toString(def));
+        String v = get(key);
+        if(null == v)
+            return def;
+
+        try {
+            return Long.parseLong(v);
+        } catch(NumberFormatException e) {
+            // fall out
+        }
+        return def;
+    }
+
+    synchronized public double getDouble(String key, double def) {
+        putDefault(key, Double.toString(def));
+        String v = get(key);
+        if(null == v)
+            return def;
+
+        try {
+            return Double.parseDouble(v);
+        } catch(NumberFormatException e) {
+            // fall out
+        }
+        return def;
+    }
+
+    synchronized public Collection<String> getCollection(String key, Collection<String> def) {
+        String s = get(key);
+        if(s != null && s.length() != 0)
+        {
+            /* handle old comma separated stuff - remove in future */
+            if(s.indexOf(',') >= 0)
+                return Arrays.asList(s.split(","));
+            /* handle space separated stuff - remove in future */
+            else if(s.indexOf(' ') >= 0)
+                return Arrays.asList(s.split(","));
+            else
+                return Arrays.asList(s.split(";"));
+        }
+        else if(def != null)
+            return def;
+        return null;
+    }
+    synchronized public void removeFromCollection(String key, String value) {
+        ArrayList<String> a = new ArrayList<String>(getCollection(key, null));
+        if(a != null)
+        {
+            a.remove(value);
+            putCollection(key, a);
+        }
+    }
+    synchronized public void putCollection(String key, Collection<String> val) {
+        String s = null;
+        if(val != null)
+        {
+            for(String a : val)
+            {
+                if(s != null)
+                    s += ";" + a;
+                else
+                    s = a;
+            }
+        }
+
+        put(key, s);
+    }
+
+    private void setSystemProperties() {
+        Properties sysProp = System.getProperties();
+        if (getBoolean(ProxyPreferences.PROXY_ENABLE)) {
+            sysProp.put("proxySet", "true");
+            sysProp.put("http.proxyHost", get(ProxyPreferences.PROXY_HOST));
+            sysProp.put("proxyPort", get(ProxyPreferences.PROXY_PORT));
+            if (!getBoolean(ProxyPreferences.PROXY_ANONYMOUS)) {
+                sysProp.put("proxyUser", get(ProxyPreferences.PROXY_USER));
+                sysProp.put("proxyPassword", get(ProxyPreferences.PROXY_PASS));
+            }
+        }/* else {
+            sysProp.put("proxySet", "false");
+            sysProp.remove("http.proxyHost");
+            sysProp.remove("proxyPort");
+            sysProp.remove("proxyUser");
+            sysProp.remove("proxyPassword");
+        }*/
+        System.setProperties(sysProp);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/SelectionChangedListener.java	(revision 1169)
@@ -10,17 +10,17 @@
  * a selection of any data member changes, the dataSet gets informed about this
  * and fires a selectionChanged event.
- * 
+ *
  * Note that these events are not fired immediately but are inserted in the
  * Swing event queue and packed together. So only one selection changed event
  * is issued within a one message dispatch routine.
- * 
+ *
  * @author imi
  */
 public interface SelectionChangedListener {
 
-	/**
-	 * Informs the listener that the selection in the dataset has changed.
-	 * @param newSelection The new selection.
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection);
+    /**
+     * Informs the listener that the selection in the dataset has changed.
+     * @param newSelection The new selection.
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection);
 }
Index: trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/ServerSidePreferences.java	(revision 1169)
@@ -32,160 +32,160 @@
  * This class tweak the Preferences class to provide server side preference settings, as example
  * used in the applet version.
- * 
+ *
  * @author Imi
  */
 public class ServerSidePreferences extends Preferences {
 
-	private final Connection connection;
+    private final Connection connection;
 
-	private class Connection extends OsmConnection {
-		URL serverUrl;
-		public Connection(URL serverUrl) {
-			this.serverUrl = serverUrl;
-		}
-		public String download() {
-			try {
-				System.out.println("reading preferences from "+serverUrl);
-				URLConnection con = serverUrl.openConnection();
-				if (con instanceof HttpURLConnection) addAuth((HttpURLConnection) con);
-				con.connect();
-				BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
-				StringBuilder b = new StringBuilder();
-				for (String line = reader.readLine(); line != null; line = reader.readLine()) {
-					b.append(line);
-					b.append("\n");
-				}
-				if (con instanceof HttpURLConnection) ((HttpURLConnection) con).disconnect();
-				return b.toString();
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-			return null;
-		}
-		public void upload(String s) {
-			try {
-				URL u = new URL(getPreferencesDir());
-				System.out.println("uploading preferences to "+u);
-				HttpURLConnection con = (HttpURLConnection)u.openConnection();
-				con.addRequestProperty("Authorization", "Basic "+Base64.encode(get("osm-server.username")+":"+get("osm-server.password")));
-				con.setRequestMethod("POST");
-				con.setDoOutput(true);
-				con.connect();
-				PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
-				out.println(s);
-				out.close();
-				con.getInputStream().close();
-				con.disconnect();
-				JOptionPane.showMessageDialog(Main.parent, tr("Preferences stored on {0}", u.getHost()));
-			} catch (Exception e) {
-				e.printStackTrace();
-				JOptionPane.showMessageDialog(Main.parent, tr("Could not upload preferences. Reason: {0}", e.getMessage()));
-			}
-		}
-	}
+    private class Connection extends OsmConnection {
+        URL serverUrl;
+        public Connection(URL serverUrl) {
+            this.serverUrl = serverUrl;
+        }
+        public String download() {
+            try {
+                System.out.println("reading preferences from "+serverUrl);
+                URLConnection con = serverUrl.openConnection();
+                if (con instanceof HttpURLConnection) addAuth((HttpURLConnection) con);
+                con.connect();
+                BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
+                StringBuilder b = new StringBuilder();
+                for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+                    b.append(line);
+                    b.append("\n");
+                }
+                if (con instanceof HttpURLConnection) ((HttpURLConnection) con).disconnect();
+                return b.toString();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            return null;
+        }
+        public void upload(String s) {
+            try {
+                URL u = new URL(getPreferencesDir());
+                System.out.println("uploading preferences to "+u);
+                HttpURLConnection con = (HttpURLConnection)u.openConnection();
+                con.addRequestProperty("Authorization", "Basic "+Base64.encode(get("osm-server.username")+":"+get("osm-server.password")));
+                con.setRequestMethod("POST");
+                con.setDoOutput(true);
+                con.connect();
+                PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
+                out.println(s);
+                out.close();
+                con.getInputStream().close();
+                con.disconnect();
+                JOptionPane.showMessageDialog(Main.parent, tr("Preferences stored on {0}", u.getHost()));
+            } catch (Exception e) {
+                e.printStackTrace();
+                JOptionPane.showMessageDialog(Main.parent, tr("Could not upload preferences. Reason: {0}", e.getMessage()));
+            }
+        }
+    }
 
-	public ServerSidePreferences(URL serverUrl) {
-		Connection connection = null;
-		try {
-			connection = new Connection(new URL(serverUrl+"user/preferences"));
-		} catch (MalformedURLException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not load preferences from server."));
-		}
-		this.connection = connection;
-	}
+    public ServerSidePreferences(URL serverUrl) {
+        Connection connection = null;
+        try {
+            connection = new Connection(new URL(serverUrl+"user/preferences"));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not load preferences from server."));
+        }
+        this.connection = connection;
+    }
 
-	@Override public String getPreferencesDir() {
-		return connection.serverUrl.toString();
-	}
+    @Override public String getPreferencesDir() {
+        return connection.serverUrl.toString();
+    }
 
-	/**
-	 * Do nothing on load. Preferences are loaded with download().
-	 */
-	@Override public void load() {
-	}
+    /**
+     * Do nothing on load. Preferences are loaded with download().
+     */
+    @Override public void load() {
+    }
 
-	/**
-	 * Do nothing on save. Preferences are uploaded using upload().
-	 */
-	@Override public void save() {
-	}
+    /**
+     * Do nothing on save. Preferences are uploaded using upload().
+     */
+    @Override public void save() {
+    }
 
-	public static class Prop {
-		public String key;
-		public String value;
-	}
+    public static class Prop {
+        public String key;
+        public String value;
+    }
 
-	public void download(String userName, String password) {
-		resetToDefault();
-		if (!properties.containsKey("osm-server.username") && userName != null)
-			properties.put("osm-server.username", userName);
-		if (!properties.containsKey("osm-server.password") && password != null)
-			properties.put("osm-server.password", password);
-		String cont = connection.download();
-		if (cont == null) return;
-		Reader in = new StringReader(cont);
-		try {
-			XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class);
-			for (Prop p : parser)
-				properties.put(p.key, p.value);
-		} catch (RuntimeException e) {
-			e.printStackTrace();
-		}
-	}
+    public void download(String userName, String password) {
+        resetToDefault();
+        if (!properties.containsKey("osm-server.username") && userName != null)
+            properties.put("osm-server.username", userName);
+        if (!properties.containsKey("osm-server.password") && password != null)
+            properties.put("osm-server.password", password);
+        String cont = connection.download();
+        if (cont == null) return;
+        Reader in = new StringReader(cont);
+        try {
+            XmlObjectParser.Uniform<Prop> parser = new XmlObjectParser.Uniform<Prop>(in, "tag", Prop.class);
+            for (Prop p : parser)
+                properties.put(p.key, p.value);
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+        }
+    }
 
-	/**
-	 * Use this instead of save() for the ServerSidePreferences, since uploads
-	 * are costly while save is called often.
-	 * 
-	 * This is triggered by an explicit menu option.
-	 */
-	public void upload() {
-		StringBuilder b = new StringBuilder("<preferences>\n");
-		for (Entry<String, String> p : properties.entrySet()) {
-			if (p.getKey().equals("osm-server.password"))
-				continue; // do not upload password. It would get stored in plain!
-			b.append("<tag key='");
-			b.append(XmlWriter.encode(p.getKey()));
-			b.append("' value='");
-			b.append(XmlWriter.encode(p.getValue()));
-			b.append("' />\n");
-		}
-		b.append("</preferences>");
-		connection.upload(b.toString());
-	}
+    /**
+     * Use this instead of save() for the ServerSidePreferences, since uploads
+     * are costly while save is called often.
+     *
+     * This is triggered by an explicit menu option.
+     */
+    public void upload() {
+        StringBuilder b = new StringBuilder("<preferences>\n");
+        for (Entry<String, String> p : properties.entrySet()) {
+            if (p.getKey().equals("osm-server.password"))
+                continue; // do not upload password. It would get stored in plain!
+            b.append("<tag key='");
+            b.append(XmlWriter.encode(p.getKey()));
+            b.append("' value='");
+            b.append(XmlWriter.encode(p.getValue()));
+            b.append("' />\n");
+        }
+        b.append("</preferences>");
+        connection.upload(b.toString());
+    }
 
-	@Override public Collection<Bookmark> loadBookmarks() {
-		try {
-			Collection<Bookmark> bookmarks;
-			BufferedReader in = new BufferedReader(new InputStreamReader(new URL("http://"+connection.serverUrl.getHost()+"/josm/bookmarks").openStream()));
-			bookmarks = new LinkedList<Bookmark>();
-			for (String line = in.readLine(); line != null; line = in.readLine()) {
-				StringTokenizer st = new StringTokenizer(line, ",");
-				if (st.countTokens() < 5)
-					continue;
-				Bookmark b = new Bookmark();
-				b.name = st.nextToken();
-				try {
-					for (int i = 0; i < b.latlon.length; ++i)
-						b.latlon[i] = Double.parseDouble(st.nextToken());
-					bookmarks.add(b);
-				} catch (NumberFormatException x) {
-					// line not parsed
-				}
-			}
-			in.close();
-			return bookmarks;
-		} catch (MalformedURLException e) {
-			e.printStackTrace();
-		} catch (IllegalArgumentException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return Collections.emptyList();
-	}
+    @Override public Collection<Bookmark> loadBookmarks() {
+        try {
+            Collection<Bookmark> bookmarks;
+            BufferedReader in = new BufferedReader(new InputStreamReader(new URL("http://"+connection.serverUrl.getHost()+"/josm/bookmarks").openStream()));
+            bookmarks = new LinkedList<Bookmark>();
+            for (String line = in.readLine(); line != null; line = in.readLine()) {
+                StringTokenizer st = new StringTokenizer(line, ",");
+                if (st.countTokens() < 5)
+                    continue;
+                Bookmark b = new Bookmark();
+                b.name = st.nextToken();
+                try {
+                    for (int i = 0; i < b.latlon.length; ++i)
+                        b.latlon[i] = Double.parseDouble(st.nextToken());
+                    bookmarks.add(b);
+                } catch (NumberFormatException x) {
+                    // line not parsed
+                }
+            }
+            in.close();
+            return bookmarks;
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return Collections.emptyList();
+    }
 
-	@Override public void saveBookmarks(Collection<Bookmark> bookmarks) {
-	}
+    @Override public void saveBookmarks(Collection<Bookmark> bookmarks) {
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 1169)
@@ -15,102 +15,102 @@
 public class UndoRedoHandler implements LayerChangeListener {
 
-	/**
-	 * All commands that were made on the dataset. Don't write from outside!
-	 */
-	public final LinkedList<Command> commands = new LinkedList<Command>();
-	/**
-	 * The stack for redoing commands
-	 */
-	private final Stack<Command> redoCommands = new Stack<Command>();
+    /**
+     * All commands that were made on the dataset. Don't write from outside!
+     */
+    public final LinkedList<Command> commands = new LinkedList<Command>();
+    /**
+     * The stack for redoing commands
+     */
+    private final Stack<Command> redoCommands = new Stack<Command>();
 
-	public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
+    public final LinkedList<CommandQueueListener> listenerCommands = new LinkedList<CommandQueueListener>();
 
 
-	public UndoRedoHandler() {
-		Layer.listeners.add(this);
-	}
+    public UndoRedoHandler() {
+        Layer.listeners.add(this);
+    }
 
 
-	/**
-	 * Execute the command and add it to the intern command queue.
-	 */
-	public void add(final Command c) {
-		c.executeCommand();
-		commands.add(c);
-		redoCommands.clear();
-		if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-			OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-			data.setModified(true);
-			data.fireDataChange();
-		}
-		fireCommandsChanged();
-	}
+    /**
+     * Execute the command and add it to the intern command queue.
+     */
+    public void add(final Command c) {
+        c.executeCommand();
+        commands.add(c);
+        redoCommands.clear();
+        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
+            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
+            data.setModified(true);
+            data.fireDataChange();
+        }
+        fireCommandsChanged();
+    }
 
-	/**
-	 * Undoes the last added command.
-	 */
-	public void undo() {
-		if (commands.isEmpty())
-			return;
-		final Command c = commands.removeLast();
-		c.undoCommand();
-		redoCommands.push(c);
-		if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-			OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-			data.setModified(data.uploadedModified || !commands.isEmpty());
-			data.fireDataChange();
-		}		
-		fireCommandsChanged();
-		Main.ds.setSelected();
-	}
+    /**
+     * Undoes the last added command.
+     */
+    public void undo() {
+        if (commands.isEmpty())
+            return;
+        final Command c = commands.removeLast();
+        c.undoCommand();
+        redoCommands.push(c);
+        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
+            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
+            data.setModified(data.uploadedModified || !commands.isEmpty());
+            data.fireDataChange();
+        }
+        fireCommandsChanged();
+        Main.ds.setSelected();
+    }
 
-	/**
-	 * Redoes the last undoed command.
-	 * TODO: This has to be moved to a central place in order to support multiple layers.
-	 */
-	public void redo() {
-		if (redoCommands.isEmpty())
-			return;
-		final Command c = redoCommands.pop();
-		c.executeCommand();
-		commands.add(c);
-		if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-			OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-			data.setModified(true);
-			data.fireDataChange();
-		}
-		fireCommandsChanged();
-	}
+    /**
+     * Redoes the last undoed command.
+     * TODO: This has to be moved to a central place in order to support multiple layers.
+     */
+    public void redo() {
+        if (redoCommands.isEmpty())
+            return;
+        final Command c = redoCommands.pop();
+        c.executeCommand();
+        commands.add(c);
+        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
+            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
+            data.setModified(true);
+            data.fireDataChange();
+        }
+        fireCommandsChanged();
+    }
 
-	public void fireCommandsChanged() {
-		for (final CommandQueueListener l : listenerCommands)
-			l.commandChanged(commands.size(), redoCommands.size());
-	}
+    public void fireCommandsChanged() {
+        for (final CommandQueueListener l : listenerCommands)
+            l.commandChanged(commands.size(), redoCommands.size());
+    }
 
-	public void clean() {
-		redoCommands.clear();
-		commands.clear();
-		fireCommandsChanged();
-	}
+    public void clean() {
+        redoCommands.clear();
+        commands.clear();
+        fireCommandsChanged();
+    }
 
-	public void layerRemoved(Layer oldLayer) {
-		boolean changed = false;
-		for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
-			if (it.next().invalidBecauselayerRemoved(oldLayer)) {
-				it.remove();
-				changed = true;
-			}
-		}
-		for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
-			if (it.next().invalidBecauselayerRemoved(oldLayer)) {
-				it.remove();
-				changed = true;
-			}
-		}
-		if (changed)
-			fireCommandsChanged();
-	}
+    public void layerRemoved(Layer oldLayer) {
+        boolean changed = false;
+        for (Iterator<Command> it = commands.iterator(); it.hasNext();) {
+            if (it.next().invalidBecauselayerRemoved(oldLayer)) {
+                it.remove();
+                changed = true;
+            }
+        }
+        for (Iterator<Command> it = redoCommands.iterator(); it.hasNext();) {
+            if (it.next().invalidBecauselayerRemoved(oldLayer)) {
+                it.remove();
+                changed = true;
+            }
+        }
+        if (changed)
+            fireCommandsChanged();
+    }
 
-	public void layerAdded(Layer newLayer) {}
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
+    public void layerAdded(Layer newLayer) {}
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
 }
Index: trunk/src/org/openstreetmap/josm/data/conflict/ConflictItem.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/conflict/ConflictItem.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/conflict/ConflictItem.java	(revision 1169)
@@ -12,29 +12,29 @@
 public abstract class ConflictItem {
 
-	public String my, their;
-	public Resolution resolution = null;
+    public String my, their;
+    public Resolution resolution = null;
 
-	public final void initialize(Map<OsmPrimitive,OsmPrimitive> conflicts) {
-		my = collectStr(conflicts.keySet());
-		their = collectStr(conflicts.values());
-	}
+    public final void initialize(Map<OsmPrimitive,OsmPrimitive> conflicts) {
+        my = collectStr(conflicts.keySet());
+        their = collectStr(conflicts.values());
+    }
 
-	abstract public boolean hasConflict(OsmPrimitive key, OsmPrimitive value);
-	abstract protected String str(OsmPrimitive osm);
-	abstract public String key();
-	abstract public void apply(OsmPrimitive target, OsmPrimitive other);
+    abstract public boolean hasConflict(OsmPrimitive key, OsmPrimitive value);
+    abstract protected String str(OsmPrimitive osm);
+    abstract public String key();
+    abstract public void apply(OsmPrimitive target, OsmPrimitive other);
 
-	protected final String collectStr(Collection<OsmPrimitive> c) {
-		String value = null;
-		for (OsmPrimitive osm : c) {
-			String v = str(osm);
-			if (value == null)
-				value = v;
-			else if (!value.equals(v)) {
-				value = "<html><i>&lt;"+tr("different")+"&gt;</i></html>";
-				break;
-			}
-		}
-		return value == null ? "" : value;
-	}
+    protected final String collectStr(Collection<OsmPrimitive> c) {
+        String value = null;
+        for (OsmPrimitive osm : c) {
+            String v = str(osm);
+            if (value == null)
+                value = v;
+            else if (!value.equals(v)) {
+                value = "<html><i>&lt;"+tr("different")+"&gt;</i></html>";
+                break;
+            }
+        }
+        return value == null ? "" : value;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/conflict/DeleteConflict.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/conflict/DeleteConflict.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/conflict/DeleteConflict.java	(revision 1169)
@@ -8,18 +8,18 @@
 public class DeleteConflict extends ConflictItem {
 
-	@Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
-		return key.deleted != value.deleted;
-	}
+    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
+        return key.deleted != value.deleted;
+    }
 
-	@Override public String key() {
-		return "deleted|"+tr("deleted");
-	}
+    @Override public String key() {
+        return "deleted|"+tr("deleted");
+    }
 
-	@Override protected String str(OsmPrimitive osm) {
-		return osm.deleted ? tr("true") : tr("false");
-	}
+    @Override protected String str(OsmPrimitive osm) {
+        return osm.deleted ? tr("true") : tr("false");
+    }
 
-	@Override public void apply(OsmPrimitive target, OsmPrimitive other) {
-		target.deleted = other.deleted;
-	}
+    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
+        target.deleted = other.deleted;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/conflict/PositionConflict.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/conflict/PositionConflict.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/conflict/PositionConflict.java	(revision 1169)
@@ -8,22 +8,22 @@
 
 public class PositionConflict extends ConflictItem {
-	
-	@Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
-		return key instanceof Node && !((Node)key).coor.equals(((Node)value).coor);
-	}
-	
-	@Override protected String str(OsmPrimitive osm) {
-		return osm instanceof Node ? ((Node)osm).coor.lat()+", "+((Node)osm).coor.lon() : null;
-	}
-	
-	@Override public String key() {
-		return "node|"+tr("position");
-	}
-	
-	@Override public void apply(OsmPrimitive target, OsmPrimitive other) {
-		if (target instanceof Node) {
-			((Node)target).coor = ((Node)other).coor;
-			((Node)target).eastNorth = ((Node)other).eastNorth;
-		}
+
+    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
+        return key instanceof Node && !((Node)key).coor.equals(((Node)value).coor);
+    }
+
+    @Override protected String str(OsmPrimitive osm) {
+        return osm instanceof Node ? ((Node)osm).coor.lat()+", "+((Node)osm).coor.lon() : null;
+    }
+
+    @Override public String key() {
+        return "node|"+tr("position");
+    }
+
+    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
+        if (target instanceof Node) {
+            ((Node)target).coor = ((Node)other).coor;
+            ((Node)target).eastNorth = ((Node)other).eastNorth;
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/conflict/PropertyConflict.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/conflict/PropertyConflict.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/conflict/PropertyConflict.java	(revision 1169)
@@ -5,27 +5,27 @@
 
 public class PropertyConflict extends ConflictItem {
-	private String key;
-	
-	public PropertyConflict(String key) {
-		this.key = key;
-	}
-	
-	@Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
-		String k = key.get(this.key);
-		String v = value.get(this.key);
-		return k == null ? v!=null : !k.equals(v);
-	}
-	
-	@Override protected String str(OsmPrimitive osm) {
-		String v = osm.get(key);
-		return v == null ? "" : v;
-	}
-	
-	@Override public String key() {
-		return "key|"+key;
-	}
-	
-	@Override public void apply(OsmPrimitive target, OsmPrimitive other) {
-		target.put(key, other.get(key));
+    private String key;
+
+    public PropertyConflict(String key) {
+        this.key = key;
+    }
+
+    @Override public boolean hasConflict(OsmPrimitive key, OsmPrimitive value) {
+        String k = key.get(this.key);
+        String v = value.get(this.key);
+        return k == null ? v!=null : !k.equals(v);
+    }
+
+    @Override protected String str(OsmPrimitive osm) {
+        String v = osm.get(key);
+        return v == null ? "" : v;
+    }
+
+    @Override public String key() {
+        return "key|"+key;
+    }
+
+    @Override public void apply(OsmPrimitive target, OsmPrimitive other) {
+        target.put(key, other.get(key));
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 1169)
@@ -7,39 +7,39 @@
 /**
  * Base class of points of both coordinate systems.
- * 
- * The variables are default package protected to allow routines in the 
+ *
+ * The variables are default package protected to allow routines in the
  * data package to access them directly.
- * 
- * As the class itself is package protected too, it is not visible 
- * outside of the data package. Routines there should only use LatLon or 
+ *
+ * As the class itself is package protected too, it is not visible
+ * outside of the data package. Routines there should only use LatLon or
  * EastNorth.
  *
  * @author imi
- */ 
+ */
 abstract class Coordinate extends Point2D implements Serializable {
 
     protected double x;
     protected double y;
-    
-	/**
-	 * Construct the point with latitude / longitude values.
-	 * 
-	 * @param x X coordinate of the point.
-	 * @param y Y coordinate of the point.
-	 */
-	Coordinate(double x, double y) {
+
+    /**
+     * Construct the point with latitude / longitude values.
+     *
+     * @param x X coordinate of the point.
+     * @param y Y coordinate of the point.
+     */
+    Coordinate(double x, double y) {
         this.x = x; this.y = y;
-	}
-    
+    }
+
     public double getX() {
         return x;
     }
-    
+
     public double getY() {
-        return y; 
+        return y;
     }
-    
+
     public void setLocation (double x, double y) {
-        this.x = x; 
+        this.x = x;
         this.y = y;
     }
Index: trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 1169)
@@ -4,49 +4,49 @@
 /**
  * Northing, Easting of the projected coordinates.
- * 
+ *
  * This class is immutable.
- * 
+ *
  * @author Imi
  */
 public class EastNorth extends Coordinate {
 
-	public EastNorth(double east, double north) {
-		super(east,north);
-	}
-	
-	public double east() {
-		return x;
-	}
+    public EastNorth(double east, double north) {
+        super(east,north);
+    }
 
-	public double north() {
-		return y;
-	}
+    public double east() {
+        return x;
+    }
 
-	public EastNorth add(double dx, double dy) {
-		return new EastNorth(x+dx, y+dy);
-	}
-	
-	public EastNorth interpolate(EastNorth en2, double proportion) {
-		return new EastNorth(this.x + proportion * (en2.x - this.x),
+    public double north() {
+        return y;
+    }
+
+    public EastNorth add(double dx, double dy) {
+        return new EastNorth(x+dx, y+dy);
+    }
+
+    public EastNorth interpolate(EastNorth en2, double proportion) {
+        return new EastNorth(this.x + proportion * (en2.x - this.x),
             this.y + proportion * (en2.y - this.y));
-	}
-    
+    }
+
     /**
-     * Returns the heading, in radians, that you have to use to get from 
+     * Returns the heading, in radians, that you have to use to get from
      * this EastNorth to another. Heading is mapped into [0, 2pi)
-     * 
+     *
      * @param other the "destination" position
-     * @return heading 
+     * @return heading
      */
     public double heading(EastNorth other) {
         double hd = Math.atan2(other.east() - east(), other.north() - north());
         if(hd < 0) hd = 2 * Math.PI + hd;
-        return hd;       
+        return hd;
     }
-    
+
     public EastNorth sub(EastNorth en) {
         return new EastNorth(en.east() - east(), en.north() - north());
     }
-  
+
     /**
      * Returns an EastNorth representing the this EastNorth rotatedaround
@@ -54,5 +54,5 @@
      * @param pivot the center of the rotation
      * @param angle the angle of the rotation
-     * @return EastNorth rotated object 
+     * @return EastNorth rotated object
      */
     public EastNorth rotate(EastNorth pivot, double angle) {
@@ -65,8 +65,8 @@
         return new EastNorth(nx, ny);
     }
-	
-	@Override public String toString() {
-		return "EastNorth[e="+x+", n="+y+"]";
-	}
+
+    @Override public String toString() {
+        return "EastNorth[e="+x+", n="+y+"]";
+    }
 
     /**
Index: trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 1169)
@@ -13,7 +13,7 @@
 /**
  * LatLon are unprojected latitude / longitude coordinates.
- * 
+ *
  * This class is immutable.
- * 
+ *
  * @author Imi
  */
@@ -23,14 +23,14 @@
     private static DecimalFormat cDmsSecondFormatter = new DecimalFormat("00.0");
     private static DecimalFormat cDdFormatter = new DecimalFormat("###0.0000");
-    
-    /** 
-     * Possible ways to display coordinates 
-     */ 
-    public enum CoordinateFormat { 
-        DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}},  
-        DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}}; 
-    } 
-    
-    public static String dms(double pCoordinate) { 
+
+    /**
+     * Possible ways to display coordinates
+     */
+    public enum CoordinateFormat {
+        DECIMAL_DEGREES {public String toString() {return tr("Decimal Degrees");}},
+        DEGREES_MINUTES_SECONDS {public String toString() {return tr("Degrees Minutes Seconds");}};
+    }
+
+    public static String dms(double pCoordinate) {
 
         double tAbsCoord = Math.abs(pCoordinate);
@@ -40,7 +40,7 @@
         double tSeconds = (tTmpMinutes - tMinutes) * 60;
 
-        return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'" 
+        return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'"
             + cDmsSecondFormatter.format(tSeconds) + "\"";
-    } 
+    }
 
     public LatLon(double lat, double lon) {
@@ -51,5 +51,5 @@
         return y;
     }
-    
+
     public String latToString(CoordinateFormat d) {
         switch(d) {
@@ -59,9 +59,9 @@
         }
     }
-    
+
     public double lon() {
         return x;
     }
-    
+
     public String lonToString(CoordinateFormat d) {
         switch(d) {
@@ -71,6 +71,6 @@
         }
     }
-    
-  
+
+
 
     /**
@@ -86,63 +86,63 @@
     /**
      * @return <code>true</code>, if the coordinate is outside the world, compared
-	 * by using lat/lon.
-	 */
-	public boolean isOutSideWorld() {
-		return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT || 
-			lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON;
-	}
+     * by using lat/lon.
+     */
+    public boolean isOutSideWorld() {
+        return lat() < -Projection.MAX_LAT || lat() > Projection.MAX_LAT ||
+            lon() < -Projection.MAX_LON || lon() > Projection.MAX_LON;
+    }
 
-	/**
-	 * @return <code>true</code> if this is within the given bounding box.
-	 */
-	public boolean isWithin(Bounds b) {
-		return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon();
-	}
-	
-	/**
-	 * Computes the distance between this lat/lon and another point on the earth.
-	 * Uses spherical law of cosines formula, not Haversine.
-	 * @param other the other point.
-	 * @return distance in metres.
-	 */
-	public double greatCircleDistance(LatLon other) {
-		return (Math.acos(
-			Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) + 
-		    Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) *
-		                  Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135);
-	}
-	
-	/**
-	 * Returns the heading, in radians, that you have to use to get from 
-	 * this lat/lon to another.
-	 * 
-	 * @param other the "destination" position
-	 * @return heading 
-	 */
-	public double heading(LatLon other) {
-		double rv;
-		if (other.lat() == lat()) {
-			rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
-		} else {
-			rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
-			if (rv < 0) rv += Math.PI;
-			if (other.lon() < lon()) rv += Math.PI;
-		}
-		return rv;
-	}
+    /**
+     * @return <code>true</code> if this is within the given bounding box.
+     */
+    public boolean isWithin(Bounds b) {
+        return lat() >= b.min.lat() && lat() <= b.max.lat() && lon() > b.min.lon() && lon() < b.max.lon();
+    }
 
-	/**
-	 * Returns this lat/lon pair in human-readable format.
-	 * 
-	 * @return String in the format "lat=1.23456°, lon=2.34567°"
-	 */
-	public String toDisplayString() {
-		NumberFormat nf = NumberFormat.getInstance();
-		nf.setMaximumFractionDigits(5);
-		return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°";
-	}
-	
-	@Override public String toString() {
-		return "LatLon[lat="+lat()+",lon="+lon()+"]";
+    /**
+     * Computes the distance between this lat/lon and another point on the earth.
+     * Uses spherical law of cosines formula, not Haversine.
+     * @param other the other point.
+     * @return distance in metres.
+     */
+    public double greatCircleDistance(LatLon other) {
+        return (Math.acos(
+            Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) +
+            Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) *
+                          Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135);
+    }
+
+    /**
+     * Returns the heading, in radians, that you have to use to get from
+     * this lat/lon to another.
+     *
+     * @param other the "destination" position
+     * @return heading
+     */
+    public double heading(LatLon other) {
+        double rv;
+        if (other.lat() == lat()) {
+            rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
+        } else {
+            rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
+            if (rv < 0) rv += Math.PI;
+            if (other.lon() < lon()) rv += Math.PI;
+        }
+        return rv;
+    }
+
+    /**
+     * Returns this lat/lon pair in human-readable format.
+     *
+     * @return String in the format "lat=1.23456°, lon=2.34567°"
+     */
+    public String toDisplayString() {
+        NumberFormat nf = NumberFormat.getInstance();
+        nf.setMaximumFractionDigits(5);
+        return "lat=" + nf.format(lat()) + "°, lon=" + nf.format(lon()) + "°";
+    }
+
+    @Override public String toString() {
+        return "LatLon[lat="+lat()+",lon="+lon()+"]";
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 1169)
@@ -15,91 +15,91 @@
  * It uses GPX v1.1, see {@link <a href="http://www.topografix.com/GPX/1/1/">the spec</a>}
  * for details.
- * 
+ *
  * @author Raphael Mack <ramack@raphael-mack.de>
  */
 public class GpxData extends WithAttributes {
-	public File storageFile;
-	public boolean fromServer;
+    public File storageFile;
+    public boolean fromServer;
 
-	public Collection<GpxTrack> tracks = new LinkedList<GpxTrack>();
-	public Collection<GpxRoute> routes = new LinkedList<GpxRoute>();
-	public Collection<WayPoint> waypoints = new LinkedList<WayPoint>();
+    public Collection<GpxTrack> tracks = new LinkedList<GpxTrack>();
+    public Collection<GpxRoute> routes = new LinkedList<GpxRoute>();
+    public Collection<WayPoint> waypoints = new LinkedList<WayPoint>();
 
-	public Bounds bounds;
+    public Bounds bounds;
 
-	public void mergeFrom(GpxData other) {
-		if (storageFile == null && other.storageFile != null) {
-			storageFile = other.storageFile;
-		}
-		fromServer = fromServer && other.fromServer;
+    public void mergeFrom(GpxData other) {
+        if (storageFile == null && other.storageFile != null) {
+            storageFile = other.storageFile;
+        }
+        fromServer = fromServer && other.fromServer;
 
-		for (Map.Entry<String, Object> ent : other.attr.entrySet()) {
-			// TODO: Detect conflicts.
-			String k = ent.getKey();
-			if (k.equals("link") && attr.containsKey("link")) {
-				((Collection<GpxLink>) attr.get("link")).addAll(
-					(Collection<GpxLink>) ent.getValue());
-			} else {
-				attr.put(k, ent.getValue());
-			}
-		}
-		tracks.addAll(other.tracks);
-		routes.addAll(other.routes);
-		waypoints.addAll(other.waypoints);
-	}
+        for (Map.Entry<String, Object> ent : other.attr.entrySet()) {
+            // TODO: Detect conflicts.
+            String k = ent.getKey();
+            if (k.equals("link") && attr.containsKey("link")) {
+                ((Collection<GpxLink>) attr.get("link")).addAll(
+                    (Collection<GpxLink>) ent.getValue());
+            } else {
+                attr.put(k, ent.getValue());
+            }
+        }
+        tracks.addAll(other.tracks);
+        routes.addAll(other.routes);
+        waypoints.addAll(other.waypoints);
+    }
 
-	public boolean hasTrackPoints() {
-		for (GpxTrack trk : tracks) {
-			for (Collection<WayPoint> trkseg : trk.trackSegs) {
-				if (!trkseg.isEmpty())
-					return true;
-			}
-		}
-		return false;
-	}
+    public boolean hasTrackPoints() {
+        for (GpxTrack trk : tracks) {
+            for (Collection<WayPoint> trkseg : trk.trackSegs) {
+                if (!trkseg.isEmpty())
+                    return true;
+            }
+        }
+        return false;
+    }
 
-	public boolean hasRoutePoints() {
-		for (GpxRoute rte : routes) {
-			if (!rte.routePoints.isEmpty())
-				return true;
-		}
-		return false;
-	}
+    public boolean hasRoutePoints() {
+        for (GpxRoute rte : routes) {
+            if (!rte.routePoints.isEmpty())
+                return true;
+        }
+        return false;
+    }
 
-	// FIXME might perhaps use visitor pattern?
-	public void recalculateBounds() {
-		bounds = null;
-		for (WayPoint wpt : waypoints) {
-			if (bounds == null) {
-				bounds = new Bounds(wpt.latlon, wpt.latlon);
-			} else {
-				bounds.extend(wpt.latlon);
-			}
-		}
-		for (GpxRoute rte : routes) {
-			for (WayPoint wpt : rte.routePoints) {
-				if (bounds == null) {
-					bounds = new Bounds(wpt.latlon, wpt.latlon);
-				} else {
-					bounds.extend(wpt.latlon);
-				}
-			}
-		}
-		for (GpxTrack trk : tracks) {
-			for (Collection<WayPoint> trkseg : trk.trackSegs) {
-				for (WayPoint wpt : trkseg) {
-					if (bounds == null) {
-						bounds = new Bounds(wpt.latlon, wpt.latlon);
-					} else {
-						bounds.extend(wpt.latlon);
-					}
-				}
-			}
-		}
-		if (bounds == null) {
-			bounds = new Bounds();
-		}
-	}
-    
+    // FIXME might perhaps use visitor pattern?
+    public void recalculateBounds() {
+        bounds = null;
+        for (WayPoint wpt : waypoints) {
+            if (bounds == null) {
+                bounds = new Bounds(wpt.latlon, wpt.latlon);
+            } else {
+                bounds.extend(wpt.latlon);
+            }
+        }
+        for (GpxRoute rte : routes) {
+            for (WayPoint wpt : rte.routePoints) {
+                if (bounds == null) {
+                    bounds = new Bounds(wpt.latlon, wpt.latlon);
+                } else {
+                    bounds.extend(wpt.latlon);
+                }
+            }
+        }
+        for (GpxTrack trk : tracks) {
+            for (Collection<WayPoint> trkseg : trk.trackSegs) {
+                for (WayPoint wpt : trkseg) {
+                    if (bounds == null) {
+                        bounds = new Bounds(wpt.latlon, wpt.latlon);
+                    } else {
+                        bounds.extend(wpt.latlon);
+                    }
+                }
+            }
+        }
+        if (bounds == null) {
+            bounds = new Bounds();
+        }
+    }
+
     /**
      * calculates the sum of the lengths of all track segments
@@ -108,5 +108,5 @@
         double result = 0.0; // in meters
         WayPoint last = null;
-		
+
         for (GpxTrack trk : tracks) {
             for (Collection<WayPoint> trkseg : trk.trackSegs) {
@@ -129,5 +129,5 @@
         double lat1, lon1, lat2, lon2;
         double dlon, dlat;
-	    
+
         lat1 = p1.lat() * Math.PI / 180.0;
         lon1 = p1.lon() * Math.PI / 180.0;
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxLink.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxLink.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxLink.java	(revision 1169)
@@ -5,10 +5,10 @@
 
 public class GpxLink {
-	public String uri;
-	public String text;
-	public String type;
+    public String uri;
+    public String text;
+    public String type;
 
-	public GpxLink(String uri) {
-		this.uri = uri;
-	}
+    public GpxLink(String uri) {
+        this.uri = uri;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxRoute.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxRoute.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxRoute.java	(revision 1169)
@@ -8,4 +8,4 @@
 
 public class GpxRoute extends WithAttributes {
-	public Collection<WayPoint> routePoints = new LinkedList<WayPoint>();
+    public Collection<WayPoint> routePoints = new LinkedList<WayPoint>();
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java	(revision 1169)
@@ -8,5 +8,5 @@
 
 public class GpxTrack extends WithAttributes {
-	public Collection<Collection<WayPoint>> trackSegs
-		= new LinkedList<Collection<WayPoint>>();
+    public Collection<Collection<WayPoint>> trackSegs
+        = new LinkedList<Collection<WayPoint>>();
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 1169)
@@ -15,65 +15,65 @@
 public class WayPoint extends WithAttributes implements Comparable<WayPoint>
 {
-	public final LatLon latlon;
-	public final EastNorth eastNorth;
-	public double time;
-	public Color speedLineColor;
-	public boolean drawLine;
-	public int dir;
+    public final LatLon latlon;
+    public final EastNorth eastNorth;
+    public double time;
+    public Color speedLineColor;
+    public boolean drawLine;
+    public int dir;
 
-	public WayPoint(LatLon ll) {
-		latlon = ll;
-		eastNorth = Main.proj.latlon2eastNorth(ll);
-	}
+    public WayPoint(LatLon ll) {
+        latlon = ll;
+        eastNorth = Main.proj.latlon2eastNorth(ll);
+    }
 
-	@Override
-	public String toString() {
-		return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")";
-	}
-	
-	/**
-	 * Convert the time stamp of the waypoint into seconds from the epoch
-	 */
-	public final static SimpleDateFormat GPXTIMEFMT = 
-		new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone
-	
-	public void setTime() {
-		if (! attr.containsKey("time")) {
-			return;
-		}
-		Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0));
-		if (d != null /* parsing ok */) {
-			time = d.getTime() / 1000.0; /* ms => seconds */
-		}
-	}
+    @Override
+    public String toString() {
+        return "WayPoint (" + (attr.containsKey("name") ? attr.get("name") + ", " :"") + latlon.toString() + ", " + attr + ")";
+    }
 
-	/**
-	 * Convert a time stamp of the waypoint from the <cmt> or <desc> field 
-	 * into seconds from the epoch. Handles the date format as it is used by 
-	 * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0).
-	 * A value of <time> fields overwrites values set with by method.
-	 * Does nothing if specified key does not exist or text cannot be parsed.
-	 * 
-	 * @param key The key that contains the text to convert.
-	 */
-	public void setGarminCommentTime(String key) {
-		// do not overwrite time if already set
-		if (time != 0.0) {
-			return;
-		}
-		if (! attr.containsKey(key)) {
-			return;
-		}
-		// example date format "18-AUG-08 13:33:03"
-		SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone
-		Date d = f.parse(attr.get(key).toString(), new ParsePosition(0));
-		if (d != null /* parsing OK */) {
-			time = d.getTime() / 1000.0; /* ms => seconds */
-		}
-	}
+    /**
+     * Convert the time stamp of the waypoint into seconds from the epoch
+     */
+    public final static SimpleDateFormat GPXTIMEFMT =
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone
 
-	public int compareTo(WayPoint w)
-	{
-		return Double.compare(time, w.time);
-	}
+    public void setTime() {
+        if (! attr.containsKey("time")) {
+            return;
+        }
+        Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0));
+        if (d != null /* parsing ok */) {
+            time = d.getTime() / 1000.0; /* ms => seconds */
+        }
+    }
+
+    /**
+     * Convert a time stamp of the waypoint from the <cmt> or <desc> field
+     * into seconds from the epoch. Handles the date format as it is used by
+     * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0).
+     * A value of <time> fields overwrites values set with by method.
+     * Does nothing if specified key does not exist or text cannot be parsed.
+     *
+     * @param key The key that contains the text to convert.
+     */
+    public void setGarminCommentTime(String key) {
+        // do not overwrite time if already set
+        if (time != 0.0) {
+            return;
+        }
+        if (! attr.containsKey(key)) {
+            return;
+        }
+        // example date format "18-AUG-08 13:33:03"
+        SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone
+        Date d = f.parse(attr.get(key).toString(), new ParsePosition(0));
+        if (d != null /* parsing OK */) {
+            time = d.getTime() / 1000.0; /* ms => seconds */
+        }
+    }
+
+    public int compareTo(WayPoint w)
+    {
+        return Double.compare(time, w.time);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java	(revision 1169)
@@ -1,3 +1,3 @@
-// License: GPL. 
+// License: GPL.
 package org.openstreetmap.josm.data.gpx;
 
@@ -9,15 +9,15 @@
  * The "attr" hash is used to store the XML payload
  * (not only XML attributes!)
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
  */
 public class WithAttributes {
-	
-	public Map<String, Object> attr = new HashMap<String, Object>(0);
-	
-	public String getString(String key) {
-		Object value = attr.get(key);
-		return (value instanceof String) ? (String)value : null;
-	}
+
+    public Map<String, Object> attr = new HashMap<String, Object>(0);
+
+    public String getString(String key) {
+        Object value = attr.get(key);
+        return (value instanceof String) ? (String)value : null;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 1169)
@@ -20,28 +20,28 @@
  */
 public final class Changeset /*extends OsmPrimitive*/ implements OsmWriterInterface {
-	/**
-	 * The key/value list for this primitive.
-	 */
-	public Map<String, String> keys;
+    /**
+     * The key/value list for this primitive.
+     */
+    public Map<String, String> keys;
 
-	public long id = 0;
-	
-	/** 
-	 * User that created this changeset, as specified by the server.
-	 * Never changed by JOSM.
-	 */
-	public User user = null;
-	
-	/**
-	 * Time of last modification to this object. This is not set by JOSM but
-	 * read from the server and delivered back to the server unmodified. 
-	 */
-	public String end_timestamp = null;
-	
-	/**
-	 * Time of first modification to this object. This is not set by JOSM but
-	 * read from the server and delivered back to the server unmodified.
-	 */
-	public String start_timestamp = null;
+    public long id = 0;
+
+    /**
+     * User that created this changeset, as specified by the server.
+     * Never changed by JOSM.
+     */
+    public User user = null;
+
+    /**
+     * Time of last modification to this object. This is not set by JOSM but
+     * read from the server and delivered back to the server unmodified.
+     */
+    public String end_timestamp = null;
+
+    /**
+     * Time of first modification to this object. This is not set by JOSM but
+     * read from the server and delivered back to the server unmodified.
+     */
+    public String start_timestamp = null;
 
         private void addTags(PrintWriter out) {
@@ -53,69 +53,69 @@
         }
 
-	public final void header(PrintWriter out) {
-        	out.print("<osm version='");
+    public final void header(PrintWriter out) {
+            out.print("<osm version='");
                 out.print(Main.pref.get("osm-server.version", "0.6"));
                 out.println("' generator='JOSM'>");
-	}
-	public final void write(PrintWriter out) {
-		out.print("  <changeset");
-		if (id != 0)
-			out.print(" id="+id);
-		if (this.user != null) {
-			out.print(" user='"+XmlWriter.encode(this.user.name)+"'");
-		}
-		out.println(">\n");
-		addTags( out );
-		out.println("  </changeset>");
-	}
-	public final void footer(PrintWriter out) {
-		out.println("</osm>");
-	}
-	
-	/******************************************************
-	 * This tag stuff is copied from OsmPrimitive. Perhaps a changeset
-	 * really is a primitive, but it's not right now. Perhaps it should
-	 * be...
-	 ******************************************************/
-	 
-	/**
-	 * Set the given value to the given key
-	 * @param key The key, for which the value is to be set.
-	 * @param value The value for the key.
-	 */
-	public final void put(String key, String value) {
-		if (value == null)
-			remove(key);
-		else {
-			if (keys == null)
-				keys = new HashMap<String, String>();
-			keys.put(key, value);
-		}
-	}
-	/**
-	 * Remove the given key from the list.
-	 */
-	public final void remove(String key) {
-		if (keys != null) {
-			keys.remove(key);
-			if (keys.isEmpty())
-				keys = null;
-		}
-	}
+    }
+    public final void write(PrintWriter out) {
+        out.print("  <changeset");
+        if (id != 0)
+            out.print(" id="+id);
+        if (this.user != null) {
+            out.print(" user='"+XmlWriter.encode(this.user.name)+"'");
+        }
+        out.println(">\n");
+        addTags( out );
+        out.println("  </changeset>");
+    }
+    public final void footer(PrintWriter out) {
+        out.println("</osm>");
+    }
 
-	public final String get(String key) {
-		return keys == null ? null : keys.get(key);
-	}
+    /******************************************************
+     * This tag stuff is copied from OsmPrimitive. Perhaps a changeset
+     * really is a primitive, but it's not right now. Perhaps it should
+     * be...
+     ******************************************************/
 
-	public final Collection<Entry<String, String>> entrySet() {
-		if (keys == null)
-			return Collections.emptyList();
-		return keys.entrySet();
-	}
+    /**
+     * Set the given value to the given key
+     * @param key The key, for which the value is to be set.
+     * @param value The value for the key.
+     */
+    public final void put(String key, String value) {
+        if (value == null)
+            remove(key);
+        else {
+            if (keys == null)
+                keys = new HashMap<String, String>();
+            keys.put(key, value);
+        }
+    }
+    /**
+     * Remove the given key from the list.
+     */
+    public final void remove(String key) {
+        if (keys != null) {
+            keys.remove(key);
+            if (keys.isEmpty())
+                keys = null;
+        }
+    }
 
-	public final Collection<String> keySet() {
-		if (keys == null)
-			return Collections.emptyList();
-		return keys.keySet();
-	}
+    public final String get(String key) {
+        return keys == null ? null : keys.get(key);
+    }
+
+    public final Collection<Entry<String, String>> entrySet() {
+        if (keys == null)
+            return Collections.emptyList();
+        return keys.entrySet();
+    }
+
+    public final Collection<String> keySet() {
+        if (keys == null)
+            return Collections.emptyList();
+        return keys.keySet();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 1169)
@@ -17,8 +17,8 @@
  * DataSet is the data behind the application. It can consists of only a few points up to the whole
  * osm database. DataSet's can be merged together, saved, (up/down/disk)loaded etc.
- * 
+ *
  * Note that DataSet is not an osm-primitive and so has no key association but a few members to
  * store some information.
- * 
+ *
  * @author imi
  */
@@ -33,5 +33,5 @@
     /**
      * All ways (Streets etc.) in the DataSet.
-     * 
+     *
      * The way nodes are stored only in the way list.
      */
@@ -235,5 +235,5 @@
 
     // Provide well-defined sorting for collections of OsmPrimitives.
-    // FIXME: probably not a good place to put this code. 
+    // FIXME: probably not a good place to put this code.
     public static OsmPrimitive[] sort(Collection<? extends OsmPrimitive> list) {
         OsmPrimitive[] selArr = new OsmPrimitive[list.size()];
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSource.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSource.java	(revision 1169)
@@ -5,14 +5,14 @@
 
 public class DataSource implements Cloneable {
-	public final Bounds bounds;
-	public final String origin;
-	
-	public DataSource(Bounds bounds, String origin) {
-	    this.bounds = bounds;
-	    this.origin = origin;
+    public final Bounds bounds;
+    public final String origin;
+
+    public DataSource(Bounds bounds, String origin) {
+        this.bounds = bounds;
+        this.origin = origin;
     }
 
-	@Override protected Object clone() throws CloneNotSupportedException {
-	    return new DataSource(bounds, origin);
+    @Override protected Object clone() throws CloneNotSupportedException {
+        return new DataSource(bounds, origin);
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/DateFormatter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DateFormatter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/DateFormatter.java	(revision 1169)
@@ -9,76 +9,76 @@
 /**
  * Outputs a date in a format suitable for an OSM XML file.
- * 
+ *
  * @author Brett Henderson
  */
 public class DateFormatter {
-	
-	private GregorianCalendar calendar;
-	
-	
-	/**
-	 * Creates a new instance.
-	 */
-	public DateFormatter() {
-		calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
-	}
-	
-	
-	/**
-	 * Formats a date in XML format.
-	 * 
-	 * @param date
-	 *            The date to be formatted.
-	 * @return The string representing the date.
-	 */
-	public String format(Date date) {
-		StringBuilder result;
-		int year;
-		int month;
-		int day;
-		int hour;
-		int minute;
-		int second;
-		
-		calendar.setTime(date);
-		
-		result = new StringBuilder(20);
-		
-		year = calendar.get(Calendar.YEAR);
-		month = calendar.get(Calendar.MONTH) + 1;
-		day = calendar.get(Calendar.DATE);
-		hour = calendar.get(Calendar.HOUR_OF_DAY);
-		minute = calendar.get(Calendar.MINUTE);
-		second = calendar.get(Calendar.SECOND);
-		
-		result.append(year);
-		result.append('-');
-		if (month < 10) {
-			result.append('0');
-		}
-		result.append(month);
-		result.append('-');
-		if (day < 10) {
-			result.append('0');
-		}
-		result.append(day);
-		result.append('T');
-		if (hour < 10) {
-			result.append('0');
-		}
-		result.append(hour);
-		result.append(':');
-		if (minute < 10) {
-			result.append('0');
-		}
-		result.append(minute);
-		result.append(':');
-		if (second < 10) {
-			result.append('0');
-		}
-		result.append(second);
-		result.append('Z');
-		
-		return result.toString();
-	}
+
+    private GregorianCalendar calendar;
+
+
+    /**
+     * Creates a new instance.
+     */
+    public DateFormatter() {
+        calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    }
+
+
+    /**
+     * Formats a date in XML format.
+     *
+     * @param date
+     *            The date to be formatted.
+     * @return The string representing the date.
+     */
+    public String format(Date date) {
+        StringBuilder result;
+        int year;
+        int month;
+        int day;
+        int hour;
+        int minute;
+        int second;
+
+        calendar.setTime(date);
+
+        result = new StringBuilder(20);
+
+        year = calendar.get(Calendar.YEAR);
+        month = calendar.get(Calendar.MONTH) + 1;
+        day = calendar.get(Calendar.DATE);
+        hour = calendar.get(Calendar.HOUR_OF_DAY);
+        minute = calendar.get(Calendar.MINUTE);
+        second = calendar.get(Calendar.SECOND);
+
+        result.append(year);
+        result.append('-');
+        if (month < 10) {
+            result.append('0');
+        }
+        result.append(month);
+        result.append('-');
+        if (day < 10) {
+            result.append('0');
+        }
+        result.append(day);
+        result.append('T');
+        if (hour < 10) {
+            result.append('0');
+        }
+        result.append(hour);
+        result.append(':');
+        if (minute < 10) {
+            result.append('0');
+        }
+        result.append(minute);
+        result.append(':');
+        if (second < 10) {
+            result.append('0');
+        }
+        result.append(second);
+        result.append('Z');
+
+        return result.toString();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 1169)
@@ -19,10 +19,10 @@
  */
 public final class Node extends OsmPrimitive {
-	
-	public LatLon coor;
-	public volatile EastNorth eastNorth;
-    
+
+    public LatLon coor;
+    public volatile EastNorth eastNorth;
+
     private static CoordinateFormat mCord;
-    
+
     static {
         try {
@@ -33,41 +33,41 @@
     }
 
-	/**
-	 * Create an incomplete Node object
-	 */
-	public Node(long id) {
-		this.id = id;
-		incomplete = true;
-	}
-	
-	/**
-	 * Create an identical clone of the argument (including the id)
-	 */
-	public Node(Node clone) {
-		cloneFrom(clone);
-	}
+    /**
+     * Create an incomplete Node object
+     */
+    public Node(long id) {
+        this.id = id;
+        incomplete = true;
+    }
 
-	public Node(LatLon latlon) {
-		this.coor = latlon;
-		eastNorth = Main.proj.latlon2eastNorth(latlon);
-	}
+    /**
+     * Create an identical clone of the argument (including the id)
+     */
+    public Node(Node clone) {
+        cloneFrom(clone);
+    }
 
-	@Override public void visit(Visitor visitor) {
-		visitor.visit(this);
-	}
-	
-	@Override public void cloneFrom(OsmPrimitive osm) {
-		super.cloneFrom(osm);
-		coor = ((Node)osm).coor;
-		eastNorth = ((Node)osm).eastNorth;
-	}
+    public Node(LatLon latlon) {
+        this.coor = latlon;
+        eastNorth = Main.proj.latlon2eastNorth(latlon);
+    }
 
-	@Override public String toString() {
-		if (coor == null) return "{Node id="+id+"}";
-		return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}";
-	}
+    @Override public void visit(Visitor visitor) {
+        visitor.visit(this);
+    }
 
-	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
-		if (osm instanceof Node) {
+    @Override public void cloneFrom(OsmPrimitive osm) {
+        super.cloneFrom(osm);
+        coor = ((Node)osm).coor;
+        eastNorth = ((Node)osm).eastNorth;
+    }
+
+    @Override public String toString() {
+        if (coor == null) return "{Node id="+id+"}";
+        return "{Node id="+id+",version="+version+",lat="+coor.lat()+",lon="+coor.lon()+"}";
+    }
+
+    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+        if (osm instanceof Node) {
             if (super.realEqual(osm, semanticOnly)) {
                 if ((coor == null) && ((Node)osm).coor == null)
@@ -80,19 +80,19 @@
     }
 
-	public int compareTo(OsmPrimitive o) {
-	    return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1;
-	}
+    public int compareTo(OsmPrimitive o) {
+        return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1;
+    }
 
-	public String getName() {
-		String name;
-		if (incomplete) {
-			name = tr("incomplete");
-		} else {
-			name = get("name");
-			if (name == null)
-				name = id == 0 ? "" : ""+id;
-			name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")";
-		}
-		return name;
-	}
+    public String getName() {
+        String name;
+        if (incomplete) {
+            name = tr("incomplete");
+        } else {
+            name = get("name");
+            if (name == null)
+                name = id == 0 ? "" : ""+id;
+            name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")";
+        }
+        return name;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 1169)
@@ -30,287 +30,287 @@
 abstract public class OsmPrimitive implements Comparable<OsmPrimitive> {
 
-	/**
-	 * The key/value list for this primitive.
-	 */
-	public Map<String, String> keys;
-
-	/**
-	 * Unique identifier in OSM. This is used to identify objects on the server.
-	 * An id of 0 means an unknown id. The object has not been uploaded yet to
-	 * know what id it will get.
-	 *
-	 * Do not write to this attribute except you know exactly what you are doing.
-	 * More specific, it is not good to set this to 0 and think the object is now
-	 * new to the server! To create a new object, call the default constructor of
-	 * the respective class.
-	 */
-	public long id = 0;
-
-	/**
-	 * <code>true</code> if the object has been modified since it was loaded from
-	 * the server. In this case, on next upload, this object will be updated.
-	 * Deleted objects are deleted from the server. If the objects are added (id=0),
-	 * the modified is ignored and the object is added to the server.
-	 */
-	public boolean modified = false;
-
-	/**
-	 * <code>true</code>, if the object has been deleted.
-	 */
-	public boolean deleted = false;
-
-	/**
-	 * Visibility status as specified by the server. The visible attribute was
-	 * introduced with the 0.4 API to be able to communicate deleted objects
-	 * (they will have visible=false). Currently JOSM does never deal with
-	 * these, so this is really for future use only.
-	 */
-	public boolean visible = true;
-
-	/**
-	 * User that last modified this primitive, as specified by the server.
-	 * Never changed by JOSM.
-	 */
-	public User user = null;
-
-	/**
-	 * true if this object is considered "tagged". To be "tagged", an object
-	 * must have one or more "non-standard" tags. "created_by" and "source"
-	 * are typically considered "standard" tags and do not make an object
-	 * "tagged".
-	 */
-	public boolean tagged = false;
-
-	/**
-	 * true if this object has direction dependent tags (e.g. oneway)
-	 */
-	public boolean hasDirectionKeys = false;
-
-	/**
-	 * If set to true, this object is currently selected.
-	 */
-	public volatile boolean selected = false;
-
-	/**
-	 * Time of last modification to this object. This is not set by JOSM but
-	 * read from the server and delivered back to the server unmodified. It is
-	 * used to check against edit conflicts.
-	 */
-	public String timestamp = null;
-
-	/**
-	 * The timestamp is only parsed when this is really necessary, and this
-	 * is the cache for the result.
-	 */
-	public Date parsedTimestamp = null;
-
-	/**
-	 * If set to true, this object is incomplete, which means only the id
-	 * and type is known (type is the objects instance class)
-	 */
-	public boolean incomplete = false;
-
-	/**
-	 * Contains the version number as returned by the API. Needed to
-	 * ensure update consistency
-	 */
-	public int version = -1;
-
-	/**
-	 * Contains a list of "uninteresting" keys that do not make an object
-	 * "tagged".
-	 * Initialized by checkTagged()
-	 */
-	private static Collection<String> uninteresting = null;
-
-	/**
-	 * Contains a list of direction-dependent keys that make an object
-	 * direction dependent.
-	 * Initialized by checkDirectionTagged()
-	 */
-	private static Collection<String> directionKeys = null;
-
-	/**
-	 * Implementation of the visitor scheme. Subclasses have to call the correct
-	 * visitor function.
-	 * @param visitor The visitor from which the visit() function must be called.
-	 */
-	abstract public void visit(Visitor visitor);
-
-	public final void delete(boolean deleted) {
-		this.deleted = deleted;
-		selected = false;
-		modified = true;
-	}
-
-	/**
-	 * Returns the timestamp for this object, or the current time if none is set.
-	 * Internally, parses the timestamp from XML into a Date object and caches it
-	 * for possible repeated calls.
-	 */
-	public Date getTimestamp() {
-		if (parsedTimestamp == null) {
-			try {
-				parsedTimestamp = DateParser.parse(timestamp);
-			} catch (ParseException ex) {
-				parsedTimestamp = new Date();
-			}
-		}
-		return parsedTimestamp;
-	}
-
-	/**
-	 * Equal, if the id (and class) is equal.
-	 *
-	 * An primitive is equal to its incomplete counter part.
-	 */
-	@Override public boolean equals(Object obj) {
-		if (id == 0) return obj == this;
-		if (obj instanceof OsmPrimitive) { // not null too
-			return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass();
-		}
-		return false;
-	}
-
-	/**
-	 * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0.
-	 *
-	 * An primitive has the same hashcode as its incomplete counterpart.
-	 */
-	@Override public final int hashCode() {
-		if (id == 0)
-			return super.hashCode();
-		final int[] ret = new int[1];
-		Visitor v = new Visitor(){
-			public void visit(Node n) { ret[0] = 1; }
-			public void visit(Way w) { ret[0] = 2; }
-			public void visit(Relation e) { ret[0] = 3; }
-		};
-		visit(v);
-		return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
-	}
-
-	/**
-	 * Set the given value to the given key
-	 * @param key The key, for which the value is to be set.
-	 * @param value The value for the key.
-	 */
-	public final void put(String key, String value) {
-		if (value == null)
-			remove(key);
-		else {
-			if (keys == null)
-				keys = new HashMap<String, String>();
-			keys.put(key, value);
-		}
-		checkTagged();
-		checkDirectionTagged();
-	}
-	/**
-	 * Remove the given key from the list.
-	 */
-	public final void remove(String key) {
-		if (keys != null) {
-			keys.remove(key);
-			if (keys.isEmpty())
-				keys = null;
-		}
-		checkTagged();
-		checkDirectionTagged();
-	}
-
-	public String getName() {
-		return null;
-	}
-
-	public final String get(String key) {
-		return keys == null ? null : keys.get(key);
-	}
-
-	public final Collection<Entry<String, String>> entrySet() {
-		if (keys == null)
-			return Collections.emptyList();
-		return keys.entrySet();
-	}
-
-	public final Collection<String> keySet() {
-		if (keys == null)
-			return Collections.emptyList();
-		return keys.keySet();
-	}
-
-	/**
-	 * Get and write all attributes from the parameter. Does not fire any listener, so
-	 * use this only in the data initializing phase
-	 */
-	public void cloneFrom(OsmPrimitive osm) {
-		keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys);
-		id = osm.id;
-		modified = osm.modified;
-		deleted = osm.deleted;
-		selected = osm.selected;
-		timestamp = osm.timestamp;
-		version = osm.version;
-		tagged = osm.tagged;
-		incomplete = osm.incomplete;
-	}
-
-	/**
-	 * Perform an equality compare for all non-volatile fields not only for the id
-	 * but for the whole object (for conflict resolving)
-	 * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared
-	 */
-	public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
-		return
-			id == osm.id &&
-			incomplete == osm.incomplete &&
-			(semanticOnly || (modified == osm.modified)) &&
-			deleted == osm.deleted &&
-			(semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) &&
-			(semanticOnly || (version==osm.version)) &&
-			(semanticOnly || (user == null ? osm.user==null : user==osm.user)) &&
-			(semanticOnly || (visible == osm.visible)) &&
-			(keys == null ? osm.keys==null : keys.equals(osm.keys));
-	}
-
-	public String getTimeStr() {
-		return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
-	}
-
-	/**
-	 * Updates the "tagged" flag. "keys" property should probably be made private
-	 * to make sure this gets called when keys are set.
-	 */
-	public void checkTagged() {
-		tagged = false;
-		if(uninteresting == null)
-			uninteresting = new HashSet<String>(Arrays.asList(Main.pref.get("tags.uninteresting",
-			"source;note;converted_by;created_by").split(";")));
-		if (keys != null) {
-			for (Entry<String,String> e : keys.entrySet()) {
-				if (!uninteresting.contains(e.getKey())) {
-					tagged = true;
-					break;
-				}
-			}
-		}
-	}
-	/**
-	 * Updates the "hasDirectionKeys" flag. "keys" property should probably be made private
-	 * to make sure this gets called when keys are set.
-	 */
-	public void checkDirectionTagged() {
-		hasDirectionKeys = false;
-		if(directionKeys == null)
-			directionKeys = new HashSet<String>(Arrays.asList(Main.pref.get("tags.direction",
-			"oneway;incline;incline_step;aerialway").split(";")));
-		if (keys != null) {
-			for (Entry<String,String> e : keys.entrySet()) {
-				if (directionKeys.contains(e.getKey())) {
-					hasDirectionKeys = true;
-					break;
-				}
-			}
-		}
-	}
+    /**
+     * The key/value list for this primitive.
+     */
+    public Map<String, String> keys;
+
+    /**
+     * Unique identifier in OSM. This is used to identify objects on the server.
+     * An id of 0 means an unknown id. The object has not been uploaded yet to
+     * know what id it will get.
+     *
+     * Do not write to this attribute except you know exactly what you are doing.
+     * More specific, it is not good to set this to 0 and think the object is now
+     * new to the server! To create a new object, call the default constructor of
+     * the respective class.
+     */
+    public long id = 0;
+
+    /**
+     * <code>true</code> if the object has been modified since it was loaded from
+     * the server. In this case, on next upload, this object will be updated.
+     * Deleted objects are deleted from the server. If the objects are added (id=0),
+     * the modified is ignored and the object is added to the server.
+     */
+    public boolean modified = false;
+
+    /**
+     * <code>true</code>, if the object has been deleted.
+     */
+    public boolean deleted = false;
+
+    /**
+     * Visibility status as specified by the server. The visible attribute was
+     * introduced with the 0.4 API to be able to communicate deleted objects
+     * (they will have visible=false). Currently JOSM does never deal with
+     * these, so this is really for future use only.
+     */
+    public boolean visible = true;
+
+    /**
+     * User that last modified this primitive, as specified by the server.
+     * Never changed by JOSM.
+     */
+    public User user = null;
+
+    /**
+     * true if this object is considered "tagged". To be "tagged", an object
+     * must have one or more "non-standard" tags. "created_by" and "source"
+     * are typically considered "standard" tags and do not make an object
+     * "tagged".
+     */
+    public boolean tagged = false;
+
+    /**
+     * true if this object has direction dependent tags (e.g. oneway)
+     */
+    public boolean hasDirectionKeys = false;
+
+    /**
+     * If set to true, this object is currently selected.
+     */
+    public volatile boolean selected = false;
+
+    /**
+     * Time of last modification to this object. This is not set by JOSM but
+     * read from the server and delivered back to the server unmodified. It is
+     * used to check against edit conflicts.
+     */
+    public String timestamp = null;
+
+    /**
+     * The timestamp is only parsed when this is really necessary, and this
+     * is the cache for the result.
+     */
+    public Date parsedTimestamp = null;
+
+    /**
+     * If set to true, this object is incomplete, which means only the id
+     * and type is known (type is the objects instance class)
+     */
+    public boolean incomplete = false;
+
+    /**
+     * Contains the version number as returned by the API. Needed to
+     * ensure update consistency
+     */
+    public int version = -1;
+
+    /**
+     * Contains a list of "uninteresting" keys that do not make an object
+     * "tagged".
+     * Initialized by checkTagged()
+     */
+    private static Collection<String> uninteresting = null;
+
+    /**
+     * Contains a list of direction-dependent keys that make an object
+     * direction dependent.
+     * Initialized by checkDirectionTagged()
+     */
+    private static Collection<String> directionKeys = null;
+
+    /**
+     * Implementation of the visitor scheme. Subclasses have to call the correct
+     * visitor function.
+     * @param visitor The visitor from which the visit() function must be called.
+     */
+    abstract public void visit(Visitor visitor);
+
+    public final void delete(boolean deleted) {
+        this.deleted = deleted;
+        selected = false;
+        modified = true;
+    }
+
+    /**
+     * Returns the timestamp for this object, or the current time if none is set.
+     * Internally, parses the timestamp from XML into a Date object and caches it
+     * for possible repeated calls.
+     */
+    public Date getTimestamp() {
+        if (parsedTimestamp == null) {
+            try {
+                parsedTimestamp = DateParser.parse(timestamp);
+            } catch (ParseException ex) {
+                parsedTimestamp = new Date();
+            }
+        }
+        return parsedTimestamp;
+    }
+
+    /**
+     * Equal, if the id (and class) is equal.
+     *
+     * An primitive is equal to its incomplete counter part.
+     */
+    @Override public boolean equals(Object obj) {
+        if (id == 0) return obj == this;
+        if (obj instanceof OsmPrimitive) { // not null too
+            return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass();
+        }
+        return false;
+    }
+
+    /**
+     * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0.
+     *
+     * An primitive has the same hashcode as its incomplete counterpart.
+     */
+    @Override public final int hashCode() {
+        if (id == 0)
+            return super.hashCode();
+        final int[] ret = new int[1];
+        Visitor v = new Visitor(){
+            public void visit(Node n) { ret[0] = 1; }
+            public void visit(Way w) { ret[0] = 2; }
+            public void visit(Relation e) { ret[0] = 3; }
+        };
+        visit(v);
+        return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
+    }
+
+    /**
+     * Set the given value to the given key
+     * @param key The key, for which the value is to be set.
+     * @param value The value for the key.
+     */
+    public final void put(String key, String value) {
+        if (value == null)
+            remove(key);
+        else {
+            if (keys == null)
+                keys = new HashMap<String, String>();
+            keys.put(key, value);
+        }
+        checkTagged();
+        checkDirectionTagged();
+    }
+    /**
+     * Remove the given key from the list.
+     */
+    public final void remove(String key) {
+        if (keys != null) {
+            keys.remove(key);
+            if (keys.isEmpty())
+                keys = null;
+        }
+        checkTagged();
+        checkDirectionTagged();
+    }
+
+    public String getName() {
+        return null;
+    }
+
+    public final String get(String key) {
+        return keys == null ? null : keys.get(key);
+    }
+
+    public final Collection<Entry<String, String>> entrySet() {
+        if (keys == null)
+            return Collections.emptyList();
+        return keys.entrySet();
+    }
+
+    public final Collection<String> keySet() {
+        if (keys == null)
+            return Collections.emptyList();
+        return keys.keySet();
+    }
+
+    /**
+     * Get and write all attributes from the parameter. Does not fire any listener, so
+     * use this only in the data initializing phase
+     */
+    public void cloneFrom(OsmPrimitive osm) {
+        keys = osm.keys == null ? null : new HashMap<String, String>(osm.keys);
+        id = osm.id;
+        modified = osm.modified;
+        deleted = osm.deleted;
+        selected = osm.selected;
+        timestamp = osm.timestamp;
+        version = osm.version;
+        tagged = osm.tagged;
+        incomplete = osm.incomplete;
+    }
+
+    /**
+     * Perform an equality compare for all non-volatile fields not only for the id
+     * but for the whole object (for conflict resolving)
+     * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared
+     */
+    public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+        return
+            id == osm.id &&
+            incomplete == osm.incomplete &&
+            (semanticOnly || (modified == osm.modified)) &&
+            deleted == osm.deleted &&
+            (semanticOnly || (timestamp == null ? osm.timestamp==null : timestamp.equals(osm.timestamp))) &&
+            (semanticOnly || (version==osm.version)) &&
+            (semanticOnly || (user == null ? osm.user==null : user==osm.user)) &&
+            (semanticOnly || (visible == osm.visible)) &&
+            (keys == null ? osm.keys==null : keys.equals(osm.keys));
+    }
+
+    public String getTimeStr() {
+        return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
+    }
+
+    /**
+     * Updates the "tagged" flag. "keys" property should probably be made private
+     * to make sure this gets called when keys are set.
+     */
+    public void checkTagged() {
+        tagged = false;
+        if(uninteresting == null)
+            uninteresting = new HashSet<String>(Arrays.asList(Main.pref.get("tags.uninteresting",
+            "source;note;converted_by;created_by").split(";")));
+        if (keys != null) {
+            for (Entry<String,String> e : keys.entrySet()) {
+                if (!uninteresting.contains(e.getKey())) {
+                    tagged = true;
+                    break;
+                }
+            }
+        }
+    }
+    /**
+     * Updates the "hasDirectionKeys" flag. "keys" property should probably be made private
+     * to make sure this gets called when keys are set.
+     */
+    public void checkDirectionTagged() {
+        hasDirectionKeys = false;
+        if(directionKeys == null)
+            directionKeys = new HashSet<String>(Arrays.asList(Main.pref.get("tags.direction",
+            "oneway;incline;incline_step;aerialway").split(";")));
+        if (keys != null) {
+            for (Entry<String,String> e : keys.entrySet()) {
+                if (directionKeys.contains(e.getKey())) {
+                    hasDirectionKeys = true;
+                    break;
+                }
+            }
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java	(revision 1169)
@@ -8,22 +8,22 @@
 public class OsmUtils {
 
-	static ArrayList<String> TRUE_VALUES = new ArrayList<String>(Arrays
-	        .asList(new String[] { "true", "yes", "1", "on" }));
-	static ArrayList<String> FALSE_VALUES = new ArrayList<String>(Arrays
-	        .asList(new String[] { "false", "no", "0", "off" }));
+    static ArrayList<String> TRUE_VALUES = new ArrayList<String>(Arrays
+            .asList(new String[] { "true", "yes", "1", "on" }));
+    static ArrayList<String> FALSE_VALUES = new ArrayList<String>(Arrays
+            .asList(new String[] { "false", "no", "0", "off" }));
 
-	public static final String trueval = "yes";
-	public static final String falseval = "no";
+    public static final String trueval = "yes";
+    public static final String falseval = "no";
 
-	public static Boolean getOsmBoolean(String value) {
-		if(value == null) return null;
-		String lowerValue = value.toLowerCase(Locale.ENGLISH);
-		if (TRUE_VALUES.contains(lowerValue)) return Boolean.TRUE;
-		if (FALSE_VALUES.contains(lowerValue)) return Boolean.FALSE;
-		return null;
-	}
-	public static String getNamedOsmBoolean(String value) {
-		Boolean res = getOsmBoolean(value);
-		return res == null ? value : (res ? trueval : falseval);
-	}
+    public static Boolean getOsmBoolean(String value) {
+        if(value == null) return null;
+        String lowerValue = value.toLowerCase(Locale.ENGLISH);
+        if (TRUE_VALUES.contains(lowerValue)) return Boolean.TRUE;
+        if (FALSE_VALUES.contains(lowerValue)) return Boolean.FALSE;
+        return null;
+    }
+    public static String getNamedOsmBoolean(String value) {
+        Boolean res = getOsmBoolean(value);
+        return res == null ? value : (res ? trueval : falseval);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 1169)
@@ -11,91 +11,91 @@
 /**
  * An relation, having a set of tags and any number (0...n) of members.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  */
 public final class Relation extends OsmPrimitive {
-	
-	/**
-	 * All members of this relation. Note that after changing this,
-	 * makeBackReferences and/or removeBackReferences should be called.
-	 */
-	public final List<RelationMember> members = new ArrayList<RelationMember>();
 
-	@Override public void visit(Visitor visitor) {
-		visitor.visit(this);
-	}
+    /**
+     * All members of this relation. Note that after changing this,
+     * makeBackReferences and/or removeBackReferences should be called.
+     */
+    public final List<RelationMember> members = new ArrayList<RelationMember>();
 
-	/**
-	 * Create an identical clone of the argument (including the id)
-	 */
-	public Relation(Relation clone) {
-		cloneFrom(clone);
-	}
-	
-	/**
-	 * Create an incomplete Relation.
-	 */
-	public Relation(long id) {
-		this.id = id;
-		incomplete = true;
-	}
-	
-	/** 
-	 * Create an empty Relation. Use this only if you set meaningful values
-	 * afterwards.
-	 */
-	public Relation() {	
-	}
-	
-	@Override public void cloneFrom(OsmPrimitive osm) {
-		super.cloneFrom(osm);
-		members.clear();
-		// we must not add the members themselves, but instead
-		// add clones of the members
-		for (RelationMember em : ((Relation)osm).members) {
-			members.add(new RelationMember(em));
-		}
-	}
+    @Override public void visit(Visitor visitor) {
+        visitor.visit(this);
+    }
 
-	@Override public String toString() {
-		// return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}";
-		// adding members in string increases memory usage a lot and overflows for looped relations
-		return "{Relation id="+id+" version="+version+"}";
-	}
+    /**
+     * Create an identical clone of the argument (including the id)
+     */
+    public Relation(Relation clone) {
+        cloneFrom(clone);
+    }
 
-	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
-		return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false;
-	}
+    /**
+     * Create an incomplete Relation.
+     */
+    public Relation(long id) {
+        this.id = id;
+        incomplete = true;
+    }
 
-	public int compareTo(OsmPrimitive o) {
-	    return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1;
-	}
+    /**
+     * Create an empty Relation. Use this only if you set meaningful values
+     * afterwards.
+     */
+    public Relation() {
+    }
 
-	public String getName() {
-		String name;
-		if (incomplete) {
-			name = tr("incomplete");
-		} else {
-			name = get("type");
-			// FIXME add names of members
-			if (name == null)
-				name = tr("relation");
-			
-			name += " (";
-			String nameTag = get("name");
-			if (nameTag == null) nameTag = get("ref");
-			if (nameTag == null) nameTag = get("note");
-			if (nameTag != null) name += "\"" + nameTag + "\", ";
-			int mbno = members.size();
-			name += trn("{0} member", "{0} members", mbno, mbno) + ")";
-		}
-		return name;
-	}
+    @Override public void cloneFrom(OsmPrimitive osm) {
+        super.cloneFrom(osm);
+        members.clear();
+        // we must not add the members themselves, but instead
+        // add clones of the members
+        for (RelationMember em : ((Relation)osm).members) {
+            members.add(new RelationMember(em));
+        }
+    }
 
-	public boolean isIncomplete() {
-		for (RelationMember m : members)
-			if (m.member == null)
-				return true;
-		return false;
-	}
+    @Override public String toString() {
+        // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}";
+        // adding members in string increases memory usage a lot and overflows for looped relations
+        return "{Relation id="+id+" version="+version+"}";
+    }
+
+    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+        return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false;
+    }
+
+    public int compareTo(OsmPrimitive o) {
+        return o instanceof Relation ? Long.valueOf(id).compareTo(o.id) : -1;
+    }
+
+    public String getName() {
+        String name;
+        if (incomplete) {
+            name = tr("incomplete");
+        } else {
+            name = get("type");
+            // FIXME add names of members
+            if (name == null)
+                name = tr("relation");
+
+            name += " (";
+            String nameTag = get("name");
+            if (nameTag == null) nameTag = get("ref");
+            if (nameTag == null) nameTag = get("note");
+            if (nameTag != null) name += "\"" + nameTag + "\", ";
+            int mbno = members.size();
+            name += trn("{0} member", "{0} members", mbno, mbno) + ")";
+        }
+        return name;
+    }
+
+    public boolean isIncomplete() {
+        for (RelationMember m : members)
+            if (m.member == null)
+                return true;
+        return false;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java	(revision 1169)
@@ -2,42 +2,42 @@
 
 /**
- * A linkage class that can be used by an relation to keep a list of 
+ * A linkage class that can be used by an relation to keep a list of
  * members. Since membership may be qualified by a "role", a simple
  * list is not sufficient.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  */
 public class RelationMember {
 
-	public String role;
-	public OsmPrimitive member;
-	
-	/**
-	 * Default constructor. Does nothing.
-	 */
-	public RelationMember() { }
+    public String role;
+    public OsmPrimitive member;
 
-	public RelationMember(String role, OsmPrimitive member) {
-		this.role = role;
-		this.member = member;
-	}
-	
-	/**
-	 * Copy constructor.
-	 * @param other relation member to be copied.
-	 */
-	public RelationMember(RelationMember other) {
-		role = other.role;
-		member = other.member;
-	}
-	
-	@Override public boolean equals(Object other) {
-		if (!(other instanceof RelationMember)) return false;
-		RelationMember otherMember = (RelationMember) other;
-		return otherMember.role.equals(role) && otherMember.member.equals(member);
-	}
+    /**
+     * Default constructor. Does nothing.
+     */
+    public RelationMember() { }
 
-	@Override public String toString() {
-		return '"' + role + "\"=" + member;
-	}
+    public RelationMember(String role, OsmPrimitive member) {
+        this.role = role;
+        this.member = member;
+    }
+
+    /**
+     * Copy constructor.
+     * @param other relation member to be copied.
+     */
+    public RelationMember(RelationMember other) {
+        role = other.role;
+        member = other.member;
+    }
+
+    @Override public boolean equals(Object other) {
+        if (!(other instanceof RelationMember)) return false;
+        RelationMember otherMember = (RelationMember) other;
+        return otherMember.role.equals(role) && otherMember.member.equals(member);
+    }
+
+    @Override public String toString() {
+        return '"' + role + "\"=" + member;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/TigerUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/TigerUtils.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/TigerUtils.java	(revision 1169)
@@ -5,35 +5,35 @@
 import java.util.TreeSet;
 
-/** 
+/**
  * A simple class to keep helper functions for merging TIGER data
- * 
+ *
  * @author daveh
  *
  */
 public class TigerUtils {
-	
-	public static boolean isTigerTag(String tag)
-	{	
-		if (tag.indexOf("tiger:") == -1)
-			return false;
-		return true;
-	}
-	
-	public static boolean tagIsInt(String name) {
-		if (name.equals("tiger:tlid"))
-			return true;
-		return false;
-	}
-	
-	public static Object tagObj(String name) {
-		if (tagIsInt(name))
-			return new Integer(name);
-		return name;
-	}
-	
-	public static String combineTags(String name, Set<String> values) {
+
+    public static boolean isTigerTag(String tag)
+    {
+        if (tag.indexOf("tiger:") == -1)
+            return false;
+        return true;
+    }
+
+    public static boolean tagIsInt(String name) {
+        if (name.equals("tiger:tlid"))
+            return true;
+        return false;
+    }
+
+    public static Object tagObj(String name) {
+        if (tagIsInt(name))
+            return new Integer(name);
+        return name;
+    }
+
+    public static String combineTags(String name, Set<String> values) {
         TreeSet<Object> resultSet = new TreeSet<Object>();
         for (String value: values) {
-        	for (String part: value.split(":")) {
+            for (String part: value.split(":")) {
                resultSet.add(tagObj(part));
             }
@@ -42,15 +42,15 @@
         for (Object part : resultSet) {
             if (combined.length() > 0)
-        		combined += ":";
-        	combined += part;
+                combined += ":";
+            combined += part;
         }
-		return combined;
-	}
-	
-	public static String combineTags(String name, String t1, String t2) {
-		Set<String> set = new TreeSet<String>();
-		set.add(t1);
-		set.add(t2);
-		return TigerUtils.combineTags(name, set);
-	}
+        return combined;
+    }
+
+    public static String combineTags(String name, String t1, String t2) {
+        Set<String> set = new TreeSet<String>();
+        set.add(t1);
+        set.add(t2);
+        return TigerUtils.combineTags(name, set);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/User.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/User.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/User.java	(revision 1169)
@@ -4,11 +4,11 @@
 import java.util.HashMap;
 
-/** 
+/**
  * A simple class to keep a list of user names.
- * 
+ *
  * Instead of storing user names as strings with every OSM primitive, we store
  * a reference to an user object, and make sure that for each username there
  * is only one user object.
- * 
+ *
  * @author fred
  *
@@ -16,23 +16,23 @@
 public class User {
 
-	/** storage for existing User objects. */
-	private static HashMap<String,User> userMap = new HashMap<String,User>();
-	
-	/** the username. */
-	public String name;
-	
-	/** private constructor, only called from get method. */
-	private User(String name) {
-		this.name = name;
-	}
-	
-	/** returns a new or existing User object that represents the given name. */
-	public static User get(String name) {
-		User user = userMap.get(name);
-		if (user == null) {
-			user = new User(name);
-			userMap.put(name, user);
-		}
-		return user;
-	}
+    /** storage for existing User objects. */
+    private static HashMap<String,User> userMap = new HashMap<String,User>();
+
+    /** the username. */
+    public String name;
+
+    /** private constructor, only called from get method. */
+    private User(String name) {
+        this.name = name;
+    }
+
+    /** returns a new or existing User object that represents the given name. */
+    public static User get(String name) {
+        User user = userMap.get(name);
+        if (user == null) {
+            user = new User(name);
+            userMap.put(name, user);
+        }
+        return user;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 1169)
@@ -21,65 +21,65 @@
 public final class Way extends OsmPrimitive {
 
-	/**
-	 * All way nodes in this way
-	 */
-	public final List<Node> nodes = new ArrayList<Node>();
+    /**
+     * All way nodes in this way
+     */
+    public final List<Node> nodes = new ArrayList<Node>();
 
-	public void visitNodes(Visitor v) {
-		for (Node n : this.nodes)
-			v.visit(n);
-	}
+    public void visitNodes(Visitor v) {
+        for (Node n : this.nodes)
+            v.visit(n);
+    }
 
-	public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {
-		ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();
-		Node lastN = null;
-		for (Node n : this.nodes) {
+    public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {
+        ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();
+        Node lastN = null;
+        for (Node n : this.nodes) {
             if (lastN == null) {
-        	    lastN = n;
-           		continue;
-	   	    }
-			Pair<Node,Node> np = new Pair<Node,Node>(lastN, n);
-           	if (sort) {
-           		Pair.sort(np);
-           	}
-           	chunkSet.add(np);
-	        lastN = n;
-		}
-		return chunkSet;
-	}
+                lastN = n;
+                continue;
+            }
+            Pair<Node,Node> np = new Pair<Node,Node>(lastN, n);
+            if (sort) {
+                Pair.sort(np);
+            }
+            chunkSet.add(np);
+            lastN = n;
+        }
+        return chunkSet;
+    }
 
 
-	@Override public void visit(Visitor visitor) {
-		visitor.visit(this);
-	}
+    @Override public void visit(Visitor visitor) {
+        visitor.visit(this);
+    }
 
-	/**
-	 * Create an identical clone of the argument (including the id)
-	 */
-	public Way(Way clone) {
-            cloneFrom(clone);            
-	}
-	
-	/**
-	 * Create an empty way without id. Use this only if you set meaningful 
-	 * values yourself.
-	 */
-	public Way() {
-	}
-	
-	/**
-	 * Create an incomplete Way.
-	 */
-	public Way(long id) {
-		this.id = id;
-		incomplete = true;
-	}
-	
-	@Override public void cloneFrom(OsmPrimitive osm) {
-		super.cloneFrom(osm);
-		nodes.clear();
-		nodes.addAll(((Way)osm).nodes);
+    /**
+     * Create an identical clone of the argument (including the id)
+     */
+    public Way(Way clone) {
+            cloneFrom(clone);
+    }
+
+    /**
+     * Create an empty way without id. Use this only if you set meaningful
+     * values yourself.
+     */
+    public Way() {
+    }
+
+    /**
+     * Create an incomplete Way.
+     */
+    public Way(long id) {
+        this.id = id;
+        incomplete = true;
+    }
+
+    @Override public void cloneFrom(OsmPrimitive osm) {
+        super.cloneFrom(osm);
+        nodes.clear();
+        nodes.addAll(((Way)osm).nodes);
                 checkDirectionTagged();
-	}
+    }
 
     @Override public String toString() {
@@ -87,38 +87,38 @@
     }
 
-	@Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
-		return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false;
+    @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
+        return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false;
     }
 
-	public int compareTo(OsmPrimitive o) {
-		if(o instanceof Relation)
-			return 1;
-		return o instanceof Way ? Long.valueOf(id).compareTo(o.id) : -1;
-	}
+    public int compareTo(OsmPrimitive o) {
+        if(o instanceof Relation)
+            return 1;
+        return o instanceof Way ? Long.valueOf(id).compareTo(o.id) : -1;
+    }
 
-	public String getName() {
-		String name;
-		if (incomplete) {
-			name = tr("incomplete");
-		} else {
-			name = get("name");
-			if (name == null) name = get("ref");
-			if (name == null) {
-				name = 
-					(get("highway") != null) ? tr("highway") :
-					(get("railway") != null) ? tr("railway") :
-					(get("waterway") != null) ? tr("waterway") :
-					(get("landuse") != null) ? tr("landuse") : "";
-			}
+    public String getName() {
+        String name;
+        if (incomplete) {
+            name = tr("incomplete");
+        } else {
+            name = get("name");
+            if (name == null) name = get("ref");
+            if (name == null) {
+                name =
+                    (get("highway") != null) ? tr("highway") :
+                    (get("railway") != null) ? tr("railway") :
+                    (get("waterway") != null) ? tr("waterway") :
+                    (get("landuse") != null) ? tr("landuse") : "";
+            }
 
-			int nodesNo = new HashSet<Node>(nodes).size();
-			name += trn(" ({0} node)", " ({0} nodes)", nodesNo, nodesNo);
-		}
-		return name;
-	}
+            int nodesNo = new HashSet<Node>(nodes).size();
+            name += trn(" ({0} node)", " ({0} nodes)", nodesNo, nodesNo);
+        }
+        return name;
+    }
 
-	@Deprecated
-	public boolean isIncomplete() {
-		return incomplete;
-	}
+    @Deprecated
+    public boolean isIncomplete() {
+        return incomplete;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java	(revision 1169)
@@ -6,28 +6,28 @@
  */
 public final class WaySegment {
-	/**
-	 * The way.
-	 */
-	public Way way;
+    /**
+     * The way.
+     */
+    public Way way;
 
-	/**
-	 * The index of one of the 2 nodes in the way.  The other node has the
-	 * index <code>lowerIndex + 1</code>.
-	 */
-	public int lowerIndex;
+    /**
+     * The index of one of the 2 nodes in the way.  The other node has the
+     * index <code>lowerIndex + 1</code>.
+     */
+    public int lowerIndex;
 
-	public WaySegment(Way w, int i) {
-		way = w;
-		lowerIndex = i;
-	}
+    public WaySegment(Way w, int i) {
+        way = w;
+        lowerIndex = i;
+    }
 
-	@Override public boolean equals(Object o) {
-		return o != null && o instanceof WaySegment
-			&& ((WaySegment) o).way == way
-			&& ((WaySegment) o).lowerIndex == lowerIndex;
-	}
+    @Override public boolean equals(Object o) {
+        return o != null && o instanceof WaySegment
+            && ((WaySegment) o).way == way
+            && ((WaySegment) o).lowerIndex == lowerIndex;
+    }
 
-	@Override public int hashCode() {
-		return way.hashCode() ^ lowerIndex;
-	}
+    @Override public int hashCode() {
+        return way.hashCode() ^ lowerIndex;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java	(revision 1169)
@@ -9,25 +9,25 @@
 /**
  * Visitor that adds the visited object to the dataset given at constructor.
- * 
+ *
  * Is not capable of adding keys.
- * 
+ *
  * @author imi
  */
 public class AddVisitor implements Visitor {
-	
-	protected final DataSet ds;
-	
-	public AddVisitor(DataSet ds) {
-		this.ds = ds;
-	}
-	
-	public void visit(Node n) {
-		ds.nodes.add(n);
-	}
-	public void visit(Way w) {
-		ds.ways.add(w);
-	}
-	public void visit(Relation e) {
-		ds.relations.add(e);
-	}
+
+    protected final DataSet ds;
+
+    public AddVisitor(DataSet ds) {
+        this.ds = ds;
+    }
+
+    public void visit(Node n) {
+        ds.nodes.add(n);
+    }
+    public void visit(Way w) {
+        ds.ways.add(w);
+    }
+    public void visit(Relation e) {
+        ds.relations.add(e);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java	(revision 1169)
@@ -13,45 +13,45 @@
 /**
  * Collect all nodes a specific osm primitive has.
- * 
+ *
  * @author imi
  */
 public class AllNodesVisitor implements Visitor {
 
-	/**
-	 * The resulting nodes collected so far.
-	 */
-	public Collection<Node> nodes = new HashSet<Node>();
+    /**
+     * The resulting nodes collected so far.
+     */
+    public Collection<Node> nodes = new HashSet<Node>();
 
-	/**
-	 * Nodes have only itself as nodes.
-	 */
-	public void visit(Node n) {
-		nodes.add(n);
-	}
+    /**
+     * Nodes have only itself as nodes.
+     */
+    public void visit(Node n) {
+        nodes.add(n);
+    }
 
-	/**
-	 * Ways have their way nodes.
-	 */
-	public void visit(Way w) {
-		w.visitNodes(this);
-	}
+    /**
+     * Ways have their way nodes.
+     */
+    public void visit(Way w) {
+        w.visitNodes(this);
+    }
 
-	/**
-	 * Relations may have any number of nodes.
-	 * FIXME: do we want to collect nodes from segs/ways that are relation members?
-	 * if so, use AutomatchVisitor!
-	 */
-	public void visit(Relation e) {
-		for (RelationMember m : e.members)
-			if (m.member instanceof Node) visit((Node)m.member);
-	}
-	/**
-	 * @return All nodes the given primitive has.
-	 */
-	public static Collection<Node> getAllNodes(Collection<? extends OsmPrimitive> osms) {
-		AllNodesVisitor v = new AllNodesVisitor();
-		for (OsmPrimitive osm : osms)
-			osm.visit(v);
-		return v.nodes;
-	}
+    /**
+     * Relations may have any number of nodes.
+     * FIXME: do we want to collect nodes from segs/ways that are relation members?
+     * if so, use AutomatchVisitor!
+     */
+    public void visit(Relation e) {
+        for (RelationMember m : e.members)
+            if (m.member instanceof Node) visit((Node)m.member);
+    }
+    /**
+     * @return All nodes the given primitive has.
+     */
+    public static Collection<Node> getAllNodes(Collection<? extends OsmPrimitive> osms) {
+        AllNodesVisitor v = new AllNodesVisitor();
+        for (OsmPrimitive osm : osms)
+            osm.visit(v);
+        return v.nodes;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java	(revision 1169)
@@ -12,5 +12,5 @@
 
 /**
- * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the 
+ * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the
  * EastNorth values as reference.
  * @author imi
@@ -61,8 +61,8 @@
 
     /**
-     * Enlarges the calculated bounding box by 0.0001 degrees. 
+     * Enlarges the calculated bounding box by 0.0001 degrees.
      * If the bounding box has not been set (<code>min</code> or <code>max</code>
      * equal <code>null</code>) this method does not do anything.
-     *    
+     *
      * @param enlargeDegree
      */
@@ -72,8 +72,8 @@
 
     /**
-     * Enlarges the calculated bounding box by the specified number of degrees. 
+     * Enlarges the calculated bounding box by the specified number of degrees.
      * If the bounding box has not been set (<code>min</code> or <code>max</code>
      * equal <code>null</code>) this method does not do anything.
-     *    
+     *
      * @param enlargeDegree
      */
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 1169)
@@ -14,77 +14,77 @@
 /**
  * Helper that collect all ways a node is part of.
- * 
+ *
  * Deleted objects are not collected.
- * 
+ *
  * @author imi
  */
 public class CollectBackReferencesVisitor implements Visitor {
 
-	private final DataSet ds;
-	private final boolean indirectRefs;
+    private final DataSet ds;
+    private final boolean indirectRefs;
 
-	/**
-	 * The result list of primitives stored here.
-	 */
-	public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
+    /**
+     * The result list of primitives stored here.
+     */
+    public final Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
 
 
-	/**
-	 * Construct a back reference counter.
-	 * @param ds The dataset to operate on.
-	 */
-	public CollectBackReferencesVisitor(DataSet ds) {
-		this.ds = ds;
-		this.indirectRefs = true;
-	}
+    /**
+     * Construct a back reference counter.
+     * @param ds The dataset to operate on.
+     */
+    public CollectBackReferencesVisitor(DataSet ds) {
+        this.ds = ds;
+        this.indirectRefs = true;
+    }
 
-	public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
-		this.ds = ds;
-		this.indirectRefs = indirectRefs;
-	}
+    public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
+        this.ds = ds;
+        this.indirectRefs = indirectRefs;
+    }
 
-	public void visit(Node n) {
-		for (Way w : ds.ways) {
-			if (w.deleted || w.incomplete) continue;
-			for (Node n2 : w.nodes) {
-				if (n == n2) {
-					data.add(w);
-					if (indirectRefs) {
-						visit(w);
-					}
-				}
-			}
-		}
-		checkRelationMembership(n);
-	}
-	
-	public void visit(Way w) {
-		checkRelationMembership(w);
-	}
-	
-	public void visit(Relation r) {
-		checkRelationMembership(r);
-	}
-	
-	private void checkRelationMembership(OsmPrimitive p) {
-		// FIXME - this might be a candidate for optimisation 
-		// if OSM primitives are made to hold a list of back
-		// references.
-		for (Relation r : ds.relations) {
-			if (r.incomplete || r.deleted) continue;
-			for (RelationMember m : r.members) {
-				if (m.member == p) {
-					if (!data.contains(r)) {
-						data.add(r);
-						if (indirectRefs) {
-							// move up the tree (there might be relations
-							// referring to this relation)
-							checkRelationMembership(r);
-						}
-					}
-					break;
-				}
-			}
-		}
-	}
+    public void visit(Node n) {
+        for (Way w : ds.ways) {
+            if (w.deleted || w.incomplete) continue;
+            for (Node n2 : w.nodes) {
+                if (n == n2) {
+                    data.add(w);
+                    if (indirectRefs) {
+                        visit(w);
+                    }
+                }
+            }
+        }
+        checkRelationMembership(n);
+    }
+
+    public void visit(Way w) {
+        checkRelationMembership(w);
+    }
+
+    public void visit(Relation r) {
+        checkRelationMembership(r);
+    }
+
+    private void checkRelationMembership(OsmPrimitive p) {
+        // FIXME - this might be a candidate for optimisation
+        // if OSM primitives are made to hold a list of back
+        // references.
+        for (Relation r : ds.relations) {
+            if (r.incomplete || r.deleted) continue;
+            for (RelationMember m : r.members) {
+                if (m.member == p) {
+                    if (!data.contains(r)) {
+                        data.add(r);
+                        if (indirectRefs) {
+                            // move up the tree (there might be relations
+                            // referring to this relation)
+                            checkRelationMembership(r);
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/CreateOsmChangeVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/CreateOsmChangeVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/CreateOsmChangeVisitor.java	(revision 1169)
@@ -16,7 +16,7 @@
 /**
  * Creates an OsmChange document from JOSM edits.
- * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the 
+ * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the
  * OsmChange format.
- * 
+ *
  * @author fred
  *
@@ -30,14 +30,14 @@
     StringWriter swriter;
     OsmWriter osmwriter;
-    
+
     public CreateOsmChangeVisitor(Changeset changeset) {
         writer = new PrintWriter(swriter = new StringWriter());
         writer.write("<osmChange version=\"");
         writer.write(Main.pref.get("osm-server.version", "0.6"));
-        writer.write("\" generator=\"JOSM\">\n"); 
+        writer.write("\" generator=\"JOSM\">\n");
         this.changeset = changeset;
         osmwriter = new OsmWriter(writer, false, changeset);
     }
-    
+
     public void visit(Node n) {
         if (n.deleted) {
@@ -55,5 +55,5 @@
         }
     }
-    
+
     public void visit(Way w) {
         if (w.deleted) {
@@ -69,7 +69,7 @@
             switchMode((w.id == 0) ? "create" : "modify");
             w.visit(osmwriter);
-        }        
+        }
     }
-    
+
     public void visit(Relation r) {
         if (r.deleted) {
@@ -85,7 +85,7 @@
             switchMode((r.id == 0) ? "create" : "modify");
             r.visit(osmwriter);
-        }           
+        }
     }
-    
+
     private void switchMode(String newMode) {
         if ((newMode != null && !newMode.equals(currentMode))||(newMode == null && currentMode != null)) {
@@ -105,10 +105,10 @@
         }
     }
-    
+
     public String getDocument() {
         switchMode(null);
         return swriter.toString() + "</osmChange>\n";
     }
-    
+
     public Map<OsmPrimitive,Long> getNewIdMap() {
         return osmwriter.usedNewIds;
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java	(revision 1169)
@@ -9,25 +9,25 @@
 /**
  * Visitor that adds the visited object to the dataset given at constructor.
- * 
+ *
  * Is not capable of adding keys.
- * 
+ *
  * @author imi
  */
 public class DeleteVisitor implements Visitor {
-	
-	private final DataSet ds;
-	
-	public DeleteVisitor(DataSet ds) {
-		this.ds = ds;
-	}
-	
-	public void visit(Node n) {
-		ds.nodes.remove(n);
-	}
-	public void visit(Way w) {
-		ds.ways.remove(w);
-	}
-	public void visit(Relation e) {
-		ds.relations.remove(e);
-	}
+
+    private final DataSet ds;
+
+    public DeleteVisitor(DataSet ds) {
+        this.ds = ds;
+    }
+
+    public void visit(Node n) {
+        ds.nodes.remove(n);
+    }
+    public void visit(Way w) {
+        ds.ways.remove(w);
+    }
+    public void visit(Relation e) {
+        ds.relations.remove(e);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 1169)
@@ -33,357 +33,357 @@
 
 public class MapPaintVisitor extends SimplePaintVisitor {
-	protected boolean useRealWidth;
-	protected boolean zoomLevelDisplay;
-	protected boolean fillAreas;
-	protected int fillAlpha;
-	protected Color untaggedColor;
-	protected Color textColor;
-	protected boolean currentDashed = false;
-	protected int currentWidth = 0;
-	protected Stroke currentStroke = null;
-	protected Font orderFont;
-	protected ElemStyles styles;
-	protected double circum;
-	protected String regionalNameOrder[];
-
-	protected boolean isZoomOk(ElemStyle e) {
-		if (!zoomLevelDisplay) /* show everything if the user wishes so */
-			return true;
-
-		if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
-			return (circum < 1500);
-
-		// formula to calculate a map scale: natural size / map size = scale
-		// example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818
-		//
-		// so the exact "correcting value" below depends only on the screen size and resolution
-		// XXX - do we need a Preference setting for this (if things vary widely)?
-		return !(circum >= e.maxScale / 22 || circum < e.minScale / 22);
-	}
-
-	/**
-	 * Draw a small rectangle.
-	 * White if selected (as always) or red otherwise.
-	 *
-	 * @param n The node to draw.
-	 */
-	public void visit(Node n) {
-		IconElemStyle nodeStyle = styles.get(n);
-		if (nodeStyle != null && isZoomOk(nodeStyle))
-			drawNode(n, nodeStyle.icon, nodeStyle.annotate);
-		else if (n.selected)
-			drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
-		else if (n.tagged)
-			drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
-		else
-			drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
-	}
-
-	/**
-	 * Draw a line for all segments, according to tags.
-	 * @param w The way to draw.
-	 */
-	public void visit(Way w) {
-		if(w.nodes.size() < 2)
-			return;
-		// show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
-		// (even if the tag is negated as in oneway=false) or the way is selected
-		boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
-		 && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
-
-		Color color = untaggedColor;
-		int width = defaultSegmentWidth;
-		int realWidth = 0; //the real width of the element in meters
-		boolean dashed = false;
-		ElemStyle wayStyle = styles.get(w);
-
-		if(!isZoomOk(wayStyle))
-			return;
-
-		LineElemStyle l = null;
-		if(wayStyle!=null)
-		{
-			Color areacolor = untaggedColor;
-			boolean area = false;
-			if(wayStyle instanceof LineElemStyle)
-				l = (LineElemStyle)wayStyle;
-			else if (wayStyle instanceof AreaElemStyle)
-			{
-				areacolor = ((AreaElemStyle)wayStyle).color;
-				color = areacolor;
-				l = ((AreaElemStyle)wayStyle).line;
-				area = true;
-			}
-			if(l != null)
-			{
-				color = l.color;
-				width = l.width;
-				realWidth = l.realWidth;
-				dashed = l.dashed;
-			}
-			if (area && fillAreas)
-				drawWayAsArea(w, areacolor);
-		}
-
-		if (realWidth > 0 && useRealWidth && !showDirection)
-		{
-			int tmpWidth = (int) (100 /  (float) (circum / realWidth));
-			if (tmpWidth > width) width = tmpWidth;
-		}
-		if(w.selected)
-			color = selectedColor;
-
-		Node lastN;
-		if(l != null && l.overlays != null)
-		{
-			for(LineElemStyle s : l.overlays)
-			{
-				if(!s.over)
-				{
-					lastN = null;
-					for(Node n : w.nodes)
-					{
-						if(lastN != null)
-						{
-							drawSeg(lastN, n, s.color != null  && !w.selected ? s.color : color,
-							false, s.getWidth(width), s.dashed);
-						}
-						lastN = n;
-					}
-				}
-			}
-		}
-
-		lastN = null;
-		for(Node n : w.nodes)
-		{
-			if(lastN != null)
-				drawSeg(lastN, n, color, showDirection, width, dashed);
-			lastN = n;
-		}
-
-		if(l != null && l.overlays != null)
-		{
-			for(LineElemStyle s : l.overlays)
-			{
-				if(s.over)
-				{
-					lastN = null;
-					for(Node n : w.nodes)
-					{
-						if(lastN != null)
-						{
-							drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
-							false, s.getWidth(width), s.dashed);
-						}
-						lastN = n;
-					}
-				}
-			}
-		}
-
-		if(showOrderNumber)
-		{
-			int orderNumber = 0;
-			lastN = null;
-			for(Node n : w.nodes)
-			{
-				if(lastN != null)
-				{
-					orderNumber++;
-					drawOrderNumber(lastN, n, orderNumber);
-				}
-				lastN = n;
-			}
-		}
-		displaySegments();
-	}
-
-	public void visit(Relation e) {
-		// relations are not (yet?) drawn.
-	}
-
-	// This assumes that all segments are aligned in the same direction!
-	protected void drawWayAsArea(Way w, Color color)
-	{
-		Polygon polygon = new Polygon();
-
-		for (Node n : w.nodes)
-		{
-			Point p = nc.getPoint(n.eastNorth);
-			polygon.addPoint(p.x,p.y);
-		}
-
-		Color mycolor = w.selected ? selectedColor : color;
-		// set the opacity (alpha) level of the filled polygon
-		g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha));
-
-		g.fillPolygon(polygon);
-	}
-
-	// NEW
-	protected void drawNode(Node n, ImageIcon icon, boolean annotate) {
-		Point p = nc.getPoint(n.eastNorth);
-		if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
-		int w = icon.getIconWidth(), h=icon.getIconHeight();
-		icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
-		String name = getNodeName(n);
-		if (name!=null && annotate)
-		{
-			g.setColor(textColor);
-			Font defaultFont = g.getFont();
-			g.setFont (orderFont);
-			g.drawString (name, p.x+w/2+2, p.y+h/2+2);
-			g.setFont(defaultFont);
-		}
-		if (n.selected)
-		{
-			g.setColor (  selectedColor );
-			g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4);
-		}
-	}
-
-	protected String getNodeName(Node n) {
-		String name = null;
-		if (n.keys != null) {
-			for (int i = 0; i < regionalNameOrder.length; i++) {
-				name = n.keys.get(regionalNameOrder[i]);
-				if (name != null) break;
-			}
-		}
-		return name;
-	}
-
-	private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) {
-		if (col != currentColor || width != currentWidth || dashed != currentDashed) {
-			displaySegments(col, width, dashed);
-		}
-		Point p1 = nc.getPoint(n1.eastNorth);
-		Point p2 = nc.getPoint(n2.eastNorth);
-
-		if (!isSegmentVisible(p1, p2)) {
-			return;
-		}
-		currentPath.moveTo(p1.x, p1.y);
-		currentPath.lineTo(p2.x, p2.y);
-
-		if (showDirection) {
-			double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
-			currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
-			currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
-			currentPath.lineTo(p2.x, p2.y);
-		}
-	}
-
-	protected void displaySegments() {
-		displaySegments(null, 0, false);
-	}
-
-	protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
-		if (currentPath != null) {
-			Graphics2D g2d = (Graphics2D)g;
-			g2d.setColor(inactive ? inactiveColor : currentColor);
-			if (currentStroke == null) {
-				if (currentDashed)
-					g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
-				else
-					g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
-			}
-			g2d.draw(currentPath);
-			g2d.setStroke(new BasicStroke(1));
-
-			currentPath = new GeneralPath();
-			currentColor = newColor;
-			currentWidth = newWidth;
-			currentDashed = newDash;
-			currentStroke = null;
-		}
-	}
-
-	/**
-	 * Draw the node as small rectangle with the given color.
-	 *
-	 * @param n  The node to draw.
-	 * @param color The color of the node.
-	 */
-	public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
-		if (isZoomOk(null) && size > 1) {
-			Point p = nc.getPoint(n.eastNorth);
-			if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
-					|| (p.y > nc.getHeight()))
-				return;
-			g.setColor(color);
-			if (fill) {
-				g.fillRect(p.x - radius, p.y - radius, size, size);
-				g.drawRect(p.x - radius, p.y - radius, size, size);
-			} else
-				g.drawRect(p.x - radius, p.y - radius, size, size);
-		}
-	}
-
-	// NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
-	// Shows areas before non-areas
-	public void visitAll(DataSet data, Boolean virtual) {
-		getSettings(virtual);
-		untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
-		textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
-		useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
-		zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
-		fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
-		fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
-		circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
-		styles = MapPaintStyles.getStyles();
-		orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
-		String currentLocale = Locale.getDefault().getLanguage();
-		regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
-
-		if (styles.hasAreas()) {
-			Collection<Way> noAreaWays = new LinkedList<Way>();
-
-			for (final OsmPrimitive osm : data.ways)
-				if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
-					osm.visit(this);
-				else if (!osm.deleted && !osm.incomplete)
-					noAreaWays.add((Way)osm);
-
-			for (final OsmPrimitive osm : noAreaWays)
-				osm.visit(this);
-		}
-		else
-		{
-			for (final OsmPrimitive osm : data.ways)
-				if (!osm.incomplete && !osm.deleted)
-					osm.visit(this);
-		}
-
-		for (final OsmPrimitive osm : data.getSelected())
-			if (!osm.incomplete && !osm.deleted){
-				osm.visit(this);
-			}
-
-		displaySegments();
-
-		for (final OsmPrimitive osm : data.nodes)
-			if (!osm.incomplete && !osm.deleted)
-				osm.visit(this);
-
-		if (virtualNodeSize != 0)
-		{
-			currentColor = nodeColor;
-			for (final OsmPrimitive osm : data.ways)
-				if (!osm.deleted)
-					visitVirtual((Way)osm);
-			displaySegments(null);
-		}
-	}
-
-	/**
-	 * Draw a number of the order of the two consecutive nodes within the
-	 * parents way
-	 */
-	protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
-		Point p1 = nc.getPoint(n1.eastNorth);
-		Point p2 = nc.getPoint(n2.eastNorth);
-		drawOrderNumber(p1, p2, orderNumber);
-	}
+    protected boolean useRealWidth;
+    protected boolean zoomLevelDisplay;
+    protected boolean fillAreas;
+    protected int fillAlpha;
+    protected Color untaggedColor;
+    protected Color textColor;
+    protected boolean currentDashed = false;
+    protected int currentWidth = 0;
+    protected Stroke currentStroke = null;
+    protected Font orderFont;
+    protected ElemStyles styles;
+    protected double circum;
+    protected String regionalNameOrder[];
+
+    protected boolean isZoomOk(ElemStyle e) {
+        if (!zoomLevelDisplay) /* show everything if the user wishes so */
+            return true;
+
+        if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
+            return (circum < 1500);
+
+        // formula to calculate a map scale: natural size / map size = scale
+        // example: 876000mm (876m as displayed) / 22mm (roughly estimated screen size of legend bar) = 39818
+        //
+        // so the exact "correcting value" below depends only on the screen size and resolution
+        // XXX - do we need a Preference setting for this (if things vary widely)?
+        return !(circum >= e.maxScale / 22 || circum < e.minScale / 22);
+    }
+
+    /**
+     * Draw a small rectangle.
+     * White if selected (as always) or red otherwise.
+     *
+     * @param n The node to draw.
+     */
+    public void visit(Node n) {
+        IconElemStyle nodeStyle = styles.get(n);
+        if (nodeStyle != null && isZoomOk(nodeStyle))
+            drawNode(n, nodeStyle.icon, nodeStyle.annotate);
+        else if (n.selected)
+            drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
+        else if (n.tagged)
+            drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
+        else
+            drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
+    }
+
+    /**
+     * Draw a line for all segments, according to tags.
+     * @param w The way to draw.
+     */
+    public void visit(Way w) {
+        if(w.nodes.size() < 2)
+            return;
+        // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
+        // (even if the tag is negated as in oneway=false) or the way is selected
+        boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
+         && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
+
+        Color color = untaggedColor;
+        int width = defaultSegmentWidth;
+        int realWidth = 0; //the real width of the element in meters
+        boolean dashed = false;
+        ElemStyle wayStyle = styles.get(w);
+
+        if(!isZoomOk(wayStyle))
+            return;
+
+        LineElemStyle l = null;
+        if(wayStyle!=null)
+        {
+            Color areacolor = untaggedColor;
+            boolean area = false;
+            if(wayStyle instanceof LineElemStyle)
+                l = (LineElemStyle)wayStyle;
+            else if (wayStyle instanceof AreaElemStyle)
+            {
+                areacolor = ((AreaElemStyle)wayStyle).color;
+                color = areacolor;
+                l = ((AreaElemStyle)wayStyle).line;
+                area = true;
+            }
+            if(l != null)
+            {
+                color = l.color;
+                width = l.width;
+                realWidth = l.realWidth;
+                dashed = l.dashed;
+            }
+            if (area && fillAreas)
+                drawWayAsArea(w, areacolor);
+        }
+
+        if (realWidth > 0 && useRealWidth && !showDirection)
+        {
+            int tmpWidth = (int) (100 /  (float) (circum / realWidth));
+            if (tmpWidth > width) width = tmpWidth;
+        }
+        if(w.selected)
+            color = selectedColor;
+
+        Node lastN;
+        if(l != null && l.overlays != null)
+        {
+            for(LineElemStyle s : l.overlays)
+            {
+                if(!s.over)
+                {
+                    lastN = null;
+                    for(Node n : w.nodes)
+                    {
+                        if(lastN != null)
+                        {
+                            drawSeg(lastN, n, s.color != null  && !w.selected ? s.color : color,
+                            false, s.getWidth(width), s.dashed);
+                        }
+                        lastN = n;
+                    }
+                }
+            }
+        }
+
+        lastN = null;
+        for(Node n : w.nodes)
+        {
+            if(lastN != null)
+                drawSeg(lastN, n, color, showDirection, width, dashed);
+            lastN = n;
+        }
+
+        if(l != null && l.overlays != null)
+        {
+            for(LineElemStyle s : l.overlays)
+            {
+                if(s.over)
+                {
+                    lastN = null;
+                    for(Node n : w.nodes)
+                    {
+                        if(lastN != null)
+                        {
+                            drawSeg(lastN, n, s.color != null && !w.selected ? s.color : color,
+                            false, s.getWidth(width), s.dashed);
+                        }
+                        lastN = n;
+                    }
+                }
+            }
+        }
+
+        if(showOrderNumber)
+        {
+            int orderNumber = 0;
+            lastN = null;
+            for(Node n : w.nodes)
+            {
+                if(lastN != null)
+                {
+                    orderNumber++;
+                    drawOrderNumber(lastN, n, orderNumber);
+                }
+                lastN = n;
+            }
+        }
+        displaySegments();
+    }
+
+    public void visit(Relation e) {
+        // relations are not (yet?) drawn.
+    }
+
+    // This assumes that all segments are aligned in the same direction!
+    protected void drawWayAsArea(Way w, Color color)
+    {
+        Polygon polygon = new Polygon();
+
+        for (Node n : w.nodes)
+        {
+            Point p = nc.getPoint(n.eastNorth);
+            polygon.addPoint(p.x,p.y);
+        }
+
+        Color mycolor = w.selected ? selectedColor : color;
+        // set the opacity (alpha) level of the filled polygon
+        g.setColor(new Color( mycolor.getRed(), mycolor.getGreen(), mycolor.getBlue(), fillAlpha));
+
+        g.fillPolygon(polygon);
+    }
+
+    // NEW
+    protected void drawNode(Node n, ImageIcon icon, boolean annotate) {
+        Point p = nc.getPoint(n.eastNorth);
+        if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
+        int w = icon.getIconWidth(), h=icon.getIconHeight();
+        icon.paintIcon ( Main.map.mapView, g, p.x-w/2, p.y-h/2 );
+        String name = getNodeName(n);
+        if (name!=null && annotate)
+        {
+            g.setColor(textColor);
+            Font defaultFont = g.getFont();
+            g.setFont (orderFont);
+            g.drawString (name, p.x+w/2+2, p.y+h/2+2);
+            g.setFont(defaultFont);
+        }
+        if (n.selected)
+        {
+            g.setColor (  selectedColor );
+            g.drawRect (p.x-w/2-2,p.y-w/2-2, w+4, h+4);
+        }
+    }
+
+    protected String getNodeName(Node n) {
+        String name = null;
+        if (n.keys != null) {
+            for (int i = 0; i < regionalNameOrder.length; i++) {
+                name = n.keys.get(regionalNameOrder[i]);
+                if (name != null) break;
+            }
+        }
+        return name;
+    }
+
+    private void drawSeg(Node n1, Node n2, Color col, boolean showDirection, int width, boolean dashed) {
+        if (col != currentColor || width != currentWidth || dashed != currentDashed) {
+            displaySegments(col, width, dashed);
+        }
+        Point p1 = nc.getPoint(n1.eastNorth);
+        Point p2 = nc.getPoint(n2.eastNorth);
+
+        if (!isSegmentVisible(p1, p2)) {
+            return;
+        }
+        currentPath.moveTo(p1.x, p1.y);
+        currentPath.lineTo(p2.x, p2.y);
+
+        if (showDirection) {
+            double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
+            currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
+            currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
+            currentPath.lineTo(p2.x, p2.y);
+        }
+    }
+
+    protected void displaySegments() {
+        displaySegments(null, 0, false);
+    }
+
+    protected void displaySegments(Color newColor, int newWidth, boolean newDash) {
+        if (currentPath != null) {
+            Graphics2D g2d = (Graphics2D)g;
+            g2d.setColor(inactive ? inactiveColor : currentColor);
+            if (currentStroke == null) {
+                if (currentDashed)
+                    g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0,new float[] {9},0));
+                else
+                    g2d.setStroke(new BasicStroke(currentWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
+            }
+            g2d.draw(currentPath);
+            g2d.setStroke(new BasicStroke(1));
+
+            currentPath = new GeneralPath();
+            currentColor = newColor;
+            currentWidth = newWidth;
+            currentDashed = newDash;
+            currentStroke = null;
+        }
+    }
+
+    /**
+     * Draw the node as small rectangle with the given color.
+     *
+     * @param n  The node to draw.
+     * @param color The color of the node.
+     */
+    public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
+        if (isZoomOk(null) && size > 1) {
+            Point p = nc.getPoint(n.eastNorth);
+            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
+                    || (p.y > nc.getHeight()))
+                return;
+            g.setColor(color);
+            if (fill) {
+                g.fillRect(p.x - radius, p.y - radius, size, size);
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+            } else
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+        }
+    }
+
+    // NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
+    // Shows areas before non-areas
+    public void visitAll(DataSet data, Boolean virtual) {
+        getSettings(virtual);
+        untaggedColor = Main.pref.getColor(marktr("untagged"),Color.GRAY);
+        textColor = Main.pref.getColor (marktr("text"), Color.WHITE);
+        useRealWidth = Main.pref.getBoolean("mappaint.useRealWidth",false);
+        zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay",false);
+        fillAreas = Main.pref.getBoolean("mappaint.fillareas", true);
+        fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50))));
+        circum = Main.map.mapView.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
+        styles = MapPaintStyles.getStyles();
+        orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
+        String currentLocale = Locale.getDefault().getLanguage();
+        regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
+
+        if (styles.hasAreas()) {
+            Collection<Way> noAreaWays = new LinkedList<Way>();
+
+            for (final OsmPrimitive osm : data.ways)
+                if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
+                    osm.visit(this);
+                else if (!osm.deleted && !osm.incomplete)
+                    noAreaWays.add((Way)osm);
+
+            for (final OsmPrimitive osm : noAreaWays)
+                osm.visit(this);
+        }
+        else
+        {
+            for (final OsmPrimitive osm : data.ways)
+                if (!osm.incomplete && !osm.deleted)
+                    osm.visit(this);
+        }
+
+        for (final OsmPrimitive osm : data.getSelected())
+            if (!osm.incomplete && !osm.deleted){
+                osm.visit(this);
+            }
+
+        displaySegments();
+
+        for (final OsmPrimitive osm : data.nodes)
+            if (!osm.incomplete && !osm.deleted)
+                osm.visit(this);
+
+        if (virtualNodeSize != 0)
+        {
+            currentColor = nodeColor;
+            for (final OsmPrimitive osm : data.ways)
+                if (!osm.deleted)
+                    visitVirtual((Way)osm);
+            displaySegments(null);
+        }
+    }
+
+    /**
+     * Draw a number of the order of the two consecutive nodes within the
+     * parents way
+     */
+    protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
+        Point p1 = nc.getPoint(n1.eastNorth);
+        Point p2 = nc.getPoint(n2.eastNorth);
+        drawOrderNumber(p1, p2, orderNumber);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 1169)
@@ -19,261 +19,261 @@
  * A visitor that get a data set at construction time and merge every visited object
  * into it.
- * 
+ *
  * @author imi
  */
 public class MergeVisitor implements Visitor {
 
-	/**
-	 * Map from primitives in the database to visited primitives. (Attention: The other way 
-	 * round than merged)
-	 */
-	public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
-
-	private final DataSet ds;
-	private final DataSet mergeds;
-
-	private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>();
-	private final HashMap<Long, Way> wayshash = new HashMap<Long, Way>();
-	private final HashMap<Long, Relation> relshash = new HashMap<Long, Relation>();
-
-	/**
-	 * A list of all primitives that got replaced with other primitives.
-	 * Key is the primitives in the other's dataset and the value is the one that is now
-	 * in ds.nodes instead.
-	 */
-	private final Map<OsmPrimitive, OsmPrimitive> merged
-		= new HashMap<OsmPrimitive, OsmPrimitive>();
-
-	public MergeVisitor(DataSet ds, DataSet mergeds) {
-		this.ds = ds;
-		this.mergeds = mergeds;
-
-		for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n);
-		for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w);
-		for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r);
-	}
-
-	private <P extends OsmPrimitive> void genMerge(P other,
-			Collection<P> myprims, Collection<P> mergeprims,
-			HashMap<Long, P> primhash) {
-		// 1. Try to find an identical prim with the same id.
-		if (mergeAfterId(myprims, primhash, other))
-			return;
-
-		// 2. Try to find a prim we can merge with the prim from the other ds.
-		for (P my : myprims) {
-			// LinkedList.contains calls equal, and OsmPrimitive.equal
-			// compares just the id.
-			if (match(my, other) && !mergeprims.contains(my)) {
-				merged.put(other, my);
-				mergeCommon(my, other);
-				return;
-			}
-		}
-
-		// 3. No idea how to merge that.  Simply add it unchanged.
-		myprims.add(other);
-	}
-
-	public void visit(Node other) {
-		genMerge(other, ds.nodes, mergeds.nodes, nodeshash);
-	}
-
-	public void visit(Way other) {
-		fixWay(other);
-		genMerge(other, ds.ways, mergeds.ways, wayshash);
-	}
-
-	public void visit(Relation other) {
-		fixRelation(other);
-		genMerge(other, ds.relations, mergeds.relations, relshash);
-	}
-
-	/**
-	 * Postprocess the dataset and fix all merged references to point to the actual
-	 * data.
-	 */
-	public void fixReferences() {
-		for (Way w : ds.ways) fixWay(w);
-		for (Relation r : ds.relations) fixRelation(r);
-		for (OsmPrimitive osm : conflicts.values())
-			if (osm instanceof Way)
-				fixWay((Way)osm);
-			else if (osm instanceof Relation)
-				fixRelation((Relation) osm);
-	}
-
-	private void fixWay(Way w) {
-	    boolean replacedSomething = false;
-	    LinkedList<Node> newNodes = new LinkedList<Node>();
-	    for (Node n : w.nodes) {
-	    	Node otherN = (Node) merged.get(n);
-	    	newNodes.add(otherN == null ? n : otherN);
-	    	if (otherN != null)
-	    		replacedSomething = true;
-	    }
-	    if (replacedSomething) {
-	    	w.nodes.clear();
-	    	w.nodes.addAll(newNodes);
-		}
-    }
-
-	private void fixRelation(Relation r) {
-	    boolean replacedSomething = false;
-	    LinkedList<RelationMember> newMembers = new LinkedList<RelationMember>();
-	    for (RelationMember m : r.members) {
-	    	OsmPrimitive otherP = merged.get(m.member);
-			if (otherP == null) {
-				newMembers.add(m);
-			} else {
-				RelationMember mnew = new RelationMember(m);
-				mnew.member = otherP;
-				newMembers.add(mnew);
-	    		replacedSomething = true;
-			}
-	    }
-	    if (replacedSomething) {
-	    	r.members.clear();
-	    	r.members.addAll(newMembers);
-		}
-	}
-
-	private static <P extends OsmPrimitive> boolean match(P p1, P p2) {
-		if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) {
-			return realMatch(p1, p2);
-		}
-		return p1.id == p2.id;
-	}
-
-	/** @return true if the prims have pretty much the same data, i.e. the
-	 * same position, the same members, ...
-	 */
-	// Java cannot dispatch on generics...
-	private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) {
-		if (p1 instanceof Node && p2 instanceof Node) {
-			return realMatch((Node) p1, (Node) p2);
-		} else if (p1 instanceof Way && p2 instanceof Way) {
-			return realMatch((Way) p1, (Way) p2);
-		} else if (p1 instanceof Relation && p2 instanceof Relation) {
-			return realMatch((Relation) p1, (Relation) p2);
-		} else {
-			throw new RuntimeException("arguments have unknown type");
-		}
-	}
-
-	private static boolean realMatch(Node n1, Node n2) {
-		return n1.coor.equalsEpsilon(n2.coor);
-	}
-
-	private static boolean realMatch(Way w1, Way w2) {
-		if (w1.nodes.size() != w2.nodes.size())
-			return false;
-		Iterator<Node> it = w1.nodes.iterator();
-		for (Node n : w2.nodes)
-			if (!match(n, it.next()))
-				return false;
-		return true;
-	}
-
-	private static boolean realMatch(Relation w1, Relation w2) {
-		// FIXME this is not perfect yet...
-		if (w1.members.size() != w2.members.size())
-			return false;
-		for (RelationMember em : w1.members) {
-			if (!w2.members.contains(em)) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Merge the common parts of an osm primitive.
-	 * @param my The object, the information gets merged into
-	 * @param other The object, the information gets merged from
-	 */
-	private void mergeCommon(OsmPrimitive my, OsmPrimitive other) {
-		if (other.deleted)
-			my.delete(true);
-		if (my.id == 0 || !my.modified || other.modified) {
-			if (my.id == 0 && other.id != 0) {
-				my.id = other.id;
-				my.modified = other.modified; // match a new node
-			} else if (my.id != 0 && other.id != 0 && other.modified)
-				my.modified = true;
-		}
-		if (other.keys == null)
-			return;
-		if (my.keySet().containsAll(other.keys.keySet()))
-			return;
-		if (my.keys == null)
-			my.keys = other.keys;
-		else
-			my.keys.putAll(other.keys);
-		
-		my.modified = true;
-	}
-
-	/**
-	 * @return <code>true</code>, if no merge is needed or merge is performed already.
-	 */
-	private <P extends OsmPrimitive> boolean mergeAfterId(
-			Collection<P> primitives, HashMap<Long, P> hash, P other) {
-		// Fast-path merging of identical objects
-		if (hash.containsKey(other.id)) {
-			P my = hash.get(other.id);
-			if (my.realEqual(other, true)) {
-				merged.put(other, my);
-				return true;
-			}
-		}
-
-		for (P my : primitives) {
-			if (my.realEqual(other, false)) {
-				merged.put(other, my);
-				return true; // no merge needed.
-			}
-			if (my.realEqual(other, true)) {
-				Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
-				Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
-
-				// they differ in modified/timestamp combination only. Auto-resolve it.
-				merged.put(other, my);
-				if (myd.before(otherd)) {
-					my.modified = other.modified;
-					my.timestamp = other.timestamp;
-				}
-				return true; // merge done.
-			}
-			if (my.id == other.id && my.id != 0) {
-				Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
-				Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
-
-				if (my.incomplete || other.incomplete) {
-					if (my.incomplete) {
-						my.cloneFrom(other);
-					}
-				} else if (my.modified && other.modified) {
-					conflicts.put(my, other);
-				} else if (!my.modified && !other.modified) {
-					if (myd.before(otherd)) {
-						my.cloneFrom(other);
-					}
-				} else if (other.modified) {
-					if (myd.after(otherd)) {
-						conflicts.put(my, other);
-					} else {
-						my.cloneFrom(other);
-					}
-				} else if (my.modified) {
-					if (myd.before(otherd)) {
-						conflicts.put(my, other);
-					}
-				}
-				merged.put(other, my);
-				return true;
-			}
-		}
-		return false;
-	}
+    /**
+     * Map from primitives in the database to visited primitives. (Attention: The other way
+     * round than merged)
+     */
+    public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
+
+    private final DataSet ds;
+    private final DataSet mergeds;
+
+    private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>();
+    private final HashMap<Long, Way> wayshash = new HashMap<Long, Way>();
+    private final HashMap<Long, Relation> relshash = new HashMap<Long, Relation>();
+
+    /**
+     * A list of all primitives that got replaced with other primitives.
+     * Key is the primitives in the other's dataset and the value is the one that is now
+     * in ds.nodes instead.
+     */
+    private final Map<OsmPrimitive, OsmPrimitive> merged
+        = new HashMap<OsmPrimitive, OsmPrimitive>();
+
+    public MergeVisitor(DataSet ds, DataSet mergeds) {
+        this.ds = ds;
+        this.mergeds = mergeds;
+
+        for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n);
+        for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w);
+        for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r);
+    }
+
+    private <P extends OsmPrimitive> void genMerge(P other,
+            Collection<P> myprims, Collection<P> mergeprims,
+            HashMap<Long, P> primhash) {
+        // 1. Try to find an identical prim with the same id.
+        if (mergeAfterId(myprims, primhash, other))
+            return;
+
+        // 2. Try to find a prim we can merge with the prim from the other ds.
+        for (P my : myprims) {
+            // LinkedList.contains calls equal, and OsmPrimitive.equal
+            // compares just the id.
+            if (match(my, other) && !mergeprims.contains(my)) {
+                merged.put(other, my);
+                mergeCommon(my, other);
+                return;
+            }
+        }
+
+        // 3. No idea how to merge that.  Simply add it unchanged.
+        myprims.add(other);
+    }
+
+    public void visit(Node other) {
+        genMerge(other, ds.nodes, mergeds.nodes, nodeshash);
+    }
+
+    public void visit(Way other) {
+        fixWay(other);
+        genMerge(other, ds.ways, mergeds.ways, wayshash);
+    }
+
+    public void visit(Relation other) {
+        fixRelation(other);
+        genMerge(other, ds.relations, mergeds.relations, relshash);
+    }
+
+    /**
+     * Postprocess the dataset and fix all merged references to point to the actual
+     * data.
+     */
+    public void fixReferences() {
+        for (Way w : ds.ways) fixWay(w);
+        for (Relation r : ds.relations) fixRelation(r);
+        for (OsmPrimitive osm : conflicts.values())
+            if (osm instanceof Way)
+                fixWay((Way)osm);
+            else if (osm instanceof Relation)
+                fixRelation((Relation) osm);
+    }
+
+    private void fixWay(Way w) {
+        boolean replacedSomething = false;
+        LinkedList<Node> newNodes = new LinkedList<Node>();
+        for (Node n : w.nodes) {
+            Node otherN = (Node) merged.get(n);
+            newNodes.add(otherN == null ? n : otherN);
+            if (otherN != null)
+                replacedSomething = true;
+        }
+        if (replacedSomething) {
+            w.nodes.clear();
+            w.nodes.addAll(newNodes);
+        }
+    }
+
+    private void fixRelation(Relation r) {
+        boolean replacedSomething = false;
+        LinkedList<RelationMember> newMembers = new LinkedList<RelationMember>();
+        for (RelationMember m : r.members) {
+            OsmPrimitive otherP = merged.get(m.member);
+            if (otherP == null) {
+                newMembers.add(m);
+            } else {
+                RelationMember mnew = new RelationMember(m);
+                mnew.member = otherP;
+                newMembers.add(mnew);
+                replacedSomething = true;
+            }
+        }
+        if (replacedSomething) {
+            r.members.clear();
+            r.members.addAll(newMembers);
+        }
+    }
+
+    private static <P extends OsmPrimitive> boolean match(P p1, P p2) {
+        if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) {
+            return realMatch(p1, p2);
+        }
+        return p1.id == p2.id;
+    }
+
+    /** @return true if the prims have pretty much the same data, i.e. the
+     * same position, the same members, ...
+     */
+    // Java cannot dispatch on generics...
+    private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) {
+        if (p1 instanceof Node && p2 instanceof Node) {
+            return realMatch((Node) p1, (Node) p2);
+        } else if (p1 instanceof Way && p2 instanceof Way) {
+            return realMatch((Way) p1, (Way) p2);
+        } else if (p1 instanceof Relation && p2 instanceof Relation) {
+            return realMatch((Relation) p1, (Relation) p2);
+        } else {
+            throw new RuntimeException("arguments have unknown type");
+        }
+    }
+
+    private static boolean realMatch(Node n1, Node n2) {
+        return n1.coor.equalsEpsilon(n2.coor);
+    }
+
+    private static boolean realMatch(Way w1, Way w2) {
+        if (w1.nodes.size() != w2.nodes.size())
+            return false;
+        Iterator<Node> it = w1.nodes.iterator();
+        for (Node n : w2.nodes)
+            if (!match(n, it.next()))
+                return false;
+        return true;
+    }
+
+    private static boolean realMatch(Relation w1, Relation w2) {
+        // FIXME this is not perfect yet...
+        if (w1.members.size() != w2.members.size())
+            return false;
+        for (RelationMember em : w1.members) {
+            if (!w2.members.contains(em)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Merge the common parts of an osm primitive.
+     * @param my The object, the information gets merged into
+     * @param other The object, the information gets merged from
+     */
+    private void mergeCommon(OsmPrimitive my, OsmPrimitive other) {
+        if (other.deleted)
+            my.delete(true);
+        if (my.id == 0 || !my.modified || other.modified) {
+            if (my.id == 0 && other.id != 0) {
+                my.id = other.id;
+                my.modified = other.modified; // match a new node
+            } else if (my.id != 0 && other.id != 0 && other.modified)
+                my.modified = true;
+        }
+        if (other.keys == null)
+            return;
+        if (my.keySet().containsAll(other.keys.keySet()))
+            return;
+        if (my.keys == null)
+            my.keys = other.keys;
+        else
+            my.keys.putAll(other.keys);
+
+        my.modified = true;
+    }
+
+    /**
+     * @return <code>true</code>, if no merge is needed or merge is performed already.
+     */
+    private <P extends OsmPrimitive> boolean mergeAfterId(
+            Collection<P> primitives, HashMap<Long, P> hash, P other) {
+        // Fast-path merging of identical objects
+        if (hash.containsKey(other.id)) {
+            P my = hash.get(other.id);
+            if (my.realEqual(other, true)) {
+                merged.put(other, my);
+                return true;
+            }
+        }
+
+        for (P my : primitives) {
+            if (my.realEqual(other, false)) {
+                merged.put(other, my);
+                return true; // no merge needed.
+            }
+            if (my.realEqual(other, true)) {
+                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
+                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
+
+                // they differ in modified/timestamp combination only. Auto-resolve it.
+                merged.put(other, my);
+                if (myd.before(otherd)) {
+                    my.modified = other.modified;
+                    my.timestamp = other.timestamp;
+                }
+                return true; // merge done.
+            }
+            if (my.id == other.id && my.id != 0) {
+                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
+                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
+
+                if (my.incomplete || other.incomplete) {
+                    if (my.incomplete) {
+                        my.cloneFrom(other);
+                    }
+                } else if (my.modified && other.modified) {
+                    conflicts.put(my, other);
+                } else if (!my.modified && !other.modified) {
+                    if (myd.before(otherd)) {
+                        my.cloneFrom(other);
+                    }
+                } else if (other.modified) {
+                    if (myd.after(otherd)) {
+                        conflicts.put(my, other);
+                    } else {
+                        my.cloneFrom(other);
+                    }
+                } else if (my.modified) {
+                    if (myd.before(otherd)) {
+                        conflicts.put(my, other);
+                    }
+                }
+                merged.put(other, my);
+                return true;
+            }
+        }
+        return false;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java	(revision 1169)
@@ -17,65 +17,65 @@
 /**
  * Able to create a name and an icon for each data element.
- * 
+ *
  * @author imi
  */
 public class NameVisitor implements Visitor {
 
-	/**
-	 * The name of the item class
-	 */
-	public String className;
-	public String classNamePlural;
-	/**
-	 * The name of this item.
-	 */
-	public String name;
-	/**
-	 * The icon of this item.
-	 */
-	public Icon icon;
-	
-	/**
-	 * If the node has a name-key or id-key, this is displayed. If not, (lat,lon)
-	 * is displayed.
-	 */
-	public void visit(Node n) {
-		name = n.getName();
-		addId(n);
-		icon = ImageProvider.get("data", "node");
-		className = "node";
-		classNamePlural = trn("node", "nodes", 2);
-	}
+    /**
+     * The name of the item class
+     */
+    public String className;
+    public String classNamePlural;
+    /**
+     * The name of this item.
+     */
+    public String name;
+    /**
+     * The icon of this item.
+     */
+    public Icon icon;
 
-	/**
-	 * If the way has a name-key or id-key, this is displayed. If not, (x nodes)
-	 * is displayed with x being the number of nodes in the way.
-	 */
-	public void visit(Way w) {
-		name = w.getName();
-		addId(w);
-		icon = ImageProvider.get("data", "way");
-		className = "way";
-		classNamePlural = trn("way", "ways", 2);
-	}
-	
-	/**
-	 */
-	public void visit(Relation e) {
-		name = e.getName();
-		addId(e);
-		icon = ImageProvider.get("data", "relation");
-		className = "relation";
-		classNamePlural = trn("relation", "relations", 2);
-	}
-	
-	public JLabel toLabel() {
-		return new JLabel(name, icon, JLabel.HORIZONTAL);
-	}
+    /**
+     * If the node has a name-key or id-key, this is displayed. If not, (lat,lon)
+     * is displayed.
+     */
+    public void visit(Node n) {
+        name = n.getName();
+        addId(n);
+        icon = ImageProvider.get("data", "node");
+        className = "node";
+        classNamePlural = trn("node", "nodes", 2);
+    }
+
+    /**
+     * If the way has a name-key or id-key, this is displayed. If not, (x nodes)
+     * is displayed with x being the number of nodes in the way.
+     */
+    public void visit(Way w) {
+        name = w.getName();
+        addId(w);
+        icon = ImageProvider.get("data", "way");
+        className = "way";
+        classNamePlural = trn("way", "ways", 2);
+    }
+
+    /**
+     */
+    public void visit(Relation e) {
+        name = e.getName();
+        addId(e);
+        icon = ImageProvider.get("data", "relation");
+        className = "relation";
+        classNamePlural = trn("relation", "relations", 2);
+    }
+
+    public JLabel toLabel() {
+        return new JLabel(name, icon, JLabel.HORIZONTAL);
+    }
 
 
-	private void addId(OsmPrimitive osm) {
-	    if (Main.pref.getBoolean("osm-primitives.showid"))
-			name += tr(" [id: {0}]", osm.id);
+    private void addId(OsmPrimitive osm) {
+        if (Main.pref.getBoolean("osm-primitives.showid"))
+            name += tr(" [id: {0}]", osm.id);
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 1169)
@@ -32,342 +32,342 @@
 public class SimplePaintVisitor implements Visitor {
 
-	public final static Color darkerblue = new Color(0,0,96);
-	public final static Color darkblue = new Color(0,0,128);
-	public final static Color darkgreen = new Color(0,128,0);
-	public final static Color teal = new Color(0,128,128);
-
-	/**
-	 * The environment to paint to.
-	 */
-	protected Graphics g;
-	/**
-	 * MapView to get screen coordinates.
-	 */
-	protected NavigatableComponent nc;
-
-	public boolean inactive;
-
-	protected static final double PHI = Math.toRadians(20);
-
-	/**
-	 * Preferences
-	*/
-	protected Color inactiveColor;
-	protected Color selectedColor;
-	protected Color nodeColor;
-	protected Color dfltWayColor;
-	protected Color relationColor;
-	protected Color untaggedWayColor;
-	protected Color incompleteColor;
-	protected Color backgroundColor;
-	protected boolean showDirectionArrow;
-	protected boolean showRelevantDirectionsOnly;
-	protected boolean showOrderNumber;
-	protected boolean fillSelectedNode;
-	protected boolean fillUnselectedNode;
-	protected int selectedNodeRadius;
-	protected int unselectedNodeRadius;
-	protected int selectedNodeSize;
-	protected int unselectedNodeSize;
-	protected int defaultSegmentWidth;
-	protected int virtualNodeSize;
-	protected int virtualNodeSpace;
-	protected int segmentNumberSpace;
-	protected int taggedNodeRadius;
-	protected int taggedNodeSize;
-
-	/**
-	 * Draw subsequent segments of same color as one Path
-	 */
-	protected Color currentColor = null;
-	protected GeneralPath currentPath = new GeneralPath();
-
-	Rectangle bbox = new Rectangle();
-
-	protected void getSettings(Boolean virtual) {
-		inactiveColor = Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY);
-		selectedColor = Main.pref.getColor(marktr("selected"), Color.WHITE);
-		nodeColor = Main.pref.getColor(marktr("node"), Color.RED);
-		dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
-		relationColor = Main.pref.getColor(marktr("relation"), teal);
-		untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
-		incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
-		backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
-		showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
-		showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
-		showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
-		selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
-		selectedNodeSize = selectedNodeRadius * 2;
-		unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
-		unselectedNodeSize = unselectedNodeRadius * 2;
-		taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
-		taggedNodeSize = taggedNodeRadius * 2;
-		defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
-		fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
-		fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
-		virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
-		virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
-		segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
-
-		((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-			Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
-			RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
-	}
-
-	public void visitAll(DataSet data, Boolean virtual) {
-		getSettings(virtual);
-		// draw tagged ways first, then untagged ways. takes
-		// time to iterate through list twice, OTOH does not
-		// require changing the colour while painting...
-		for (final OsmPrimitive osm : data.relations)
-			if (!osm.deleted && !osm.selected)
-				osm.visit(this);
-
-		for (final OsmPrimitive osm : data.ways)
-			if (!osm.deleted && !osm.selected && osm.tagged)
-				osm.visit(this);
-		displaySegments();
-
-		for (final OsmPrimitive osm : data.ways)
-			if (!osm.deleted && !osm.selected && !osm.tagged)
-				osm.visit(this);
-		displaySegments();
-
-		for (final OsmPrimitive osm : data.getSelected())
-			if (!osm.deleted)
-				osm.visit(this);
-		displaySegments();
-
-		for (final OsmPrimitive osm : data.nodes)
-			if (!osm.deleted && !osm.selected)
-				osm.visit(this);
-		if(virtualNodeSize != 0)
-		{
-			currentColor = nodeColor;
-			for (final OsmPrimitive osm : data.ways)
-				if (!osm.deleted)
-					visitVirtual((Way)osm);
-			displaySegments();
-		}
-	}
-
-	/**
-	 * Draw a small rectangle.
-	 * White if selected (as always) or red otherwise.
-	 *
-	 * @param n The node to draw.
-	 */
-	public void visit(Node n) {
-		if (n.incomplete) return;
-
-		if (inactive)
-			drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
-		else if (n.selected)
-			drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
-		else if(n.tagged)
-			drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
-		else
-			drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
-	}
-
-	public static Boolean isLargeSegment(Point p1, Point p2, int space)
-	{
-		int xd = p1.x-p2.x; if(xd < 0) xd = -xd;
-		int yd = p1.y-p2.y; if(yd < 0) yd = -yd;
-		return (xd+yd > space);
-	}
-
-	public void visitVirtual(Way w) {
-		Iterator<Node> it = w.nodes.iterator();
-		if (it.hasNext()) {
-			Point lastP = nc.getPoint(it.next().eastNorth);
-			while(it.hasNext())
-			{
-				Point p = nc.getPoint(it.next().eastNorth);
-				if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
-				{
-					int x = (p.x+lastP.x)/2;
-					int y = (p.y+lastP.y)/2;
-					currentPath.moveTo(x-virtualNodeSize, y);
-					currentPath.lineTo(x+virtualNodeSize, y);
-					currentPath.moveTo(x, y-virtualNodeSize);
-					currentPath.lineTo(x, y+virtualNodeSize);
-				}
-				lastP = p;
-			}
-		}
-	}
-
-	/**
-	 * Draw a darkblue line for all segments.
-	 * @param w The way to draw.
-	 */
-	public void visit(Way w) {
-		if (w.incomplete || w.nodes.size() < 2)
-			return;
-
-		// show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
-		// (even if the tag is negated as in oneway=false) or the way is selected
-
-		boolean showThisDirectionArrow = w.selected
-		|| (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys));
-		Color wayColor;
-
-		if (inactive) {
-			wayColor = inactiveColor;
-		} else if (!w.tagged) {
-			wayColor = untaggedWayColor;
-		} else {
-			wayColor = dfltWayColor;
-		}
-
-		Iterator<Node> it = w.nodes.iterator();
-		if (it.hasNext()) {
-			Point lastP = nc.getPoint(it.next().eastNorth);
-			for (int orderNumber = 1; it.hasNext(); orderNumber++) {
-				Point p = nc.getPoint(it.next().eastNorth);
-				drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow);
-				if (showOrderNumber)
-					drawOrderNumber(lastP, p, orderNumber);
-				lastP = p;
-			}
-		}
-	}
-
-	private Stroke relatedWayStroke = new BasicStroke(
-		4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
-	public void visit(Relation r) {
-		if (r.incomplete) return;
-
-		Color col;
-		if (inactive) {
-			col = inactiveColor;
-		} else if (r.selected) {
-			col = selectedColor;
-		} else {
-			col = relationColor;
-		}
-		g.setColor(col);
-
-		for (RelationMember m : r.members) {
-			if (m.member.incomplete || m.member.deleted) continue;
-
-			if (m.member instanceof Node) {
-				Point p = nc.getPoint(((Node) m.member).eastNorth);
-				if (p.x < 0 || p.y < 0
-					|| p.x > nc.getWidth() || p.y > nc.getHeight()) continue;
-
-				g.drawOval(p.x-3, p.y-3, 6, 6);
-			} else if (m.member instanceof Way) {
-				GeneralPath path = new GeneralPath();
-
-				boolean first = true;
-				for (Node n : ((Way) m.member).nodes) {
-					if (n.incomplete || n.deleted) continue;
-					Point p = nc.getPoint(n.eastNorth);
-					if (first) {
-						path.moveTo(p.x, p.y);
-						first = false;
-					} else {
-						path.lineTo(p.x, p.y);
-					}
-				}
-
-				((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
-			}
-		}
-	}
-
-	/**
-	 * Draw an number of the order of the two consecutive nodes within the
-	 * parents way
-	 */
-	protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
-		if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
-			String on = Integer.toString(orderNumber);
-			int strlen = on.length();
-			int x = (p1.x+p2.x)/2 - 4*strlen;
-			int y = (p1.y+p2.y)/2 + 4;
-
-			if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
-			{
-				y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
-			}
-
-			displaySegments(); // draw nodes on top!
-			Color c = g.getColor();
-			g.setColor(backgroundColor);
-			g.fillRect(x-1, y-12, 8*strlen+1, 14);
-			g.setColor(c);
-			g.drawString(on, x, y);
-		}
-	}
-
-	/**
-	 * Draw the node as small rectangle with the given color.
-	 *
-	 * @param n		The node to draw.
-	 * @param color The color of the node.
-	 */
-	public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
-		if (size > 1) {
-			Point p = nc.getPoint(n.eastNorth);
-			if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
-					|| (p.y > nc.getHeight()))
-				return;
-			g.setColor(color);
-			if (fill) {
-				g.fillRect(p.x - radius, p.y - radius, size, size);
-				g.drawRect(p.x - radius, p.y - radius, size, size);
-			} else
-				g.drawRect(p.x - radius, p.y - radius, size, size);
-		}
-	}
-
-	/**
-	 * Draw a line with the given color.
-	 */
-	protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
-		if (col != currentColor) displaySegments(col);
-
-		if (isSegmentVisible(p1, p2)) {
-			currentPath.moveTo(p1.x, p1.y);
-			currentPath.lineTo(p2.x, p2.y);
-
-			if (showDirection) {
-				double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
-				currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
-				currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
-				currentPath.lineTo(p2.x, p2.y);
-			}
-		}
-	}
-
-	protected boolean isSegmentVisible(Point p1, Point p2) {
-		if ((p1.x < 0) && (p2.x < 0)) return false;
-		if ((p1.y < 0) && (p2.y < 0)) return false;
-		if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
-		if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
-		return true;
-	}
-
-	public void setGraphics(Graphics g) {
-		this.g = g;
-	}
-
-	public void setNavigatableComponent(NavigatableComponent nc) {
-		this.nc = nc;
-	}
-
-	protected void displaySegments() {
-		displaySegments(null);
-	}
-	protected void displaySegments(Color newColor) {
-		if (currentPath != null) {
-			g.setColor(currentColor);
-			((Graphics2D) g).draw(currentPath);
-			currentPath = new GeneralPath();
-			currentColor = newColor;
-		}
-	}
+    public final static Color darkerblue = new Color(0,0,96);
+    public final static Color darkblue = new Color(0,0,128);
+    public final static Color darkgreen = new Color(0,128,0);
+    public final static Color teal = new Color(0,128,128);
+
+    /**
+     * The environment to paint to.
+     */
+    protected Graphics g;
+    /**
+     * MapView to get screen coordinates.
+     */
+    protected NavigatableComponent nc;
+
+    public boolean inactive;
+
+    protected static final double PHI = Math.toRadians(20);
+
+    /**
+     * Preferences
+    */
+    protected Color inactiveColor;
+    protected Color selectedColor;
+    protected Color nodeColor;
+    protected Color dfltWayColor;
+    protected Color relationColor;
+    protected Color untaggedWayColor;
+    protected Color incompleteColor;
+    protected Color backgroundColor;
+    protected boolean showDirectionArrow;
+    protected boolean showRelevantDirectionsOnly;
+    protected boolean showOrderNumber;
+    protected boolean fillSelectedNode;
+    protected boolean fillUnselectedNode;
+    protected int selectedNodeRadius;
+    protected int unselectedNodeRadius;
+    protected int selectedNodeSize;
+    protected int unselectedNodeSize;
+    protected int defaultSegmentWidth;
+    protected int virtualNodeSize;
+    protected int virtualNodeSpace;
+    protected int segmentNumberSpace;
+    protected int taggedNodeRadius;
+    protected int taggedNodeSize;
+
+    /**
+     * Draw subsequent segments of same color as one Path
+     */
+    protected Color currentColor = null;
+    protected GeneralPath currentPath = new GeneralPath();
+
+    Rectangle bbox = new Rectangle();
+
+    protected void getSettings(Boolean virtual) {
+        inactiveColor = Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY);
+        selectedColor = Main.pref.getColor(marktr("selected"), Color.WHITE);
+        nodeColor = Main.pref.getColor(marktr("node"), Color.RED);
+        dfltWayColor = Main.pref.getColor(marktr("way"), darkblue);
+        relationColor = Main.pref.getColor(marktr("relation"), teal);
+        untaggedWayColor = Main.pref.getColor(marktr("untagged way"), darkgreen);
+        incompleteColor = Main.pref.getColor(marktr("incomplete way"), darkerblue);
+        backgroundColor = Main.pref.getColor(marktr("background"), Color.BLACK);
+        showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
+        showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
+        showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
+        selectedNodeRadius = Main.pref.getInteger("mappaint.node.selected-size", 5) / 2;
+        selectedNodeSize = selectedNodeRadius * 2;
+        unselectedNodeRadius = Main.pref.getInteger("mappaint.node.unselected-size", 3) / 2;
+        unselectedNodeSize = unselectedNodeRadius * 2;
+        taggedNodeRadius = Main.pref.getInteger("mappaint.node.tagged-size", 5) / 2;
+        taggedNodeSize = taggedNodeRadius * 2;
+        defaultSegmentWidth = Main.pref.getInteger("mappaint.segment.default-width", 2);
+        fillSelectedNode = Main.pref.getBoolean("mappaint.node.fill-selected", true);
+        fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
+        virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 8) / 2 : 0;
+        virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
+        segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
+
+        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+            Main.pref.getBoolean("mappaint.use-antialiasing", false) ?
+            RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
+    }
+
+    public void visitAll(DataSet data, Boolean virtual) {
+        getSettings(virtual);
+        // draw tagged ways first, then untagged ways. takes
+        // time to iterate through list twice, OTOH does not
+        // require changing the colour while painting...
+        for (final OsmPrimitive osm : data.relations)
+            if (!osm.deleted && !osm.selected)
+                osm.visit(this);
+
+        for (final OsmPrimitive osm : data.ways)
+            if (!osm.deleted && !osm.selected && osm.tagged)
+                osm.visit(this);
+        displaySegments();
+
+        for (final OsmPrimitive osm : data.ways)
+            if (!osm.deleted && !osm.selected && !osm.tagged)
+                osm.visit(this);
+        displaySegments();
+
+        for (final OsmPrimitive osm : data.getSelected())
+            if (!osm.deleted)
+                osm.visit(this);
+        displaySegments();
+
+        for (final OsmPrimitive osm : data.nodes)
+            if (!osm.deleted && !osm.selected)
+                osm.visit(this);
+        if(virtualNodeSize != 0)
+        {
+            currentColor = nodeColor;
+            for (final OsmPrimitive osm : data.ways)
+                if (!osm.deleted)
+                    visitVirtual((Way)osm);
+            displaySegments();
+        }
+    }
+
+    /**
+     * Draw a small rectangle.
+     * White if selected (as always) or red otherwise.
+     *
+     * @param n The node to draw.
+     */
+    public void visit(Node n) {
+        if (n.incomplete) return;
+
+        if (inactive)
+            drawNode(n, inactiveColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
+        else if (n.selected)
+            drawNode(n, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
+        else if(n.tagged)
+            drawNode(n, nodeColor, taggedNodeSize, taggedNodeRadius, fillUnselectedNode);
+        else
+            drawNode(n, nodeColor, unselectedNodeSize, unselectedNodeRadius, fillUnselectedNode);
+    }
+
+    public static Boolean isLargeSegment(Point p1, Point p2, int space)
+    {
+        int xd = p1.x-p2.x; if(xd < 0) xd = -xd;
+        int yd = p1.y-p2.y; if(yd < 0) yd = -yd;
+        return (xd+yd > space);
+    }
+
+    public void visitVirtual(Way w) {
+        Iterator<Node> it = w.nodes.iterator();
+        if (it.hasNext()) {
+            Point lastP = nc.getPoint(it.next().eastNorth);
+            while(it.hasNext())
+            {
+                Point p = nc.getPoint(it.next().eastNorth);
+                if(isSegmentVisible(lastP, p) && isLargeSegment(lastP, p, virtualNodeSpace))
+                {
+                    int x = (p.x+lastP.x)/2;
+                    int y = (p.y+lastP.y)/2;
+                    currentPath.moveTo(x-virtualNodeSize, y);
+                    currentPath.lineTo(x+virtualNodeSize, y);
+                    currentPath.moveTo(x, y-virtualNodeSize);
+                    currentPath.lineTo(x, y+virtualNodeSize);
+                }
+                lastP = p;
+            }
+        }
+    }
+
+    /**
+     * Draw a darkblue line for all segments.
+     * @param w The way to draw.
+     */
+    public void visit(Way w) {
+        if (w.incomplete || w.nodes.size() < 2)
+            return;
+
+        // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
+        // (even if the tag is negated as in oneway=false) or the way is selected
+
+        boolean showThisDirectionArrow = w.selected
+        || (showDirectionArrow && (!showRelevantDirectionsOnly || w.hasDirectionKeys));
+        Color wayColor;
+
+        if (inactive) {
+            wayColor = inactiveColor;
+        } else if (!w.tagged) {
+            wayColor = untaggedWayColor;
+        } else {
+            wayColor = dfltWayColor;
+        }
+
+        Iterator<Node> it = w.nodes.iterator();
+        if (it.hasNext()) {
+            Point lastP = nc.getPoint(it.next().eastNorth);
+            for (int orderNumber = 1; it.hasNext(); orderNumber++) {
+                Point p = nc.getPoint(it.next().eastNorth);
+                drawSegment(lastP, p, w.selected && !inactive ? selectedColor : wayColor, showThisDirectionArrow);
+                if (showOrderNumber)
+                    drawOrderNumber(lastP, p, orderNumber);
+                lastP = p;
+            }
+        }
+    }
+
+    private Stroke relatedWayStroke = new BasicStroke(
+        4, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
+    public void visit(Relation r) {
+        if (r.incomplete) return;
+
+        Color col;
+        if (inactive) {
+            col = inactiveColor;
+        } else if (r.selected) {
+            col = selectedColor;
+        } else {
+            col = relationColor;
+        }
+        g.setColor(col);
+
+        for (RelationMember m : r.members) {
+            if (m.member.incomplete || m.member.deleted) continue;
+
+            if (m.member instanceof Node) {
+                Point p = nc.getPoint(((Node) m.member).eastNorth);
+                if (p.x < 0 || p.y < 0
+                    || p.x > nc.getWidth() || p.y > nc.getHeight()) continue;
+
+                g.drawOval(p.x-3, p.y-3, 6, 6);
+            } else if (m.member instanceof Way) {
+                GeneralPath path = new GeneralPath();
+
+                boolean first = true;
+                for (Node n : ((Way) m.member).nodes) {
+                    if (n.incomplete || n.deleted) continue;
+                    Point p = nc.getPoint(n.eastNorth);
+                    if (first) {
+                        path.moveTo(p.x, p.y);
+                        first = false;
+                    } else {
+                        path.lineTo(p.x, p.y);
+                    }
+                }
+
+                ((Graphics2D) g).draw(relatedWayStroke.createStrokedShape(path));
+            }
+        }
+    }
+
+    /**
+     * Draw an number of the order of the two consecutive nodes within the
+     * parents way
+     */
+    protected void drawOrderNumber(Point p1, Point p2, int orderNumber) {
+        if (isSegmentVisible(p1, p2) && isLargeSegment(p1, p2, segmentNumberSpace)) {
+            String on = Integer.toString(orderNumber);
+            int strlen = on.length();
+            int x = (p1.x+p2.x)/2 - 4*strlen;
+            int y = (p1.y+p2.y)/2 + 4;
+
+            if(virtualNodeSize != 0 && isLargeSegment(p1, p2, virtualNodeSpace))
+            {
+                y = (p1.y+p2.y)/2 - virtualNodeSize - 3;
+            }
+
+            displaySegments(); // draw nodes on top!
+            Color c = g.getColor();
+            g.setColor(backgroundColor);
+            g.fillRect(x-1, y-12, 8*strlen+1, 14);
+            g.setColor(c);
+            g.drawString(on, x, y);
+        }
+    }
+
+    /**
+     * Draw the node as small rectangle with the given color.
+     *
+     * @param n     The node to draw.
+     * @param color The color of the node.
+     */
+    public void drawNode(Node n, Color color, int size, int radius, boolean fill) {
+        if (size > 1) {
+            Point p = nc.getPoint(n.eastNorth);
+            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth())
+                    || (p.y > nc.getHeight()))
+                return;
+            g.setColor(color);
+            if (fill) {
+                g.fillRect(p.x - radius, p.y - radius, size, size);
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+            } else
+                g.drawRect(p.x - radius, p.y - radius, size, size);
+        }
+    }
+
+    /**
+     * Draw a line with the given color.
+     */
+    protected void drawSegment(Point p1, Point p2, Color col, boolean showDirection) {
+        if (col != currentColor) displaySegments(col);
+
+        if (isSegmentVisible(p1, p2)) {
+            currentPath.moveTo(p1.x, p1.y);
+            currentPath.lineTo(p2.x, p2.y);
+
+            if (showDirection) {
+                double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
+                currentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
+                currentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
+                currentPath.lineTo(p2.x, p2.y);
+            }
+        }
+    }
+
+    protected boolean isSegmentVisible(Point p1, Point p2) {
+        if ((p1.x < 0) && (p2.x < 0)) return false;
+        if ((p1.y < 0) && (p2.y < 0)) return false;
+        if ((p1.x > nc.getWidth()) && (p2.x > nc.getWidth())) return false;
+        if ((p1.y > nc.getHeight()) && (p2.y > nc.getHeight())) return false;
+        return true;
+    }
+
+    public void setGraphics(Graphics g) {
+        this.g = g;
+    }
+
+    public void setNavigatableComponent(NavigatableComponent nc) {
+        this.nc = nc;
+    }
+
+    protected void displaySegments() {
+        displaySegments(null);
+    }
+    protected void displaySegments(Color newColor) {
+        if (currentPath != null) {
+            g.setColor(currentColor);
+            ((Graphics2D) g).draw(currentPath);
+            currentPath = new GeneralPath();
+            currentColor = newColor;
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java	(revision 1169)
@@ -9,10 +9,10 @@
  * Implementation of the visitor scheme. Every OsmPrimitive can be visited by
  * several different visitors.
- * 
+ *
  * @author imi
  */
 public interface Visitor {
-	void visit(Node n);
-	void visit(Way w);
-	void visit(Relation e);
+    void visit(Node n);
+    void visit(Way w);
+    void visit(Relation e);
 }
Index: trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/projection/Epsg4326.java	(revision 1169)
@@ -12,15 +12,15 @@
 public class Epsg4326 implements Projection {
 
-	public EastNorth latlon2eastNorth(LatLon p) {
-		return new EastNorth(p.lon(), p.lat());
-	}
+    public EastNorth latlon2eastNorth(LatLon p) {
+        return new EastNorth(p.lon(), p.lat());
+    }
 
-	public LatLon eastNorth2latlon(EastNorth p) {
-		return new LatLon(p.north(), p.east());
-	}
+    public LatLon eastNorth2latlon(EastNorth p) {
+        return new LatLon(p.north(), p.east());
+    }
 
-	@Override public String toString() {
-		return tr("EPSG:4326");
-	}
+    @Override public String toString() {
+        return tr("EPSG:4326");
+    }
 
     public String getCacheDirectoryName() {
@@ -28,14 +28,14 @@
     }
 
-	public double scaleFactor() {
-	    return 1.0/360;
+    public double scaleFactor() {
+        return 1.0/360;
     }
 
-	@Override public boolean equals(Object o) {
-		return o instanceof Epsg4326;
-	}
+    @Override public boolean equals(Object o) {
+        return o instanceof Epsg4326;
+    }
 
-	@Override public int hashCode() {
-		return Epsg4326.class.hashCode();
-	}
+    @Override public int hashCode() {
+        return Epsg4326.class.hashCode();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/projection/Lambert.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/Lambert.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/projection/Lambert.java	(revision 1169)
@@ -14,292 +14,292 @@
 
 public class Lambert implements Projection {
-	/**
-	 * Lambert I, II, III, and IV projection exponents
-	 */
-	public static final double n[] = { 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322 };
-
-	/**
-	 * Lambert I, II, III, and IV projection constants
-	 */
-	public static final double c[] = { 11603796.98, 11745793.39, 11947992.52, 12136281.99 };
-
-	/**
-	 * Lambert I, II, III, and IV false east
-	 */
-	public static final double Xs[] = { 600000.0, 600000.0, 600000.0, 234.358 };
-
-	/**
-	 * Lambert I, II, III, and IV false north
-	 */
-	public static final double Ys[] = { 5657616.674, 6199695.768, 6791905.085, 7239161.542 };
-
-	/**
-	 * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian
-	 */
-	public static final double lg0 = 0.04079234433198; // 2deg20'14.025"
-
-	/**
-	 * precision in iterative schema
-	 */
-
-	public static final double epsilon = 1e-11;
-
-	/**
-	 * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
-	 */
-	public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9);
-
-	public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9)
-			Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3
-			Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4
-			Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4
-
-	public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
-
-	public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
-
-	/**
-	 *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
-	 */
-	public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
-
-	public static int layoutZone = -1;
-
-	private static int currentZone = 0;
-
-	private static boolean dontDisplayErrors = false;
-
-	/**
-	 * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
-	 * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
-	 */
-	public EastNorth latlon2eastNorth(LatLon p) {
-		// translate ellipsoid GRS80 (WGS83) => Clark
-		LatLon geo = GRS802Clark(p);
-		double lt = geo.lat(); // in radian
-		double lg = geo.lon();
-
-		// check if longitude and latitude are inside the french Lambert zones
-		currentZone = 0;
-		boolean outOfLambertZones = false;
-		if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) {
-			// zone I
-			if (lt > zoneLimits[0])
-				currentZone = 0;
-			// zone II
-			else if (lt > zoneLimits[1])
-				currentZone = 1;
-			// zone III
-			else if (lt > zoneLimits[2])
-				currentZone = 2;
-			// zone III or IV
-			else if (lt > zoneLimits[3])
-				// Note: zone IV is dedicated to Corsica island and extends from 47.8 to
-				// 45.9 degrees of latitude. There is an overlap with zone III that can be
-				// solved only with longitude (covers Corsica if lon > 7.2 degree)
-				if (lg < Math.toRadians(8 * 0.9))
-					currentZone = 2;
-				else
-					currentZone = 3;
-		} else {
-			outOfLambertZones = true; // possible when MAX_LAT is used
-			if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT
-					&& p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON
-					&& dontDisplayErrors == false) {
-				JOptionPane.showMessageDialog(Main.parent,
-						tr("The projection \"{0}\" is designed for\n"
-						+ "latitudes between 46.1° and 57° only.\n"
-						+ "Use another projection system if you are not using\n"
-						+ "a french WMS server.\n"
-						+ "Do not upload any data after this message.", this.toString()));
-				dontDisplayErrors = true;
-			}
-		}
-		if (!outOfLambertZones) {
-			if (layoutZone == -1) {
-				layoutZone = currentZone;
-				dontDisplayErrors = false;
-			} else if (layoutZone != currentZone) {
-				if ((currentZone < layoutZone && Math.abs(zoneLimits[currentZone] - lt) > cMaxOverlappingZones)
-						|| (currentZone > layoutZone && Math.abs(zoneLimits[layoutZone] - lt) > cMaxOverlappingZones)) {
-					JOptionPane.showMessageDialog(Main.parent,
-									tr("IMPORTANT : data positionned far away from\n"
-											+ "the current Lambert zone limits.\n"
-											+ "Do not upload any data after this message.\n"
-											+ "Undo your last action, Save your work \n"
-											+ "and Start a new layer on the new zone."));
-					layoutZone = -1;
-					dontDisplayErrors = true;
-				} else {
-					System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
-							+ lt + "," + lg);
-				}
-			}
-		}
-		if (layoutZone == -1) {
-			return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
-		} // else
-		return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
-	}
-
-	public LatLon eastNorth2latlon(EastNorth p) {
-		LatLon geo;
-		if (layoutZone == -1)
-			// possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon
-			geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
-		else
-			geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
-		// translate ellipsoid Clark => GRS80 (WGS83)
-		LatLon wgs = Clark2GRS80(geo);
-		return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon()));
-	}
-
-	@Override public String toString() {
-		return tr("Lambert Zone (France)");
-	}
-
-	public String getCacheDirectoryName() {
-		return "lambert";
-	}
-
-	public double scaleFactor() {
-		return 1.0 / 360;
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		return o instanceof Lambert;
-	}
-
-	@Override
-	public int hashCode() {
-		return Lambert.class.hashCode();
-	}
-
-	/**
-	 * Initializes from geographic coordinates. Note that reference ellipsoid
-	 * used by Lambert is the Clark ellipsoid.
-	 *
-	 * @param lat latitude in grad
-	 * @param lon longitude in grad
-	 * @param Xs  false east (coordinate system origin) in meters
-	 * @param Ys  false north (coordinate system origin) in meters
-	 * @param c   projection constant
-	 * @param n   projection exponent
-	 * @return EastNorth projected coordinates in meter
-	 */
-	private EastNorth ConicProjection(double lat, double lon, double Xs, double Ys, double c, double n) {
-		double eslt = Ellipsoid.clarke.e * Math.sin(lat);
-		double l = Math.log(Math.tan(Math.PI / 4.0 + (lat / 2.0))
-				* Math.pow((1.0 - eslt) / (1.0 + eslt), Ellipsoid.clarke.e / 2.0));
-		double east = Xs + c * Math.exp(-n * l) * Math.sin(n * (lon - lg0));
-		double north = Ys - c * Math.exp(-n * l) * Math.cos(n * (lon - lg0));
-		return new EastNorth(east, north);
-	}
-
-	/**
-	 * Initializes from projected coordinates (conic projection). Note that
-	 * reference ellipsoid used by Lambert is Clark
-	 *
-	 * @param coord projected coordinates pair in meters
-	 * @param Xs    false east (coordinate system origin) in meters
-	 * @param Ys    false north (coordinate system origin) in meters
-	 * @param c     projection constant
-	 * @param n     projection exponent
-	 * @return LatLon in radian
-	 */
-	private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
-		double dx = eastNorth.east() - Xs;
-		double dy = Ys - eastNorth.north();
-		double R = Math.sqrt(dx * dx + dy * dy);
-		double gamma = Math.atan(dx / dy);
-		double l = -1.0 / n * Math.log(Math.abs(R / c));
-		l = Math.exp(l);
-		double lon = lg0 + gamma / n;
-		double lat = 2.0 * Math.atan(l) - Math.PI / 2.0;
-		double delta = 1.0;
-		while (delta > epsilon) {
-			double eslt = Ellipsoid.clarke.e * Math.sin(lat);
-			double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l) - Math.PI
-					/ 2.0;
-			delta = Math.abs(nlt - lat);
-			lat = nlt;
-		}
-		return new LatLon(lat, lon); // in radian
-	}
-
-	/**
-	 * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
-	 * geographic, (ellipsoid Clark)
-	 *
-	 * @param wgs
-	 * @return
-	 */
-	private LatLon GRS802Clark(LatLon wgs) {
-		double lat = Math.toRadians(wgs.lat()); // degree to radian
-		double lon = Math.toRadians(wgs.lon());
-		// WGS84 geographic => WGS84 cartesian
-		double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat)));
-		double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
-		double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
-		double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat);
-		// WGS84 => Lambert ellipsoide similarity
-		X += 168.0;
-		Y += 60.0;
-		Z += -320.0;
-		// Lambert cartesian => Lambert geographic
-		return Geographic(X, Y, Z, Ellipsoid.clarke);
-	}
-
-	/**
-	 * @param lambert
-	 * @return
-	 */
-	private LatLon Clark2GRS80(LatLon lambert) {
-		double lat = lambert.lat(); // in radian
-		double lon = lambert.lon();
-		// Lambert geographic => Lambert cartesian
-		double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat)));
-		double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
-		double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
-		double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat);
-		// Lambert => WGS84 ellipsoide similarity
-		X += -168.0;
-		Y += -60.0;
-		Z += 320.0;
-		// WGS84 cartesian => WGS84 geographic
-		return Geographic(X, Y, Z, Ellipsoid.GRS80);
-	}
-
-	/**
-	 * initializes from cartesian coordinates
-	 *
-	 * @param X
-	 *            1st coordinate in meters
-	 * @param Y
-	 *            2nd coordinate in meters
-	 * @param Z
-	 *            3rd coordinate in meters
-	 * @param ell
-	 *            reference ellipsoid
-	 */
-	private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) {
-		double norm = Math.sqrt(X * X + Y * Y);
-		double lg = 2.0 * Math.atan(Y / (X + norm));
-		double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z)))));
-		double delta = 1.0;
-		while (delta > epsilon) {
-			double s2 = Math.sin(lt);
-			s2 *= s2;
-			double l = Math.atan((Z / norm)
-				/ (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2)))));
-			delta = Math.abs(l - lt);
-			lt = l;
-		}
-		double s2 = Math.sin(lt);
-		s2 *= s2;
-		// h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2);
-		return new LatLon(lt, lg);
-	}
+    /**
+     * Lambert I, II, III, and IV projection exponents
+     */
+    public static final double n[] = { 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322 };
+
+    /**
+     * Lambert I, II, III, and IV projection constants
+     */
+    public static final double c[] = { 11603796.98, 11745793.39, 11947992.52, 12136281.99 };
+
+    /**
+     * Lambert I, II, III, and IV false east
+     */
+    public static final double Xs[] = { 600000.0, 600000.0, 600000.0, 234.358 };
+
+    /**
+     * Lambert I, II, III, and IV false north
+     */
+    public static final double Ys[] = { 5657616.674, 6199695.768, 6791905.085, 7239161.542 };
+
+    /**
+     * Lambert I, II, III, and IV longitudinal offset to Greenwich meridian
+     */
+    public static final double lg0 = 0.04079234433198; // 2deg20'14.025"
+
+    /**
+     * precision in iterative schema
+     */
+
+    public static final double epsilon = 1e-11;
+
+    /**
+     * France is divided in 4 Lambert projection zones (1,2,3 + 4th for Corsica)
+     */
+    public static final double cMaxLatZone1 = Math.toRadians(57 * 0.9);
+
+    public static final double zoneLimits[] = { Math.toRadians(53.5 * 0.9), // between Zone 1 and Zone 2 (in grad *0.9)
+            Math.toRadians(50.5 * 0.9), // between Zone 2 and Zone 3
+            Math.toRadians(47.51963 * 0.9), // between Zone 3 and Zone 4
+            Math.toRadians(46.17821 * 0.9) };// lowest latitude of Zone 4
+
+    public static final double cMinLonZones = Math.toRadians(-4.9074074074074059 * 0.9);
+
+    public static final double cMaxLonZones = Math.toRadians(10.2 * 0.9);
+
+    /**
+     *  Because josm cannot work correctly if two zones are displayed, we allow some overlapping
+     */
+    public static final double cMaxOverlappingZones = Math.toRadians(1.5 * 0.9);
+
+    public static int layoutZone = -1;
+
+    private static int currentZone = 0;
+
+    private static boolean dontDisplayErrors = false;
+
+    /**
+     * @param p  WGS84 lat/lon (ellipsoid GRS80) (in degree)
+     * @return eastnorth projection in Lambert Zone (ellipsoid Clark)
+     */
+    public EastNorth latlon2eastNorth(LatLon p) {
+        // translate ellipsoid GRS80 (WGS83) => Clark
+        LatLon geo = GRS802Clark(p);
+        double lt = geo.lat(); // in radian
+        double lg = geo.lon();
+
+        // check if longitude and latitude are inside the french Lambert zones
+        currentZone = 0;
+        boolean outOfLambertZones = false;
+        if (lt >= zoneLimits[3] && lt <= cMaxLatZone1 && lg >= cMinLonZones && lg <= cMaxLonZones) {
+            // zone I
+            if (lt > zoneLimits[0])
+                currentZone = 0;
+            // zone II
+            else if (lt > zoneLimits[1])
+                currentZone = 1;
+            // zone III
+            else if (lt > zoneLimits[2])
+                currentZone = 2;
+            // zone III or IV
+            else if (lt > zoneLimits[3])
+                // Note: zone IV is dedicated to Corsica island and extends from 47.8 to
+                // 45.9 degrees of latitude. There is an overlap with zone III that can be
+                // solved only with longitude (covers Corsica if lon > 7.2 degree)
+                if (lg < Math.toRadians(8 * 0.9))
+                    currentZone = 2;
+                else
+                    currentZone = 3;
+        } else {
+            outOfLambertZones = true; // possible when MAX_LAT is used
+            if (p.lat() != 0 && Math.abs(p.lat()) != Projection.MAX_LAT
+                    && p.lon() != 0 && Math.abs(p.lon()) != Projection.MAX_LON
+                    && dontDisplayErrors == false) {
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("The projection \"{0}\" is designed for\n"
+                        + "latitudes between 46.1° and 57° only.\n"
+                        + "Use another projection system if you are not using\n"
+                        + "a french WMS server.\n"
+                        + "Do not upload any data after this message.", this.toString()));
+                dontDisplayErrors = true;
+            }
+        }
+        if (!outOfLambertZones) {
+            if (layoutZone == -1) {
+                layoutZone = currentZone;
+                dontDisplayErrors = false;
+            } else if (layoutZone != currentZone) {
+                if ((currentZone < layoutZone && Math.abs(zoneLimits[currentZone] - lt) > cMaxOverlappingZones)
+                        || (currentZone > layoutZone && Math.abs(zoneLimits[layoutZone] - lt) > cMaxOverlappingZones)) {
+                    JOptionPane.showMessageDialog(Main.parent,
+                                    tr("IMPORTANT : data positionned far away from\n"
+                                            + "the current Lambert zone limits.\n"
+                                            + "Do not upload any data after this message.\n"
+                                            + "Undo your last action, Save your work \n"
+                                            + "and Start a new layer on the new zone."));
+                    layoutZone = -1;
+                    dontDisplayErrors = true;
+                } else {
+                    System.out.println("temporarily extend Lambert zone " + layoutZone + " projection at lat,lon:"
+                            + lt + "," + lg);
+                }
+            }
+        }
+        if (layoutZone == -1) {
+            return ConicProjection(lt, lg, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
+        } // else
+        return ConicProjection(lt, lg, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
+    }
+
+    public LatLon eastNorth2latlon(EastNorth p) {
+        LatLon geo;
+        if (layoutZone == -1)
+            // possible until the Lambert zone is determined by latlon2eastNorth() with a valid LatLon
+            geo = Geographic(p, Xs[currentZone], Ys[currentZone], c[currentZone], n[currentZone]);
+        else
+            geo = Geographic(p, Xs[layoutZone], Ys[layoutZone], c[layoutZone], n[layoutZone]);
+        // translate ellipsoid Clark => GRS80 (WGS83)
+        LatLon wgs = Clark2GRS80(geo);
+        return new LatLon(Math.toDegrees(wgs.lat()), Math.toDegrees(wgs.lon()));
+    }
+
+    @Override public String toString() {
+        return tr("Lambert Zone (France)");
+    }
+
+    public String getCacheDirectoryName() {
+        return "lambert";
+    }
+
+    public double scaleFactor() {
+        return 1.0 / 360;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof Lambert;
+    }
+
+    @Override
+    public int hashCode() {
+        return Lambert.class.hashCode();
+    }
+
+    /**
+     * Initializes from geographic coordinates. Note that reference ellipsoid
+     * used by Lambert is the Clark ellipsoid.
+     *
+     * @param lat latitude in grad
+     * @param lon longitude in grad
+     * @param Xs  false east (coordinate system origin) in meters
+     * @param Ys  false north (coordinate system origin) in meters
+     * @param c   projection constant
+     * @param n   projection exponent
+     * @return EastNorth projected coordinates in meter
+     */
+    private EastNorth ConicProjection(double lat, double lon, double Xs, double Ys, double c, double n) {
+        double eslt = Ellipsoid.clarke.e * Math.sin(lat);
+        double l = Math.log(Math.tan(Math.PI / 4.0 + (lat / 2.0))
+                * Math.pow((1.0 - eslt) / (1.0 + eslt), Ellipsoid.clarke.e / 2.0));
+        double east = Xs + c * Math.exp(-n * l) * Math.sin(n * (lon - lg0));
+        double north = Ys - c * Math.exp(-n * l) * Math.cos(n * (lon - lg0));
+        return new EastNorth(east, north);
+    }
+
+    /**
+     * Initializes from projected coordinates (conic projection). Note that
+     * reference ellipsoid used by Lambert is Clark
+     *
+     * @param coord projected coordinates pair in meters
+     * @param Xs    false east (coordinate system origin) in meters
+     * @param Ys    false north (coordinate system origin) in meters
+     * @param c     projection constant
+     * @param n     projection exponent
+     * @return LatLon in radian
+     */
+    private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
+        double dx = eastNorth.east() - Xs;
+        double dy = Ys - eastNorth.north();
+        double R = Math.sqrt(dx * dx + dy * dy);
+        double gamma = Math.atan(dx / dy);
+        double l = -1.0 / n * Math.log(Math.abs(R / c));
+        l = Math.exp(l);
+        double lon = lg0 + gamma / n;
+        double lat = 2.0 * Math.atan(l) - Math.PI / 2.0;
+        double delta = 1.0;
+        while (delta > epsilon) {
+            double eslt = Ellipsoid.clarke.e * Math.sin(lat);
+            double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l) - Math.PI
+                    / 2.0;
+            delta = Math.abs(nlt - lat);
+            lat = nlt;
+        }
+        return new LatLon(lat, lon); // in radian
+    }
+
+    /**
+     * Translate latitude/longitude in WGS84, (ellipsoid GRS80) to Lambert
+     * geographic, (ellipsoid Clark)
+     *
+     * @param wgs
+     * @return
+     */
+    private LatLon GRS802Clark(LatLon wgs) {
+        double lat = Math.toRadians(wgs.lat()); // degree to radian
+        double lon = Math.toRadians(wgs.lon());
+        // WGS84 geographic => WGS84 cartesian
+        double N = Ellipsoid.GRS80.a / (Math.sqrt(1.0 - Ellipsoid.GRS80.e2 * Math.sin(lat) * Math.sin(lat)));
+        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
+        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
+        double Z = (N * (1.0 - Ellipsoid.GRS80.e2)/* + height */) * Math.sin(lat);
+        // WGS84 => Lambert ellipsoide similarity
+        X += 168.0;
+        Y += 60.0;
+        Z += -320.0;
+        // Lambert cartesian => Lambert geographic
+        return Geographic(X, Y, Z, Ellipsoid.clarke);
+    }
+
+    /**
+     * @param lambert
+     * @return
+     */
+    private LatLon Clark2GRS80(LatLon lambert) {
+        double lat = lambert.lat(); // in radian
+        double lon = lambert.lon();
+        // Lambert geographic => Lambert cartesian
+        double N = Ellipsoid.clarke.a / (Math.sqrt(1.0 - Ellipsoid.clarke.e2 * Math.sin(lat) * Math.sin(lat)));
+        double X = (N/* +height */) * Math.cos(lat) * Math.cos(lon);
+        double Y = (N/* +height */) * Math.cos(lat) * Math.sin(lon);
+        double Z = (N * (1.0 - Ellipsoid.clarke.e2)/* + height */) * Math.sin(lat);
+        // Lambert => WGS84 ellipsoide similarity
+        X += -168.0;
+        Y += -60.0;
+        Z += 320.0;
+        // WGS84 cartesian => WGS84 geographic
+        return Geographic(X, Y, Z, Ellipsoid.GRS80);
+    }
+
+    /**
+     * initializes from cartesian coordinates
+     *
+     * @param X
+     *            1st coordinate in meters
+     * @param Y
+     *            2nd coordinate in meters
+     * @param Z
+     *            3rd coordinate in meters
+     * @param ell
+     *            reference ellipsoid
+     */
+    private LatLon Geographic(double X, double Y, double Z, Ellipsoid ell) {
+        double norm = Math.sqrt(X * X + Y * Y);
+        double lg = 2.0 * Math.atan(Y / (X + norm));
+        double lt = Math.atan(Z / (norm * (1.0 - (ell.a * ell.e2 / Math.sqrt(X * X + Y * Y + Z * Z)))));
+        double delta = 1.0;
+        while (delta > epsilon) {
+            double s2 = Math.sin(lt);
+            s2 *= s2;
+            double l = Math.atan((Z / norm)
+                / (1.0 - (ell.a * ell.e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - ell.e2 * s2)))));
+            delta = Math.abs(l - lt);
+            lt = l;
+        }
+        double s2 = Math.sin(lt);
+        s2 *= s2;
+        // h = norm / Math.cos(lt) - ell.a / Math.sqrt(1.0 - ell.e2 * s2);
+        return new LatLon(lt, lg);
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/data/projection/Mercator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/Mercator.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/projection/Mercator.java	(revision 1169)
@@ -10,27 +10,27 @@
  * Implement Mercator Projection code, coded after documentation
  * from wikipedia.
- * 
- * The center of the mercator projection is always the 0 grad 
+ *
+ * The center of the mercator projection is always the 0 grad
  * coordinate.
- * 
+ *
  * @author imi
  */
 public class Mercator implements Projection {
 
-	public EastNorth latlon2eastNorth(LatLon p) {
-		return new EastNorth(
-			p.lon()*Math.PI/180,
-			Math.log(Math.tan(Math.PI/4+p.lat()*Math.PI/360)));
-	}
+    public EastNorth latlon2eastNorth(LatLon p) {
+        return new EastNorth(
+            p.lon()*Math.PI/180,
+            Math.log(Math.tan(Math.PI/4+p.lat()*Math.PI/360)));
+    }
 
-	public LatLon eastNorth2latlon(EastNorth p) {
-		return new LatLon(
-			Math.atan(Math.sinh(p.north()))*180/Math.PI,
-			p.east()*180/Math.PI);
-	}
+    public LatLon eastNorth2latlon(EastNorth p) {
+        return new LatLon(
+            Math.atan(Math.sinh(p.north()))*180/Math.PI,
+            p.east()*180/Math.PI);
+    }
 
-	@Override public String toString() {
-		return tr("Mercator");
-	}
+    @Override public String toString() {
+        return tr("Mercator");
+    }
 
     public String getCacheDirectoryName() {
@@ -38,14 +38,14 @@
     }
 
-	public double scaleFactor() {
-	    return 1/Math.PI/2;
+    public double scaleFactor() {
+        return 1/Math.PI/2;
     }
 
-	@Override public boolean equals(Object o) {
-		return o instanceof Mercator;
-	}
+    @Override public boolean equals(Object o) {
+        return o instanceof Mercator;
+    }
 
-	@Override public int hashCode() {
-		return Mercator.class.hashCode();
-	}
+    @Override public int hashCode() {
+        return Mercator.class.hashCode();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/projection/Projection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/Projection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/data/projection/Projection.java	(revision 1169)
@@ -6,61 +6,61 @@
 
 /**
- * Classes implementing this are able to convert lat/lon values to 
+ * Classes implementing this are able to convert lat/lon values to
  * planar screen coordinates.
- * 
+ *
  * @author imi
  */
 public interface Projection {
 
-	/**
-	 * Maximum latitude representable.
-	 */
-	public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world
-	
-	/**
-	 * Maximum longditude representable.
-	 */
-	public static final double MAX_LON = 180;
+    /**
+     * Maximum latitude representable.
+     */
+    public static final double MAX_LAT = 85.05112877980659; // Mercator squares the world
 
-	/**
-	 * Minimum difference in location to not be represented as the same position.
-	 */
-	public static final double MAX_SERVER_PRECISION = 1e12;
+    /**
+     * Maximum longditude representable.
+     */
+    public static final double MAX_LON = 180;
 
-	/**
-	 * List of all available projections.
-	 */
-	public static Projection[] allProjections = new Projection[]{
-		new Epsg4326(),
-		new Mercator(),
-		new Lambert()
-	};
-	
-	/**
-	 * Convert from lat/lon to northing/easting. 
-	 * 
-	 * @param p		The geo point to convert. x/y members of the point are filled.
-	 */
-	EastNorth latlon2eastNorth(LatLon p);
-	
-	/**
-	 * Convert from norting/easting to lat/lon.
-	 * 
-	 * @param p		The geo point to convert. lat/lon members of the point are filled.
-	 */
-	LatLon eastNorth2latlon(EastNorth p);
+    /**
+     * Minimum difference in location to not be represented as the same position.
+     */
+    public static final double MAX_SERVER_PRECISION = 1e12;
 
-	/**
-	 * Describe the projection converter in one or two words.
-	 */
-	String toString();
-    
+    /**
+     * List of all available projections.
+     */
+    public static Projection[] allProjections = new Projection[]{
+        new Epsg4326(),
+        new Mercator(),
+        new Lambert()
+    };
+
+    /**
+     * Convert from lat/lon to northing/easting.
+     *
+     * @param p     The geo point to convert. x/y members of the point are filled.
+     */
+    EastNorth latlon2eastNorth(LatLon p);
+
+    /**
+     * Convert from norting/easting to lat/lon.
+     *
+     * @param p     The geo point to convert. lat/lon members of the point are filled.
+     */
+    LatLon eastNorth2latlon(EastNorth p);
+
+    /**
+     * Describe the projection converter in one or two words.
+     */
+    String toString();
+
     /**
      * Get a filename compatible string (for the cache directory)
      */
     String getCacheDirectoryName();
-    
+
     /**
-     * The factor to multiply with an easting coordinate to get from "easting 
+     * The factor to multiply with an easting coordinate to get from "easting
      * units per pixel" to "meters per pixel"
      */
Index: trunk/src/org/openstreetmap/josm/gui/BookmarkList.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/BookmarkList.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/BookmarkList.java	(revision 1169)
@@ -21,40 +21,40 @@
 public class BookmarkList extends JList {
 
-	/**
-	 * Create a bookmark list as well as the Buttons add and remove.
-	 */
-	public BookmarkList() {
-		setModel(new DefaultListModel());
-		load();
-		setVisibleRowCount(7);
-	}
+    /**
+     * Create a bookmark list as well as the Buttons add and remove.
+     */
+    public BookmarkList() {
+        setModel(new DefaultListModel());
+        load();
+        setVisibleRowCount(7);
+    }
 
-	/**
-	 * Loads the bookmarks from file.
-	 */
-	public void load() {
-		DefaultListModel model = (DefaultListModel)getModel();
-		model.removeAllElements();
-		try {
-			for (Preferences.Bookmark b : Main.pref.loadBookmarks())
-				model.addElement(b);
-		} catch (IOException e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not read bookmarks.")+"\n"+e.getMessage());
-		}
-	}
+    /**
+     * Loads the bookmarks from file.
+     */
+    public void load() {
+        DefaultListModel model = (DefaultListModel)getModel();
+        model.removeAllElements();
+        try {
+            for (Preferences.Bookmark b : Main.pref.loadBookmarks())
+                model.addElement(b);
+        } catch (IOException e) {
+            e.printStackTrace();
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not read bookmarks.")+"\n"+e.getMessage());
+        }
+    }
 
-	/**
-	 * Save all bookmarks to the preferences file
-	 */
-	public void save() {
-		try {
-			Collection<Preferences.Bookmark> bookmarks = new LinkedList<Preferences.Bookmark>();
-			for (Object o : ((DefaultListModel)getModel()).toArray())
-				bookmarks.add((Preferences.Bookmark)o);
-			Main.pref.saveBookmarks(bookmarks);
-		} catch (IOException e) {
-			JOptionPane.showMessageDialog(Main.parent,tr("Could not write bookmark.")+"\n"+e.getMessage());
-		}
-	}
+    /**
+     * Save all bookmarks to the preferences file
+     */
+    public void save() {
+        try {
+            Collection<Preferences.Bookmark> bookmarks = new LinkedList<Preferences.Bookmark>();
+            for (Object o : ((DefaultListModel)getModel()).toArray())
+                bookmarks.add((Preferences.Bookmark)o);
+            Main.pref.saveBookmarks(bookmarks);
+        } catch (IOException e) {
+            JOptionPane.showMessageDialog(Main.parent,tr("Could not write bookmark.")+"\n"+e.getMessage());
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/ConflictResolver.java	(revision 1169)
@@ -46,197 +46,197 @@
  * three tables in the screen, one for each both sides and one resulting table. The user can
  * move items from either one of the sides ("my" and "their") to the resulting table.
- * 
+ *
  * @author Imi
  */
 public class ConflictResolver extends JPanel {
 
-	public static enum Resolution {MY, THEIR}
-
-	private final class ConflictTableModel implements TableModel {
-		private final Resolution resolution;
-		public ConflictTableModel(Resolution resolution) {
-			this.resolution = resolution;
-		}
-
-		public int getRowCount() {
-			return conflicts.size();
-		}
-
-		public Object getValueAt(int rowIndex, int columnIndex) {
-			ConflictItem ci = conflicts.get(rowIndex);
-			if (columnIndex == 0)
-				return ci.key();
-			Resolution r = resolution == null ? ci.resolution : resolution;
-			if (r == null)
-				return "<html><i>???</i></html>";
-			JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their);
-			if (ci.resolution == resolution && resolution != null)
-				l.setFont(l.getFont().deriveFont(Font.BOLD));
-			return l;
-		}
-
-		public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");}
-		public int getColumnCount() {return 2;}
-		public boolean isCellEditable(int row, int column) {return false;}
-		public Class<?> getColumnClass(int columnIndex) {return Object.class;}
-
-		public void addTableModelListener(TableModelListener l) {}
-		public void removeTableModelListener(TableModelListener l) {}
-		public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
-	}
-
-	private final class DblClickListener extends MouseAdapter {
-		private final Resolution resolution;
-		public DblClickListener(Resolution resolution) {
-			this.resolution = resolution;
-		}
-		@Override public void mouseClicked(MouseEvent e) {
-			if (e.getClickCount() >= 2) {
-				int sel = ((JTable)e.getSource()).getSelectedRow();
-				if (sel == -1)
-					return;
-				ConflictResolver.this.conflicts.get(sel).resolution = resolution;
-				repaint();
-			}
-		}
-	}
-	private final class ResolveAction extends AbstractAction {
-		private final Resolution resolution;
-		public ResolveAction(String name, Resolution resolution) {
-			super(null, ImageProvider.get("dialogs", name));
-			this.resolution = resolution;
-		}
-		public void actionPerformed(ActionEvent e) {
-			int sel = myTable.getSelectedRow();
-			if (sel == -1)
-				return;
-			conflicts.get(sel).resolution = resolution;
-			if (sel == myTable.getRowCount()-1)
-				myTable.clearSelection();
-			else
-				myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1);
-			repaint();
-		}
-	}
-
-	public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>();
-
-	private final ConflictTableModel my = new ConflictTableModel(Resolution.MY);
-	private final JTable myTable;
-	private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR);
-	private final JTable theirTable;
-	private final ConflictTableModel resolve = new ConflictTableModel(null);
-	private final JTable resolveTable;
-
-	
-	public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) {
-		super(new GridBagLayout());
-		Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>();
-		possibleConflicts.add(new DeleteConflict());
-		possibleConflicts.add(new PositionConflict());
-		TreeSet<String> allkeys = new TreeSet<String>();
-		for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
-			allkeys.addAll(e.getKey().keySet());
-			allkeys.addAll(e.getValue().keySet());
-		}
-		for (String s : allkeys)
-			possibleConflicts.add(new PropertyConflict(s));
-		
-		for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
-			for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) {
-				ConflictItem ci = it.next();
-				if (ci.hasConflict(e.getKey(), e.getValue())) {
-					ci.initialize(conflicts);
-					this.conflicts.add(ci);
-					it.remove();
-				}
-			}
-		}
-		
-
-		// have to initialize the JTables here and not in the declaration, because its constructor
-		// may access this.conflicts (indirectly)
-		myTable = new JTable(my);
-		theirTable = new JTable(their);
-		resolveTable = new JTable(resolve);
-		
-		myTable.setPreferredScrollableViewportSize(new Dimension(250,70));
-		theirTable.setPreferredScrollableViewportSize(new Dimension(250,70));
-		resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70));
-
-		TableCellRenderer renderer = new DefaultTableCellRenderer(){
-			final Font defFont = new JLabel().getFont();
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-				c.setIcon(null);
-				c.setFont(defFont);
-				if (value instanceof JLabel) {
-					JLabel l = (JLabel)value;
-					String text = l.getText();
-					c.setText(text);
-					c.setFont(l.getFont());
-					if (text.startsWith("<html>") && l.getFont().isBold())
-						c.setText("<html>"+"<b>"+text.substring(6, text.length()-12));
-				} else {
-					String s = value.toString();
-					int i = s.indexOf('|');
-					if (i != -1) {
-						c.setIcon(ImageProvider.get("data", s.substring(0,i)));
-						c.setText(s.substring(i+1));
-					}
-				}
-				return c;
-			}
-		};
-		myTable.setDefaultRenderer(Object.class, renderer);
-		theirTable.setDefaultRenderer(Object.class, renderer);
-		resolveTable.setDefaultRenderer(Object.class, renderer);
-
-		myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		ListSelectionListener selListener = new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
-					myTable.clearSelection();
-					theirTable.clearSelection();
-					resolveTable.clearSelection();
-				} else {
-					int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex();
-					myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true));
-					myTable.getSelectionModel().setSelectionInterval(i, i);
-					theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true));
-					theirTable.getSelectionModel().setSelectionInterval(i, i);
-					resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true));
-					resolveTable.getSelectionModel().setSelectionInterval(i, i);
-				}
-			}
-		};
-		myTable.getSelectionModel().addListSelectionListener(selListener);
-		theirTable.getSelectionModel().addListSelectionListener(selListener);
-		resolveTable.getSelectionModel().addListSelectionListener(selListener);
-		myTable.getSelectionModel().setSelectionInterval(0,0);
-
-		myTable.addMouseListener(new DblClickListener(Resolution.MY));
-		theirTable.addMouseListener(new DblClickListener(Resolution.THEIR));
-		resolveTable.addMouseListener(new DblClickListener(null));
-
-		add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10));
-
-		JPanel p = new JPanel(new GridBagLayout());
-		p.add(new JLabel(tr("my version:")), GBC.eol());
-		p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH));
-		p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
-		add(p, GBC.std().insets(0,0,5,0));
-
-		p = new JPanel(new GridBagLayout());
-		p.add(new JLabel(tr("their version:")), GBC.eol());
-		p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH));
-		p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
-		add(p, GBC.eop().insets(5,0,0,0));
-
-		add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER));
-		add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0));
-		add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH));
-	}
+    public static enum Resolution {MY, THEIR}
+
+    private final class ConflictTableModel implements TableModel {
+        private final Resolution resolution;
+        public ConflictTableModel(Resolution resolution) {
+            this.resolution = resolution;
+        }
+
+        public int getRowCount() {
+            return conflicts.size();
+        }
+
+        public Object getValueAt(int rowIndex, int columnIndex) {
+            ConflictItem ci = conflicts.get(rowIndex);
+            if (columnIndex == 0)
+                return ci.key();
+            Resolution r = resolution == null ? ci.resolution : resolution;
+            if (r == null)
+                return "<html><i>???</i></html>";
+            JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their);
+            if (ci.resolution == resolution && resolution != null)
+                l.setFont(l.getFont().deriveFont(Font.BOLD));
+            return l;
+        }
+
+        public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");}
+        public int getColumnCount() {return 2;}
+        public boolean isCellEditable(int row, int column) {return false;}
+        public Class<?> getColumnClass(int columnIndex) {return Object.class;}
+
+        public void addTableModelListener(TableModelListener l) {}
+        public void removeTableModelListener(TableModelListener l) {}
+        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
+    }
+
+    private final class DblClickListener extends MouseAdapter {
+        private final Resolution resolution;
+        public DblClickListener(Resolution resolution) {
+            this.resolution = resolution;
+        }
+        @Override public void mouseClicked(MouseEvent e) {
+            if (e.getClickCount() >= 2) {
+                int sel = ((JTable)e.getSource()).getSelectedRow();
+                if (sel == -1)
+                    return;
+                ConflictResolver.this.conflicts.get(sel).resolution = resolution;
+                repaint();
+            }
+        }
+    }
+    private final class ResolveAction extends AbstractAction {
+        private final Resolution resolution;
+        public ResolveAction(String name, Resolution resolution) {
+            super(null, ImageProvider.get("dialogs", name));
+            this.resolution = resolution;
+        }
+        public void actionPerformed(ActionEvent e) {
+            int sel = myTable.getSelectedRow();
+            if (sel == -1)
+                return;
+            conflicts.get(sel).resolution = resolution;
+            if (sel == myTable.getRowCount()-1)
+                myTable.clearSelection();
+            else
+                myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1);
+            repaint();
+        }
+    }
+
+    public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>();
+
+    private final ConflictTableModel my = new ConflictTableModel(Resolution.MY);
+    private final JTable myTable;
+    private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR);
+    private final JTable theirTable;
+    private final ConflictTableModel resolve = new ConflictTableModel(null);
+    private final JTable resolveTable;
+
+
+    public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) {
+        super(new GridBagLayout());
+        Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>();
+        possibleConflicts.add(new DeleteConflict());
+        possibleConflicts.add(new PositionConflict());
+        TreeSet<String> allkeys = new TreeSet<String>();
+        for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
+            allkeys.addAll(e.getKey().keySet());
+            allkeys.addAll(e.getValue().keySet());
+        }
+        for (String s : allkeys)
+            possibleConflicts.add(new PropertyConflict(s));
+
+        for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
+            for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) {
+                ConflictItem ci = it.next();
+                if (ci.hasConflict(e.getKey(), e.getValue())) {
+                    ci.initialize(conflicts);
+                    this.conflicts.add(ci);
+                    it.remove();
+                }
+            }
+        }
+
+
+        // have to initialize the JTables here and not in the declaration, because its constructor
+        // may access this.conflicts (indirectly)
+        myTable = new JTable(my);
+        theirTable = new JTable(their);
+        resolveTable = new JTable(resolve);
+
+        myTable.setPreferredScrollableViewportSize(new Dimension(250,70));
+        theirTable.setPreferredScrollableViewportSize(new Dimension(250,70));
+        resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70));
+
+        TableCellRenderer renderer = new DefaultTableCellRenderer(){
+            final Font defFont = new JLabel().getFont();
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+                c.setIcon(null);
+                c.setFont(defFont);
+                if (value instanceof JLabel) {
+                    JLabel l = (JLabel)value;
+                    String text = l.getText();
+                    c.setText(text);
+                    c.setFont(l.getFont());
+                    if (text.startsWith("<html>") && l.getFont().isBold())
+                        c.setText("<html>"+"<b>"+text.substring(6, text.length()-12));
+                } else {
+                    String s = value.toString();
+                    int i = s.indexOf('|');
+                    if (i != -1) {
+                        c.setIcon(ImageProvider.get("data", s.substring(0,i)));
+                        c.setText(s.substring(i+1));
+                    }
+                }
+                return c;
+            }
+        };
+        myTable.setDefaultRenderer(Object.class, renderer);
+        theirTable.setDefaultRenderer(Object.class, renderer);
+        resolveTable.setDefaultRenderer(Object.class, renderer);
+
+        myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        ListSelectionListener selListener = new ListSelectionListener(){
+            public void valueChanged(ListSelectionEvent e) {
+                if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
+                    myTable.clearSelection();
+                    theirTable.clearSelection();
+                    resolveTable.clearSelection();
+                } else {
+                    int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex();
+                    myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true));
+                    myTable.getSelectionModel().setSelectionInterval(i, i);
+                    theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true));
+                    theirTable.getSelectionModel().setSelectionInterval(i, i);
+                    resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true));
+                    resolveTable.getSelectionModel().setSelectionInterval(i, i);
+                }
+            }
+        };
+        myTable.getSelectionModel().addListSelectionListener(selListener);
+        theirTable.getSelectionModel().addListSelectionListener(selListener);
+        resolveTable.getSelectionModel().addListSelectionListener(selListener);
+        myTable.getSelectionModel().setSelectionInterval(0,0);
+
+        myTable.addMouseListener(new DblClickListener(Resolution.MY));
+        theirTable.addMouseListener(new DblClickListener(Resolution.THEIR));
+        resolveTable.addMouseListener(new DblClickListener(null));
+
+        add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10));
+
+        JPanel p = new JPanel(new GridBagLayout());
+        p.add(new JLabel(tr("my version:")), GBC.eol());
+        p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH));
+        p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
+        add(p, GBC.std().insets(0,0,5,0));
+
+        p = new JPanel(new GridBagLayout());
+        p.add(new JLabel(tr("their version:")), GBC.eol());
+        p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH));
+        p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
+        add(p, GBC.eop().insets(5,0,0,0));
+
+        add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER));
+        add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0));
+        add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/GettingStarted.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 1169)
@@ -25,5 +25,5 @@
 public class GettingStarted extends JPanel {
 
-    static private String content = "";    
+    static private String content = "";
 
     public class LinkGeneral extends JEditorPane implements HyperlinkListener {
@@ -74,5 +74,5 @@
                 boolean included = false;
                 if (condition.equals("%3E")) {
-                    if ((myVersion == 0 || myVersion > targetVersion) 
+                    if ((myVersion == 0 || myVersion > targetVersion)
                         /* && ! Main.pref.getBoolean("motd.gt."+targetVersion) */) {
                         /* Main.pref.put("motd.gt."+targetVersion, true); */
@@ -80,5 +80,5 @@
                     }
                 } else if (condition.equals("%3E%3D")) {
-                    if ((myVersion == 0 || myVersion >= targetVersion) 
+                    if ((myVersion == 0 || myVersion >= targetVersion)
                         /* && ! Main.pref.getBoolean("motd.ge."+targetVersion) */) {
                         /* Main.pref.put("motd.ge."+targetVersion, true); */
@@ -114,20 +114,20 @@
                             content += wr.read(url).replace("<html>", "").replace("</html>", "").replace("<div id=\"searchable\">", "").replace("</div>", "");
                         } catch (IOException ioe2) {
-                        }            
-                    }            
+                        }
+                    }
                 }
             }
             content += motdcontent.substring(start);
             content = content.replace("<html>", "<html><style type=\"text/css\">\nbody { font-family: sans-serif; font-weight: bold; }\nh1 {text-align: center;}</style>");
-            /* replace the wiki title */ 
-            content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor")); 
+            /* replace the wiki title */
+            content = content.replace("JOSM, the Java OpenStreetMap editor", tr("JOSM, the Java OpenStreetMap editor"));
         }
 
     }
-    
+
     public GettingStarted() {
         super(new BorderLayout());
         assignContent();
-                                
+
         // panel.add(GBC.glue(0,1), GBC.eol());
         //panel.setMinimumSize(new Dimension(400, 600));
Index: trunk/src/org/openstreetmap/josm/gui/IconToggleButton.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/IconToggleButton.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/IconToggleButton.java	(revision 1169)
@@ -18,31 +18,31 @@
 public class IconToggleButton extends JToggleButton implements PropertyChangeListener {
 
-	public boolean groupbutton;
+    public boolean groupbutton;
 
-	/**
-	 * Construct the toggle button with the given action.
-	 */
-	public IconToggleButton(Action action) {
-		super(action);
-		setText(null);
+    /**
+     * Construct the toggle button with the given action.
+     */
+    public IconToggleButton(Action action) {
+        super(action);
+        setText(null);
 
-		Object o = action.getValue(Action.SHORT_DESCRIPTION);
-		if (o != null)
-			setToolTipText(o.toString());
+        Object o = action.getValue(Action.SHORT_DESCRIPTION);
+        if (o != null)
+            setToolTipText(o.toString());
 
-		action.addPropertyChangeListener(this);
-		
-		addMouseListener(new MouseAdapter(){
-			@Override public void mousePressed(MouseEvent e) {
-				groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2;
+        action.addPropertyChangeListener(this);
+
+        addMouseListener(new MouseAdapter(){
+            @Override public void mousePressed(MouseEvent e) {
+                groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2;
             }
-		});
-	}
+        });
+    }
 
-	public void propertyChange(PropertyChangeEvent evt) {
-		if (evt.getPropertyName().equals("active")) {
-			setSelected((Boolean)evt.getNewValue());
-			requestFocusInWindow();
-		}
-	}
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getPropertyName().equals("active")) {
+            setSelected((Boolean)evt.getNewValue());
+            requestFocusInWindow();
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java	(revision 1169)
@@ -1,5 +1,5 @@
 // License: GPL. For details, see LICENSE file.
 
-// This class was taken from 
+// This class was taken from
 // http://forum.java.sun.com/thread.jspa?threadID=459705&messageID=2104021
 // - Removed hardcoded margin
@@ -22,93 +22,93 @@
 
 public class JMultilineLabel extends JComponent {
-	private String text;
-	private int maxWidth = Integer.MAX_VALUE;
-	private boolean justify;
-	private final FontRenderContext frc = new FontRenderContext(null, false, false);
+    private String text;
+    private int maxWidth = Integer.MAX_VALUE;
+    private boolean justify;
+    private final FontRenderContext frc = new FontRenderContext(null, false, false);
 
-	public JMultilineLabel(String description) {
-		super();
-		setText(description);
-	}
+    public JMultilineLabel(String description) {
+        super();
+        setText(description);
+    }
 
-	private void morph() {
-		revalidate();
-		repaint();
-	}
+    private void morph() {
+        revalidate();
+        repaint();
+    }
 
-	public String getText() {
-		return text;
-	}
+    public String getText() {
+        return text;
+    }
 
-	public void setText(String text) {
-		String old = this.text;
-		this.text = text;
-		firePropertyChange("text", old, this.text);
-		if ((old == null) ? text!=null : !old.equals(text))
-			morph();
-	}
+    public void setText(String text) {
+        String old = this.text;
+        this.text = text;
+        firePropertyChange("text", old, this.text);
+        if ((old == null) ? text!=null : !old.equals(text))
+            morph();
+    }
 
-	public int getMaxWidth() {
-		return maxWidth;
-	}
+    public int getMaxWidth() {
+        return maxWidth;
+    }
 
-	public void setMaxWidth(int maxWidth) {
-		if (maxWidth <= 0)
-			throw new IllegalArgumentException();
-		int old = this.maxWidth;
-		this.maxWidth = maxWidth;
-		firePropertyChange("maxWidth", old, this.maxWidth);
-		if (old !=	this.maxWidth)
-			morph();
-	}
+    public void setMaxWidth(int maxWidth) {
+        if (maxWidth <= 0)
+            throw new IllegalArgumentException();
+        int old = this.maxWidth;
+        this.maxWidth = maxWidth;
+        firePropertyChange("maxWidth", old, this.maxWidth);
+        if (old !=  this.maxWidth)
+            morph();
+    }
 
-	public boolean isJustified() {
-		return justify;
-	}
+    public boolean isJustified() {
+        return justify;
+    }
 
-	public void setJustified(boolean justify) {
-		boolean old = this.justify;
-		this.justify = justify;
-		firePropertyChange("justified", old, this.justify);
-		if (old != this.justify)
-			repaint();
-	}
+    public void setJustified(boolean justify) {
+        boolean old = this.justify;
+        this.justify = justify;
+        firePropertyChange("justified", old, this.justify);
+        if (old != this.justify)
+            repaint();
+    }
 
-	public Dimension getPreferredSize() {
-		return paintOrGetSize(null, getMaxWidth());
-	}
+    public Dimension getPreferredSize() {
+        return paintOrGetSize(null, getMaxWidth());
+    }
 
-	public Dimension getMinimumSize() {
-		return getPreferredSize();
-	}
+    public Dimension getMinimumSize() {
+        return getPreferredSize();
+    }
 
-	protected void paintComponent(Graphics g) {
-		super.paintComponent(g);
-		paintOrGetSize((Graphics2D)g, getWidth());
-	}
+    protected void paintComponent(Graphics g) {
+        super.paintComponent(g);
+        paintOrGetSize((Graphics2D)g, getWidth());
+    }
 
-	private Dimension paintOrGetSize(Graphics2D g, int width) {
-		Insets insets = getInsets();
-		width -= insets.left + insets.right;
-		float w = insets.left + insets.right;
-		float x = insets.left, y=insets.top;
-		if (width > 0 && text != null && text.length() > 0) {
-			AttributedString as = new AttributedString(getText());
-			as.addAttribute(TextAttribute.FONT, getFont());
-			AttributedCharacterIterator aci = as.getIterator();
-			LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
-			float max = 0;
-			while (lbm.getPosition() < aci.getEndIndex()) {
-				TextLayout textLayout = lbm.nextLayout(width);
-				if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width)
-					textLayout = textLayout.getJustifiedLayout(width);
-				if (g != null)
-					textLayout.draw(g, x, y + textLayout.getAscent());
-				y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
-				max = Math.max(max, textLayout.getVisibleAdvance());
-			}
-			w += max;
-		}
-		return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom);
-	}
+    private Dimension paintOrGetSize(Graphics2D g, int width) {
+        Insets insets = getInsets();
+        width -= insets.left + insets.right;
+        float w = insets.left + insets.right;
+        float x = insets.left, y=insets.top;
+        if (width > 0 && text != null && text.length() > 0) {
+            AttributedString as = new AttributedString(getText());
+            as.addAttribute(TextAttribute.FONT, getFont());
+            AttributedCharacterIterator aci = as.getIterator();
+            LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
+            float max = 0;
+            while (lbm.getPosition() < aci.getEndIndex()) {
+                TextLayout textLayout = lbm.nextLayout(width);
+                if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width)
+                    textLayout = textLayout.getJustifiedLayout(width);
+                if (g != null)
+                    textLayout.draw(g, x, y + textLayout.getAscent());
+                y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
+                max = Math.max(max, textLayout.getVisibleAdvance());
+            }
+            w += max;
+        }
+        return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MainApplet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplet.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplet.java	(revision 1169)
@@ -33,133 +33,133 @@
 public class MainApplet extends JApplet {
 
-	public static final class UploadPreferencesAction extends JosmAction {
-		public UploadPreferencesAction() {
-			super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"),
-			Shortcut.registerShortcut("applet:uploadprefs", tr("Upload Preferences"), KeyEvent.VK_U, Shortcut.GROUP_HOTKEY), true);
+    public static final class UploadPreferencesAction extends JosmAction {
+        public UploadPreferencesAction() {
+            super(tr("Upload Preferences"), "upload-preferences", tr("Upload the current preferences to the server"),
+            Shortcut.registerShortcut("applet:uploadprefs", tr("Upload Preferences"), KeyEvent.VK_U, Shortcut.GROUP_HOTKEY), true);
         }
-	    public void actionPerformed(ActionEvent e) {
-	    	((ServerSidePreferences)Main.pref).upload();
-	    }
+        public void actionPerformed(ActionEvent e) {
+            ((ServerSidePreferences)Main.pref).upload();
+        }
     }
 
     private final class MainCaller extends Main {
-		private MainCaller() {
-			setContentPane(contentPane);
-			setJMenuBar(menu);
-			setBounds(bounds);
-		}
-	}
+        private MainCaller() {
+            setContentPane(contentPane);
+            setJMenuBar(menu);
+            setBounds(bounds);
+        }
+    }
 
-	private final static String[][] paramInfo = {
-		{"username", tr("string"), tr("Name of the user.")},
-		{"password", tr("string"), tr("OSM Password.")},
-		{"geometry", tr("string"), tr("Resize the applet to the given geometry (format: WIDTHxHEIGHT)")},
-		{"download", tr("string;string;..."), tr("Download each. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
-		{"downloadgps", tr("string;string;..."), tr("Download each as raw gps. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
-		{"selection", tr("string;string;..."), tr("Add each to the initial selection. Can be a google-like search string or an url which returns osm-xml")},
-		{"reset-preferences", tr("any"),tr("If specified, reset the configuration instead of reading it.")}
-	};
+    private final static String[][] paramInfo = {
+        {"username", tr("string"), tr("Name of the user.")},
+        {"password", tr("string"), tr("OSM Password.")},
+        {"geometry", tr("string"), tr("Resize the applet to the given geometry (format: WIDTHxHEIGHT)")},
+        {"download", tr("string;string;..."), tr("Download each. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
+        {"downloadgps", tr("string;string;..."), tr("Download each as raw gps. Can be x1,y1,x2,y2 an url containing lat=y&lon=x&zoom=z or a filename")},
+        {"selection", tr("string;string;..."), tr("Add each to the initial selection. Can be a google-like search string or an url which returns osm-xml")},
+        {"reset-preferences", tr("any"),tr("If specified, reset the configuration instead of reading it.")}
+    };
 
-	private Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
+    private Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
 
-	@Override public String[][] getParameterInfo() {
-		return paramInfo;
-	}
+    @Override public String[][] getParameterInfo() {
+        return paramInfo;
+    }
 
-	@Override public void init() {
-		for (String[] s : paramInfo) {
-			Collection<String> p = readParameter(s[0], args.get(s[0]));
-			if (p != null)
-				args.put(s[0], p);
-		}
-		if (!args.containsKey("geometry") && getParameter("width") != null && getParameter("height") != null) {
-			args.put("geometry", Arrays.asList(new String[]{getParameter("width")+"x"+getParameter("height")}));
-		}
-	}
+    @Override public void init() {
+        for (String[] s : paramInfo) {
+            Collection<String> p = readParameter(s[0], args.get(s[0]));
+            if (p != null)
+                args.put(s[0], p);
+        }
+        if (!args.containsKey("geometry") && getParameter("width") != null && getParameter("height") != null) {
+            args.put("geometry", Arrays.asList(new String[]{getParameter("width")+"x"+getParameter("height")}));
+        }
+    }
 
-	@Override public void start() {
-		String username = args.containsKey("username") ? args.get("username").iterator().next() : null;
-		String password = args.containsKey("password") ? args.get("password").iterator().next() : null;
-		if (username == null || password == null) {
-			JPanel p = new JPanel(new GridBagLayout());
-			p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,20,0));
-			JTextField user = new JTextField(username == null ? "" : username);
-			p.add(user, GBC.eol().fill(GBC.HORIZONTAL));
-			p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,20,0));
-			JPasswordField pass = new JPasswordField(password == null ? "" : password);
-			p.add(pass, GBC.eol().fill(GBC.HORIZONTAL));
-			JOptionPane.showMessageDialog(null, p);
-			username = user.getText();
-			password = new String(pass.getPassword());
-			args.put("password", Arrays.asList(new String[]{password}));
-		}
+    @Override public void start() {
+        String username = args.containsKey("username") ? args.get("username").iterator().next() : null;
+        String password = args.containsKey("password") ? args.get("password").iterator().next() : null;
+        if (username == null || password == null) {
+            JPanel p = new JPanel(new GridBagLayout());
+            p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,20,0));
+            JTextField user = new JTextField(username == null ? "" : username);
+            p.add(user, GBC.eol().fill(GBC.HORIZONTAL));
+            p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,20,0));
+            JPasswordField pass = new JPasswordField(password == null ? "" : password);
+            p.add(pass, GBC.eol().fill(GBC.HORIZONTAL));
+            JOptionPane.showMessageDialog(null, p);
+            username = user.getText();
+            password = new String(pass.getPassword());
+            args.put("password", Arrays.asList(new String[]{password}));
+        }
 
-		Main.applet = true;
-		Main.pref = new ServerSidePreferences(getCodeBase());
-		((ServerSidePreferences)Main.pref).download(username, password);
+        Main.applet = true;
+        Main.pref = new ServerSidePreferences(getCodeBase());
+        ((ServerSidePreferences)Main.pref).download(username, password);
 
-		Main.preConstructorInit(args);
-		Main.parent = this;
-		new MainCaller().postConstructorProcessCmdLine(args);
+        Main.preConstructorInit(args);
+        Main.parent = this;
+        new MainCaller().postConstructorProcessCmdLine(args);
 
-		MainMenu m = Main.main.menu; // shortcut
+        MainMenu m = Main.main.menu; // shortcut
 
-		// remove offending stuff from JOSM (that would break the SecurityManager)
-		m.remove(m.fileMenu);
-		m.editMenu.add(new UploadPreferencesAction());
-		m.openFile.setEnabled(false);
-		m.exit.setEnabled(false);
-		m.save.setEnabled(false);
-		m.saveAs.setEnabled(false);
-		m.gpxExport.setEnabled(false);
-	}
+        // remove offending stuff from JOSM (that would break the SecurityManager)
+        m.remove(m.fileMenu);
+        m.editMenu.add(new UploadPreferencesAction());
+        m.openFile.setEnabled(false);
+        m.exit.setEnabled(false);
+        m.save.setEnabled(false);
+        m.saveAs.setEnabled(false);
+        m.gpxExport.setEnabled(false);
+    }
 
-	private Collection<String> readParameter(String s, Collection<String> v) {
-		String param = getParameter(s);
-		if (param != null) {
-			if (v == null)
-				v = new LinkedList<String>();
-			v.addAll(Arrays.asList(param.split(";")));
-		}
-		return v;
-	}
+    private Collection<String> readParameter(String s, Collection<String> v) {
+        String param = getParameter(s);
+        if (param != null) {
+            if (v == null)
+                v = new LinkedList<String>();
+            v.addAll(Arrays.asList(param.split(";")));
+        }
+        return v;
+    }
 
-	public static void main(String[] args) {
-		final JFrame frame = new JFrame("Java OpenStreetMap Applet");
-		MainApplet applet = new MainApplet();
-		applet.setStub(new AppletStub() {
-			public void appletResize(int w, int h) {
-				frame.setSize(w, h);
-			}
+    public static void main(String[] args) {
+        final JFrame frame = new JFrame("Java OpenStreetMap Applet");
+        MainApplet applet = new MainApplet();
+        applet.setStub(new AppletStub() {
+            public void appletResize(int w, int h) {
+                frame.setSize(w, h);
+            }
 
-			public AppletContext getAppletContext() {
-				return null;
-			}
+            public AppletContext getAppletContext() {
+                return null;
+            }
 
-			public URL getCodeBase() {
-				try {
-					return new File(".").toURI().toURL();
-				} catch (Exception e) {
-					e.printStackTrace();
-					return null;
-				}
-			}
+            public URL getCodeBase() {
+                try {
+                    return new File(".").toURI().toURL();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return null;
+                }
+            }
 
-			public URL getDocumentBase() {
-				return getCodeBase();
-			}
+            public URL getDocumentBase() {
+                return getCodeBase();
+            }
 
-			public String getParameter(String k) {
-				return null;
-			}
+            public String getParameter(String k) {
+                return null;
+            }
 
-			public boolean isActive() {
-				return true;
-			}
-		});
-		applet.init();
-		applet.start();
-		frame.setContentPane(applet);
-		frame.setVisible(true);
-	}
+            public boolean isActive() {
+                return true;
+            }
+        });
+        applet.init();
+        applet.start();
+        frame.setContentPane(applet);
+        frame.setVisible(true);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 1169)
@@ -37,156 +37,156 @@
  */
 public class MainApplication extends Main {
-	/**
-	 * Allow subclassing (see JOSM.java)
-	 */
-	public MainApplication() {}
-
-	/**
-	 * Construct an main frame, ready sized and operating. Does not
-	 * display the frame.
-	 */
-	public MainApplication(JFrame mainFrame) {
-		super();
-		mainFrame.setContentPane(contentPane);
-		mainFrame.setJMenuBar(menu);
-		mainFrame.setBounds(bounds);
-		mainFrame.setIconImage(ImageProvider.get("logo.png").getImage());
-		mainFrame.addWindowListener(new WindowAdapter(){
-			@Override public void windowClosing(final WindowEvent arg0) {
-				if (Main.breakBecauseUnsavedChanges())
-					return;
-				System.exit(0);
-			}
-		});
-		mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-	}
-
-	/**
-	 * Main application Startup
-	 */
-	public static void main(final String[] argArray) {
-		/////////////////////////////////////////////////////////////////////////
-		//                        TO ALL TRANSLATORS
-		/////////////////////////////////////////////////////////////////////////
-		// Do not translate the early strings below until the locale is set up.
-		// (By the eager loaded plugins)
-		//
-		// These strings cannot be translated. That's life. Really. Sorry.
-		//
-		//                                                                 Imi.
-		/////////////////////////////////////////////////////////////////////////
-
-		Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
-
-		// initialize the plaform hook, and
-		Main.determinePlatformHook();
-		// call the really early hook before we anything else
-		Main.platform.preStartupHook();
-
-		// construct argument table
-		List<String> argList = Arrays.asList(argArray);
-		final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
-		for (String arg : argArray) {
-			if (!arg.startsWith("--"))
-				arg = "--download="+arg;
-			int i = arg.indexOf('=');
-			String key = i == -1 ? arg.substring(2) : arg.substring(2,i);
-			String value = i == -1 ? "" : arg.substring(i+1);
-			Collection<String> v = args.get(key);
-			if (v == null)
-				v = new LinkedList<String>();
-			v.add(value);
-			args.put(key, v);
-		}
-
-		if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
-			// TODO: put in a platformHook for system that have no console by default
-			System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+
-					tr("usage")+":\n"+
-					"\tjava -jar josm.jar <option> <option> <option>...\n\n"+
-					tr("options")+":\n"+
-					"\t--help|-?|-h                              "+tr("Show this help")+"\n"+
-					"\t--geometry=widthxheight(+|-)x(+|-)y       "+tr("Standard unix geometry argument")+"\n"+
-					"\t[--download=]minlat,minlon,maxlat,maxlon  "+tr("Download the bounding box")+"\n"+
-					"\t[--download=]<url>                        "+tr("Download the location at the url (with lat=x&lon=y&zoom=z)")+"\n"+
-					"\t[--download=]<filename>                   "+tr("Open file (as raw gps, if .gpx)")+"\n"+
-					"\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw gps")+"\n"+
-					"\t--selection=<searchstring>                "+tr("Select with the given search")+"\n"+
-					"\t--no-fullscreen                           "+tr("Don't launch in fullscreen mode")+"\n"+
-					"\t--reset-preferences                       "+tr("Reset the preferences to default")+"\n\n"+
-					"\t--language=<language>                     "+tr("Set the language.")+"\n\n"+
-					tr("examples")+":\n"+
-					"\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
-					"\tjava -jar josm.jar http://www.openstreetmap.org/index.html?lat=43.2&lon=11.1&zoom=13\n"+
-					"\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
-					"\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n\n"+
-
-					tr("Parameters are read in the order they are specified, so make sure you load\n"+
-					"some data before --selection")+"\n\n"+
-					tr("Instead of --download=<bbox> you may specify osm://<bbox>\n"));
-			System.exit(0);
-		}
-
-		// get the preferences.
-		final File prefDir = new File(Main.pref.getPreferencesDir());
-		// check if preferences directory has moved (TODO: Update code. Remove this after some time)
-		File oldPrefDir = new File(System.getProperty("user.home"), ".josm");
-		if (!prefDir.isDirectory() && oldPrefDir.isDirectory()) {
-			if (oldPrefDir.renameTo(prefDir)) {
-				// do not translate this
-				JOptionPane.showMessageDialog(null, "The preference directory has been moved to "+prefDir);
-			} else {
-				JOptionPane.showMessageDialog(null, "The preference directory location has changed. Please move "+oldPrefDir+" to "+prefDir);
-			}
-		}
-
-		if (prefDir.exists() && !prefDir.isDirectory()) {
-			JOptionPane.showMessageDialog(null, "Cannot open preferences directory: "+Main.pref.getPreferencesDir());
-			return;
-		}
-		if (!prefDir.exists())
-			prefDir.mkdirs();
-
-		if (!new File(Main.pref.getPreferencesDir()+"preferences").exists()) {
-			Main.pref.resetToDefault();
-		}
-
-		try {
-			if (args.containsKey("reset-preferences")) {
-				Main.pref.resetToDefault();
-			} else {
-				Main.pref.load();
-			}
-		} catch (final IOException e1) {
-			e1.printStackTrace();
-			String backup = Main.pref.getPreferencesDir() + "preferences.bak";
-			JOptionPane.showMessageDialog(null, "Preferences file had errors.  Making backup of old one to " + backup);
-			new File(Main.pref.getPreferencesDir() + "preferences").renameTo(new File(backup));
-			Main.pref.save();
-		}
+    /**
+     * Allow subclassing (see JOSM.java)
+     */
+    public MainApplication() {}
+
+    /**
+     * Construct an main frame, ready sized and operating. Does not
+     * display the frame.
+     */
+    public MainApplication(JFrame mainFrame) {
+        super();
+        mainFrame.setContentPane(contentPane);
+        mainFrame.setJMenuBar(menu);
+        mainFrame.setBounds(bounds);
+        mainFrame.setIconImage(ImageProvider.get("logo.png").getImage());
+        mainFrame.addWindowListener(new WindowAdapter(){
+            @Override public void windowClosing(final WindowEvent arg0) {
+                if (Main.breakBecauseUnsavedChanges())
+                    return;
+                System.exit(0);
+            }
+        });
+        mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    }
+
+    /**
+     * Main application Startup
+     */
+    public static void main(final String[] argArray) {
+        /////////////////////////////////////////////////////////////////////////
+        //                        TO ALL TRANSLATORS
+        /////////////////////////////////////////////////////////////////////////
+        // Do not translate the early strings below until the locale is set up.
+        // (By the eager loaded plugins)
+        //
+        // These strings cannot be translated. That's life. Really. Sorry.
+        //
+        //                                                                 Imi.
+        /////////////////////////////////////////////////////////////////////////
+
+        Thread.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler());
+
+        // initialize the plaform hook, and
+        Main.determinePlatformHook();
+        // call the really early hook before we anything else
+        Main.platform.preStartupHook();
+
+        // construct argument table
+        List<String> argList = Arrays.asList(argArray);
+        final Map<String, Collection<String>> args = new HashMap<String, Collection<String>>();
+        for (String arg : argArray) {
+            if (!arg.startsWith("--"))
+                arg = "--download="+arg;
+            int i = arg.indexOf('=');
+            String key = i == -1 ? arg.substring(2) : arg.substring(2,i);
+            String value = i == -1 ? "" : arg.substring(i+1);
+            Collection<String> v = args.get(key);
+            if (v == null)
+                v = new LinkedList<String>();
+            v.add(value);
+            args.put(key, v);
+        }
+
+        if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
+            // TODO: put in a platformHook for system that have no console by default
+            System.out.println(tr("Java OpenStreetMap Editor")+"\n\n"+
+                    tr("usage")+":\n"+
+                    "\tjava -jar josm.jar <option> <option> <option>...\n\n"+
+                    tr("options")+":\n"+
+                    "\t--help|-?|-h                              "+tr("Show this help")+"\n"+
+                    "\t--geometry=widthxheight(+|-)x(+|-)y       "+tr("Standard unix geometry argument")+"\n"+
+                    "\t[--download=]minlat,minlon,maxlat,maxlon  "+tr("Download the bounding box")+"\n"+
+                    "\t[--download=]<url>                        "+tr("Download the location at the url (with lat=x&lon=y&zoom=z)")+"\n"+
+                    "\t[--download=]<filename>                   "+tr("Open file (as raw gps, if .gpx)")+"\n"+
+                    "\t--downloadgps=minlat,minlon,maxlat,maxlon "+tr("Download the bounding box as raw gps")+"\n"+
+                    "\t--selection=<searchstring>                "+tr("Select with the given search")+"\n"+
+                    "\t--no-fullscreen                           "+tr("Don't launch in fullscreen mode")+"\n"+
+                    "\t--reset-preferences                       "+tr("Reset the preferences to default")+"\n\n"+
+                    "\t--language=<language>                     "+tr("Set the language.")+"\n\n"+
+                    tr("examples")+":\n"+
+                    "\tjava -jar josm.jar track1.gpx track2.gpx london.osm\n"+
+                    "\tjava -jar josm.jar http://www.openstreetmap.org/index.html?lat=43.2&lon=11.1&zoom=13\n"+
+                    "\tjava -jar josm.jar london.osm --selection=http://www.ostertag.name/osm/OSM_errors_node-duplicate.xml\n"+
+                    "\tjava -jar josm.jar 43.2,11.1,43.4,11.4\n\n"+
+
+                    tr("Parameters are read in the order they are specified, so make sure you load\n"+
+                    "some data before --selection")+"\n\n"+
+                    tr("Instead of --download=<bbox> you may specify osm://<bbox>\n"));
+            System.exit(0);
+        }
+
+        // get the preferences.
+        final File prefDir = new File(Main.pref.getPreferencesDir());
+        // check if preferences directory has moved (TODO: Update code. Remove this after some time)
+        File oldPrefDir = new File(System.getProperty("user.home"), ".josm");
+        if (!prefDir.isDirectory() && oldPrefDir.isDirectory()) {
+            if (oldPrefDir.renameTo(prefDir)) {
+                // do not translate this
+                JOptionPane.showMessageDialog(null, "The preference directory has been moved to "+prefDir);
+            } else {
+                JOptionPane.showMessageDialog(null, "The preference directory location has changed. Please move "+oldPrefDir+" to "+prefDir);
+            }
+        }
+
+        if (prefDir.exists() && !prefDir.isDirectory()) {
+            JOptionPane.showMessageDialog(null, "Cannot open preferences directory: "+Main.pref.getPreferencesDir());
+            return;
+        }
+        if (!prefDir.exists())
+            prefDir.mkdirs();
+
+        if (!new File(Main.pref.getPreferencesDir()+"preferences").exists()) {
+            Main.pref.resetToDefault();
+        }
+
+        try {
+            if (args.containsKey("reset-preferences")) {
+                Main.pref.resetToDefault();
+            } else {
+                Main.pref.load();
+            }
+        } catch (final IOException e1) {
+            e1.printStackTrace();
+            String backup = Main.pref.getPreferencesDir() + "preferences.bak";
+            JOptionPane.showMessageDialog(null, "Preferences file had errors.  Making backup of old one to " + backup);
+            new File(Main.pref.getPreferencesDir() + "preferences").renameTo(new File(backup));
+            Main.pref.save();
+        }
 
         // TODO remove this in early 2009 - just here to weed out color setting we don't use any more
         Main.pref.put("downloaded Area", null);
 
-		String localeName = null; //The locale to use
-        
-		//Check if passed as parameter
-		if(args.containsKey("language")) 
-		    localeName = (String)(args.get("language").toArray()[0]);
-		
-		if (localeName == null) {
-			localeName = Main.pref.get("language", null);
-		}
-
-		if (localeName != null) {
-			Locale l;
-			int i = localeName.indexOf('_');
-			if (i > 0) {
-				l = new Locale(localeName.substring(0, i), localeName.substring(i + 1));
-			} else {
-				l = new Locale(localeName);
-			}
-			Locale.setDefault(l);
-		}
+        String localeName = null; //The locale to use
+
+        //Check if passed as parameter
+        if(args.containsKey("language"))
+            localeName = (String)(args.get("language").toArray()[0]);
+
+        if (localeName == null) {
+            localeName = Main.pref.get("language", null);
+        }
+
+        if (localeName != null) {
+            Locale l;
+            int i = localeName.indexOf('_');
+            if (i > 0) {
+                l = new Locale(localeName.substring(0, i), localeName.substring(i + 1));
+            } else {
+                l = new Locale(localeName);
+            }
+            Locale.setDefault(l);
+        }
         try {
             i18n = I18nFactory.getI18n(MainApplication.class);
@@ -194,40 +194,40 @@
             System.out.println("Unable to find translation for the locale: " + Locale.getDefault().getDisplayName() + " reverting to English.");
         }
-		
-		SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true));
-
-		splash.setStatus(tr("Activating updated plugins"));
-		if (!PluginDownloader.moveUpdatedPlugins()) {
-			JOptionPane.showMessageDialog(null,
-			        tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."),
-			        tr("Plugins"), JOptionPane.ERROR_MESSAGE);
-		}
-
-		// load the early plugins
-		splash.setStatus(tr("Loading early plugins"));
-		Main.loadPlugins(true);
-
-		splash.setStatus(tr("Setting defaults"));
-		preConstructorInit(args);
-		splash.setStatus(tr("Creating main GUI"));
-		JFrame mainFrame = new JFrame(tr("Java OpenStreetMap - Editor"));
-		Main.parent = mainFrame;
-		final Main main = new MainApplication(mainFrame);
-		splash.setStatus(tr("Loading plugins"));
-		Main.loadPlugins(false);
-		toolbar.refreshToolbarControl();
-
-		mainFrame.setVisible(true);
-		splash.closeSplash();
-
-		if (!args.containsKey("no-fullscreen") && !args.containsKey("geometry") && Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH))
-			mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
-
-		EventQueue.invokeLater(new Runnable(){
-			public void run() {
-				main.postConstructorProcessCmdLine(args);
-			}
-		});
-	}
+
+        SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true));
+
+        splash.setStatus(tr("Activating updated plugins"));
+        if (!PluginDownloader.moveUpdatedPlugins()) {
+            JOptionPane.showMessageDialog(null,
+                    tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."),
+                    tr("Plugins"), JOptionPane.ERROR_MESSAGE);
+        }
+
+        // load the early plugins
+        splash.setStatus(tr("Loading early plugins"));
+        Main.loadPlugins(true);
+
+        splash.setStatus(tr("Setting defaults"));
+        preConstructorInit(args);
+        splash.setStatus(tr("Creating main GUI"));
+        JFrame mainFrame = new JFrame(tr("Java OpenStreetMap - Editor"));
+        Main.parent = mainFrame;
+        final Main main = new MainApplication(mainFrame);
+        splash.setStatus(tr("Loading plugins"));
+        Main.loadPlugins(false);
+        toolbar.refreshToolbarControl();
+
+        mainFrame.setVisible(true);
+        splash.closeSplash();
+
+        if (!args.containsKey("no-fullscreen") && !args.containsKey("geometry") && Toolkit.getDefaultToolkit().isFrameStateSupported(JFrame.MAXIMIZED_BOTH))
+            mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
+
+        EventQueue.invokeLater(new Runnable(){
+            public void run() {
+                main.postConstructorProcessCmdLine(args);
+            }
+        });
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 1169)
@@ -68,7 +68,7 @@
  * This is the JOSM main menu bar. It is overwritten to initialize itself and provide all menu
  * entries as member variables (sort of collect them).
- * 
+ *
  * It also provides possibilities to attach new menu entries (used by plugins).
- * 
+ *
  * @author Immanuel.Scholz
  */
@@ -140,5 +140,5 @@
     /**
      * Add a JosmAction to a menu.
-     * 
+     *
      * This method handles all the shortcut handling. It also makes sure that actions that are
      * handled by the OS are not duplicated on the menu.
@@ -156,5 +156,5 @@
     /**
      * Add a menu to the main menu.
-     * 
+     *
      * This method handles all the shortcut handling.
      */
Index: trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 1169)
@@ -35,169 +35,169 @@
  * One Map frame with one dataset behind. This is the container gui class whose
  * display can be set to the different views.
- * 
+ *
  * @author imi
  */
 public class MapFrame extends JPanel implements Destroyable {
 
-	/**
-	 * The current mode, this frame operates.
-	 */
-	public MapMode mapMode;
-	/**
-	 * The view control displayed.
-	 */
-	public MapView mapView;
-	/**
-	 * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog
-	 * instead of adding directly to this list. To add a new mode use addMapMode.
-	 */
-	public JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL);
-	public JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL);
-	/**
-	 * The status line below the map
-	 */
-	public MapStatus statusLine;
-
-	public ConflictDialog conflictDialog;
-	/**
-	 * The dialog that shows all relations and lets the user edit them.
-	 */
-	public RelationListDialog relationListDialog;
-	/**
-	 * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog
-	 * instead of adding directly to this list.
-	 */
-	public JPanel toggleDialogs = new JPanel();
-
-	public final ButtonGroup toolGroup = new ButtonGroup();
-
-	public MapFrame() {
-		setSize(400,400);
-		setLayout(new BorderLayout());
-
-		add(mapView = new MapView(), BorderLayout.CENTER);
-
-		// show menu entry
-		Main.main.menu.viewMenu.setVisible(true);
-
-		// toolbar
-		toolBarActions.setFloatable(false);
-		addMapMode(new IconToggleButton(new ZoomAction(this)));
-		addMapMode(new IconToggleButton(new SelectAction(this)));
-		addMapMode(new IconToggleButton(new DrawAction(this)));
-		addMapMode(new IconToggleButton(new DeleteAction(this)));
-		addMapMode(new IconToggleButton(new ExtrudeAction(this)));
-
-		toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true);
-
-		add(toggleDialogs, BorderLayout.EAST);
-		toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
-
-		toolBarToggle.setFloatable(false);
-		addToggleDialog(new LayerListDialog(this));
-		addToggleDialog(new PropertiesDialog(this));
-		addToggleDialog(new HistoryDialog());
-		addToggleDialog(new SelectionListDialog());
-		addToggleDialog(new UserListDialog());
-		addToggleDialog(conflictDialog = new ConflictDialog());
-		addToggleDialog(new CommandStackDialog(this));
-		addToggleDialog(relationListDialog = new RelationListDialog());
-
-		// status line below the map
-		statusLine = new MapStatus(this);
-	}
-
-	/**
-	 * Called as some kind of destructor when the last layer has been removed.
-	 * Delegates the call to all Destroyables within this component (e.g. MapModes)
-	 */
-	public void destroy() {
-		for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
-			if (toolBarActions.getComponent(i) instanceof Destroyable)
-				((Destroyable)toolBarActions).destroy();
-		for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
-			if (toolBarToggle.getComponent(i) instanceof Destroyable)
-				((Destroyable)toolBarToggle).destroy();
-		
-		// remove menu entries
-		Main.main.menu.viewMenu.setVisible(false);
-    }
-
-	public Action getDefaultButtonAction() {
-		return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
-	}
-
-	/**
-	 * Open all ToggleDialogs that have their preferences property set. Close all others.
-	 */
-	public void setVisibleDialogs() {
-		for (Component c : toggleDialogs.getComponents()) {
-			if (c instanceof ToggleDialog) {
-				boolean sel = Main.pref.getBoolean(((ToggleDialog)c).prefName+".visible");
-				((ToggleDialog)c).action.button.setSelected(sel);
-				c.setVisible(sel);
-			}
-		}
-	}
-
-	/**
-	 * Call this to add new toggle dialogs to the left button-list
-	 * @param dlg The toggle dialog. It must not be in the list already.
-	 */
-	public void addToggleDialog(ToggleDialog dlg) {
-		IconToggleButton button = new IconToggleButton(dlg.action);
-		dlg.action.button = button;
-		dlg.parent = toggleDialogs;
-		toolBarToggle.add(button);
-		toggleDialogs.add(dlg);
-	}
-
-	public void addMapMode(IconToggleButton b) {
-		toolBarActions.add(b);
-		toolGroup.add((AbstractButton)b);
-	}
-
-	/**
-	 * Fires an property changed event "visible".
-	 */
-	@Override public void setVisible(boolean aFlag) {
-		boolean old = isVisible();
-		super.setVisible(aFlag);
-		if (old != aFlag)
-			firePropertyChange("visible", old, aFlag);
-	}
-
-
-
-	/**
-	 * Change the operating map mode for the view. Will call unregister on the
-	 * old MapMode and register on the new one.
-	 * @param mapMode	The new mode to set.
-	 */
-	public void selectMapMode(MapMode mapMode) {
-		if (mapMode == this.mapMode)
-			return;
-		if (this.mapMode != null)
-			this.mapMode.exitMode();
-		this.mapMode = mapMode;
-		mapMode.enterMode();
-	}
-
-	/**
-	 * Fill the given panel by adding all necessary components to the different
-	 * locations.
-	 * 
-	 * @param panel The container to fill. Must have an BorderLayout.
-	 */
-	public void fillPanel(Container panel) {
-		panel.add(this, BorderLayout.CENTER);
-		JToolBar jb = new JToolBar(JToolBar.VERTICAL);
-		jb.setFloatable(false);
-		jb.add(toolBarActions);
-		jb.addSeparator();
-		jb.add(toolBarToggle);
-		panel.add(jb, BorderLayout.WEST);
-		if (statusLine != null)
-			panel.add(statusLine, BorderLayout.SOUTH);
-	}
+    /**
+     * The current mode, this frame operates.
+     */
+    public MapMode mapMode;
+    /**
+     * The view control displayed.
+     */
+    public MapView mapView;
+    /**
+     * The toolbar with the action icons. To add new toggle dialog actions, use addToggleDialog
+     * instead of adding directly to this list. To add a new mode use addMapMode.
+     */
+    public JToolBar toolBarActions = new JToolBar(JToolBar.VERTICAL);
+    public JToolBar toolBarToggle = new JToolBar(JToolBar.VERTICAL);
+    /**
+     * The status line below the map
+     */
+    public MapStatus statusLine;
+
+    public ConflictDialog conflictDialog;
+    /**
+     * The dialog that shows all relations and lets the user edit them.
+     */
+    public RelationListDialog relationListDialog;
+    /**
+     * The panel list of all toggle dialog icons. To add new toggle dialog actions, use addToggleDialog
+     * instead of adding directly to this list.
+     */
+    public JPanel toggleDialogs = new JPanel();
+
+    public final ButtonGroup toolGroup = new ButtonGroup();
+
+    public MapFrame() {
+        setSize(400,400);
+        setLayout(new BorderLayout());
+
+        add(mapView = new MapView(), BorderLayout.CENTER);
+
+        // show menu entry
+        Main.main.menu.viewMenu.setVisible(true);
+
+        // toolbar
+        toolBarActions.setFloatable(false);
+        addMapMode(new IconToggleButton(new ZoomAction(this)));
+        addMapMode(new IconToggleButton(new SelectAction(this)));
+        addMapMode(new IconToggleButton(new DrawAction(this)));
+        addMapMode(new IconToggleButton(new DeleteAction(this)));
+        addMapMode(new IconToggleButton(new ExtrudeAction(this)));
+
+        toolGroup.setSelected(((AbstractButton)toolBarActions.getComponent(0)).getModel(), true);
+
+        add(toggleDialogs, BorderLayout.EAST);
+        toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
+
+        toolBarToggle.setFloatable(false);
+        addToggleDialog(new LayerListDialog(this));
+        addToggleDialog(new PropertiesDialog(this));
+        addToggleDialog(new HistoryDialog());
+        addToggleDialog(new SelectionListDialog());
+        addToggleDialog(new UserListDialog());
+        addToggleDialog(conflictDialog = new ConflictDialog());
+        addToggleDialog(new CommandStackDialog(this));
+        addToggleDialog(relationListDialog = new RelationListDialog());
+
+        // status line below the map
+        statusLine = new MapStatus(this);
+    }
+
+    /**
+     * Called as some kind of destructor when the last layer has been removed.
+     * Delegates the call to all Destroyables within this component (e.g. MapModes)
+     */
+    public void destroy() {
+        for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
+            if (toolBarActions.getComponent(i) instanceof Destroyable)
+                ((Destroyable)toolBarActions).destroy();
+        for (int i = 0; i < toolBarToggle.getComponentCount(); ++i)
+            if (toolBarToggle.getComponent(i) instanceof Destroyable)
+                ((Destroyable)toolBarToggle).destroy();
+
+        // remove menu entries
+        Main.main.menu.viewMenu.setVisible(false);
+    }
+
+    public Action getDefaultButtonAction() {
+        return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
+    }
+
+    /**
+     * Open all ToggleDialogs that have their preferences property set. Close all others.
+     */
+    public void setVisibleDialogs() {
+        for (Component c : toggleDialogs.getComponents()) {
+            if (c instanceof ToggleDialog) {
+                boolean sel = Main.pref.getBoolean(((ToggleDialog)c).prefName+".visible");
+                ((ToggleDialog)c).action.button.setSelected(sel);
+                c.setVisible(sel);
+            }
+        }
+    }
+
+    /**
+     * Call this to add new toggle dialogs to the left button-list
+     * @param dlg The toggle dialog. It must not be in the list already.
+     */
+    public void addToggleDialog(ToggleDialog dlg) {
+        IconToggleButton button = new IconToggleButton(dlg.action);
+        dlg.action.button = button;
+        dlg.parent = toggleDialogs;
+        toolBarToggle.add(button);
+        toggleDialogs.add(dlg);
+    }
+
+    public void addMapMode(IconToggleButton b) {
+        toolBarActions.add(b);
+        toolGroup.add((AbstractButton)b);
+    }
+
+    /**
+     * Fires an property changed event "visible".
+     */
+    @Override public void setVisible(boolean aFlag) {
+        boolean old = isVisible();
+        super.setVisible(aFlag);
+        if (old != aFlag)
+            firePropertyChange("visible", old, aFlag);
+    }
+
+
+
+    /**
+     * Change the operating map mode for the view. Will call unregister on the
+     * old MapMode and register on the new one.
+     * @param mapMode   The new mode to set.
+     */
+    public void selectMapMode(MapMode mapMode) {
+        if (mapMode == this.mapMode)
+            return;
+        if (this.mapMode != null)
+            this.mapMode.exitMode();
+        this.mapMode = mapMode;
+        mapMode.enterMode();
+    }
+
+    /**
+     * Fill the given panel by adding all necessary components to the different
+     * locations.
+     *
+     * @param panel The container to fill. Must have an BorderLayout.
+     */
+    public void fillPanel(Container panel) {
+        panel.add(this, BorderLayout.CENTER);
+        JToolBar jb = new JToolBar(JToolBar.VERTICAL);
+        jb.setFloatable(false);
+        jb.add(toolBarActions);
+        jb.addSeparator();
+        jb.add(toolBarToggle);
+        panel.add(jb, BorderLayout.WEST);
+        if (statusLine != null)
+            panel.add(statusLine, BorderLayout.SOUTH);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MapMover.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapMover.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapMover.java	(revision 1169)
@@ -28,176 +28,176 @@
 public class MapMover extends MouseAdapter implements MouseMotionListener, MouseWheelListener {
 
-	private final class ZoomerAction extends AbstractAction {
-		private final String action;
-		public ZoomerAction(String action) {
-			this.action = action;
+    private final class ZoomerAction extends AbstractAction {
+        private final String action;
+        public ZoomerAction(String action) {
+            this.action = action;
         }
-	    public void actionPerformed(ActionEvent e) {
-	    	if (action.equals(".") || action.equals(",")) {
-	    		Point mouse = nc.getMousePosition();
-	    		if (mouse == null)
-	    			mouse = new Point((int)nc.getBounds().getCenterX(), (int)nc.getBounds().getCenterY());
-	    		MouseWheelEvent we = new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, action.equals(",") ? -1 : 1);
-	    		mouseWheelMoved(we);
-	    	} else {
-	    		EastNorth center = nc.getCenter();
-	    		EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5);
-	    		if (action.equals("left"))
-	    			nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()), nc.getScale());
-	    		else if (action.equals("right"))
-	    			nc.zoomTo(new EastNorth(newcenter.east(), center.north()), nc.getScale());
-	    		else if (action.equals("up"))
-	    			nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()), nc.getScale());
-	    		else if (action.equals("down"))
-	    			nc.zoomTo(new EastNorth(center.east(), newcenter.north()), nc.getScale());
-	    	}
-	    }
-    }
-
-	/**
-	 * The point in the map that was the under the mouse point
-	 * when moving around started.
-	 */
-	private EastNorth mousePosMove;
-	/**
-	 * The map to move around.
-	 */
-	private final NavigatableComponent nc;
-	/**
-	 * The old cursor when we changed it to movement cursor.
-	 */
-	private Cursor oldCursor;
-
-	private boolean movementInPlace = false;
-
-	/**
-	 * Create a new MapMover
-	 */
-	public MapMover(NavigatableComponent navComp, JPanel contentPane) {
-		this.nc = navComp;
-		nc.addMouseListener(this);
-		nc.addMouseMotionListener(this);
-		nc.addMouseWheelListener(this);
-
-		if (contentPane != null) {
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.right");
-			contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
-
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.left");
-			contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
-
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.up");
-			contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
-
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.down");
-			contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
-
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.in");
-			contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
-
-			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.GROUP_HOTKEY).getKeyStroke(),
-				"MapMover.Zoomer.out");
-			contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
-		}
-	}
-
-	/**
-	 * If the right (and only the right) mouse button is pressed, move the map
-	 */
-	public void mouseDragged(MouseEvent e) {
-		int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
-		if ((e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK) {
-			if (mousePosMove == null)
-				startMovement(e);
-			EastNorth center = nc.getCenter();
-			EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY());
-			EastNorth p = new EastNorth(
-					mousePosMove.east() + center.east() - mouseCenter.east(),
-					mousePosMove.north() + center.north() - mouseCenter.north());
-			nc.zoomTo(p, nc.getScale());
-		} else
-			endMovement();
-	}
-
-	/**
-	 * Start the movement, if it was the 3rd button (right button).
-	 */
-	@Override public void mousePressed(MouseEvent e) {
-		int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
-		if (e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0)
-			startMovement(e);
-	}
-
-	/**
-	 * Change the cursor back to it's pre-move cursor.
-	 */
-	@Override public void mouseReleased(MouseEvent e) {
-		if (e.getButton() == MouseEvent.BUTTON3)
-			endMovement();
-	}
-
-	/**
-	 * Start movement by setting a new cursor and remember the current mouse
-	 * position.
-	 * @param e The mouse event that leat to the movement from.
-	 */
-	private void startMovement(MouseEvent e) {
-		if (movementInPlace)
-			return;
-		movementInPlace = true;
-		mousePosMove = nc.getEastNorth(e.getX(), e.getY());
-		oldCursor = nc.getCursor();
-		nc.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-	}
-
-	/**
-	 * End the movement. Setting back the cursor and clear the movement variables
-	 */
-	private void endMovement() {
-		if (!movementInPlace)
-			return;
-		movementInPlace = false;
-		if (oldCursor != null)
-			nc.setCursor(oldCursor);
-		else
-			nc.setCursor(Cursor.getDefaultCursor());
-		mousePosMove = null;
-		oldCursor = null;
-	}
-
-	/**
-	 * Zoom the map by 1/5th of current zoom per wheel-delta.
-	 * @param e The wheel event.
-	 */
-	public void mouseWheelMoved(MouseWheelEvent e) {
-		int w = nc.getWidth();
-		int h = nc.getHeight();
-
-		double zoom = Math.max(0.1, 1 + e.getWheelRotation()/5.0);
-		double zoomfactor = (zoom-1)/2+1;
-
-		double newHalfWidth = w*zoomfactor - w/2;
-		double newHalfHeight = h*zoomfactor - h/2;
-		double centerx = e.getX() - (e.getX()-w/2)*newHalfWidth*2/w;
-		double centery = e.getY() - (e.getY()-h/2)*newHalfHeight*2/h;
-		EastNorth newCenter = nc.getEastNorth((int)centerx, (int)centery);
-
-		nc.zoomTo(newCenter, nc.getScale()*zoom);
-	}
-
-	/**
-	 * Does nothing. Only to satisfy MouseMotionListener
-	 */
-	public void mouseMoved(MouseEvent e) {}
+        public void actionPerformed(ActionEvent e) {
+            if (action.equals(".") || action.equals(",")) {
+                Point mouse = nc.getMousePosition();
+                if (mouse == null)
+                    mouse = new Point((int)nc.getBounds().getCenterX(), (int)nc.getBounds().getCenterY());
+                MouseWheelEvent we = new MouseWheelEvent(nc, e.getID(), e.getWhen(), e.getModifiers(), mouse.x, mouse.y, 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, action.equals(",") ? -1 : 1);
+                mouseWheelMoved(we);
+            } else {
+                EastNorth center = nc.getCenter();
+                EastNorth newcenter = nc.getEastNorth(nc.getWidth()/2+nc.getWidth()/5, nc.getHeight()/2+nc.getHeight()/5);
+                if (action.equals("left"))
+                    nc.zoomTo(new EastNorth(2*center.east()-newcenter.east(), center.north()), nc.getScale());
+                else if (action.equals("right"))
+                    nc.zoomTo(new EastNorth(newcenter.east(), center.north()), nc.getScale());
+                else if (action.equals("up"))
+                    nc.zoomTo(new EastNorth(center.east(), 2*center.north()-newcenter.north()), nc.getScale());
+                else if (action.equals("down"))
+                    nc.zoomTo(new EastNorth(center.east(), newcenter.north()), nc.getScale());
+            }
+        }
+    }
+
+    /**
+     * The point in the map that was the under the mouse point
+     * when moving around started.
+     */
+    private EastNorth mousePosMove;
+    /**
+     * The map to move around.
+     */
+    private final NavigatableComponent nc;
+    /**
+     * The old cursor when we changed it to movement cursor.
+     */
+    private Cursor oldCursor;
+
+    private boolean movementInPlace = false;
+
+    /**
+     * Create a new MapMover
+     */
+    public MapMover(NavigatableComponent navComp, JPanel contentPane) {
+        this.nc = navComp;
+        nc.addMouseListener(this);
+        nc.addMouseMotionListener(this);
+        nc.addMouseWheelListener(this);
+
+        if (contentPane != null) {
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.right");
+            contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
+
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.left");
+            contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
+
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.up");
+            contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
+
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.down");
+            contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
+
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.in");
+            contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
+
+            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.GROUP_HOTKEY).getKeyStroke(),
+                "MapMover.Zoomer.out");
+            contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
+        }
+    }
+
+    /**
+     * If the right (and only the right) mouse button is pressed, move the map
+     */
+    public void mouseDragged(MouseEvent e) {
+        int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
+        if ((e.getModifiersEx() & (MouseEvent.BUTTON3_DOWN_MASK | offMask)) == MouseEvent.BUTTON3_DOWN_MASK) {
+            if (mousePosMove == null)
+                startMovement(e);
+            EastNorth center = nc.getCenter();
+            EastNorth mouseCenter = nc.getEastNorth(e.getX(), e.getY());
+            EastNorth p = new EastNorth(
+                    mousePosMove.east() + center.east() - mouseCenter.east(),
+                    mousePosMove.north() + center.north() - mouseCenter.north());
+            nc.zoomTo(p, nc.getScale());
+        } else
+            endMovement();
+    }
+
+    /**
+     * Start the movement, if it was the 3rd button (right button).
+     */
+    @Override public void mousePressed(MouseEvent e) {
+        int offMask = MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK;
+        if (e.getButton() == MouseEvent.BUTTON3 && (e.getModifiersEx() & offMask) == 0)
+            startMovement(e);
+    }
+
+    /**
+     * Change the cursor back to it's pre-move cursor.
+     */
+    @Override public void mouseReleased(MouseEvent e) {
+        if (e.getButton() == MouseEvent.BUTTON3)
+            endMovement();
+    }
+
+    /**
+     * Start movement by setting a new cursor and remember the current mouse
+     * position.
+     * @param e The mouse event that leat to the movement from.
+     */
+    private void startMovement(MouseEvent e) {
+        if (movementInPlace)
+            return;
+        movementInPlace = true;
+        mousePosMove = nc.getEastNorth(e.getX(), e.getY());
+        oldCursor = nc.getCursor();
+        nc.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+    }
+
+    /**
+     * End the movement. Setting back the cursor and clear the movement variables
+     */
+    private void endMovement() {
+        if (!movementInPlace)
+            return;
+        movementInPlace = false;
+        if (oldCursor != null)
+            nc.setCursor(oldCursor);
+        else
+            nc.setCursor(Cursor.getDefaultCursor());
+        mousePosMove = null;
+        oldCursor = null;
+    }
+
+    /**
+     * Zoom the map by 1/5th of current zoom per wheel-delta.
+     * @param e The wheel event.
+     */
+    public void mouseWheelMoved(MouseWheelEvent e) {
+        int w = nc.getWidth();
+        int h = nc.getHeight();
+
+        double zoom = Math.max(0.1, 1 + e.getWheelRotation()/5.0);
+        double zoomfactor = (zoom-1)/2+1;
+
+        double newHalfWidth = w*zoomfactor - w/2;
+        double newHalfHeight = h*zoomfactor - h/2;
+        double centerx = e.getX() - (e.getX()-w/2)*newHalfWidth*2/w;
+        double centery = e.getY() - (e.getY()-h/2)*newHalfHeight*2/h;
+        EastNorth newCenter = nc.getEastNorth((int)centerx, (int)centery);
+
+        nc.zoomTo(newCenter, nc.getScale()*zoom);
+    }
+
+    /**
+     * Does nothing. Only to satisfy MouseMotionListener
+     */
+    public void mouseMoved(MouseEvent e) {}
 }
Index: trunk/src/org/openstreetmap/josm/gui/MapScaler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapScaler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapScaler.java	(revision 1169)
@@ -18,29 +18,29 @@
 public class MapScaler extends JComponent implements Helpful {
 
-	private final NavigatableComponent mv;
-	public MapScaler(NavigatableComponent mv, Projection proj) {
-		this.mv = mv;
-		setSize(100,30);
-		setOpaque(false);
+    private final NavigatableComponent mv;
+    public MapScaler(NavigatableComponent mv, Projection proj) {
+        this.mv = mv;
+        setSize(100,30);
+        setOpaque(false);
     }
 
-	@Override public void paint(Graphics g) {
-		LatLon ll1 = mv.getLatLon(0,0);
-		LatLon ll2 = mv.getLatLon(100,0);
-		double dist = ll1.greatCircleDistance(ll2);
-		String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10+" m";
-		Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g);
-		g.setColor(Main.pref.getColor(marktr("scale"), Color.white));
-		g.drawLine(0, 5, 99, 5);
-		g.drawLine(0, 0, 0, 10);
-		g.drawLine(99, 0, 99, 10);
-		g.drawLine(49, 0, 49, 10);
-		g.drawLine(24, 3, 24, 7);
-		g.drawLine(74, 3, 74, 7);
-		g.drawString(text, (int)(50-bound.getWidth()/2), 23);
+    @Override public void paint(Graphics g) {
+        LatLon ll1 = mv.getLatLon(0,0);
+        LatLon ll2 = mv.getLatLon(100,0);
+        double dist = ll1.greatCircleDistance(ll2);
+        String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10+" m";
+        Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g);
+        g.setColor(Main.pref.getColor(marktr("scale"), Color.white));
+        g.drawLine(0, 5, 99, 5);
+        g.drawLine(0, 0, 0, 10);
+        g.drawLine(99, 0, 99, 10);
+        g.drawLine(49, 0, 49, 10);
+        g.drawLine(24, 3, 24, 7);
+        g.drawLine(74, 3, 74, 7);
+        g.drawString(text, (int)(50-bound.getWidth()/2), 23);
     }
 
-	public String helpTopic() {
-	    return "MapView/Scaler";
+    public String helpTopic() {
+        return "MapView/Scaler";
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MapSlider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapSlider.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapSlider.java	(revision 1169)
@@ -15,43 +15,43 @@
 
 class MapSlider extends JSlider implements PropertyChangeListener, ChangeListener, Helpful {
-	
+
     private final MapView mv;
-	boolean clicked = false;
-	
-	public MapSlider(MapView mv) {
-		super(0, 20);
-		setOpaque(false);
-		this.mv = mv;
-		addMouseListener(new MouseAdapter(){
-			@Override public void mousePressed(MouseEvent e) {
-				clicked = true;
-			}
-			@Override public void mouseReleased(MouseEvent e) {
-				clicked = false;
-			}
-		});
-		mv.addPropertyChangeListener("scale", this);
-		addChangeListener(this);
-	}
-	
-	public void propertyChange(PropertyChangeEvent evt) {
-		if (!getModel().getValueIsAdjusting())
-			setValue(this.mv.zoom());
-	}
-	
-	public void stateChanged(ChangeEvent e) {
-		if (!clicked)
-			return;
-		EastNorth pos = MapView.world;
-		for (int zoom = 0; zoom < getValue(); ++zoom)
-			pos = new EastNorth(pos.east()/2, pos.north()/2);
-		if (this.mv.getWidth() < this.mv.getHeight())
-			this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20));
-		else
-			this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20));
-	}
+    boolean clicked = false;
 
-	public String helpTopic() {
-	    return "MapView/Slider";
+    public MapSlider(MapView mv) {
+        super(0, 20);
+        setOpaque(false);
+        this.mv = mv;
+        addMouseListener(new MouseAdapter(){
+            @Override public void mousePressed(MouseEvent e) {
+                clicked = true;
+            }
+            @Override public void mouseReleased(MouseEvent e) {
+                clicked = false;
+            }
+        });
+        mv.addPropertyChangeListener("scale", this);
+        addChangeListener(this);
+    }
+
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (!getModel().getValueIsAdjusting())
+            setValue(this.mv.zoom());
+    }
+
+    public void stateChanged(ChangeEvent e) {
+        if (!clicked)
+            return;
+        EastNorth pos = MapView.world;
+        for (int zoom = 0; zoom < getValue(); ++zoom)
+            pos = new EastNorth(pos.east()/2, pos.north()/2);
+        if (this.mv.getWidth() < this.mv.getHeight())
+            this.mv.zoomTo(this.mv.center, pos.east()*2/(this.mv.getWidth()-20));
+        else
+            this.mv.zoomTo(this.mv.center, pos.north()*2/(this.mv.getHeight()-20));
+    }
+
+    public String helpTopic() {
+        return "MapView/Slider";
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 1169)
@@ -57,37 +57,37 @@
 public class MapStatus extends JPanel implements Helpful {
 
-	/**
-	 * The MapView this status belongs to.
-	 */
-	final MapView mv;
-	
-	/** 
-	 * A small user interface component that consists of an image label and
-	 * a fixed text content to the right of the image.
-	 */
-	class ImageLabel extends JPanel {
-		private JLabel tf; 
-		private int chars;
-		public ImageLabel(String img, String tooltip, int chars) {
-			super();
-			setLayout(new GridBagLayout());
-			setBackground(Color.decode("#b8cfe5"));
-			add(new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0));
-			add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0));
-			setToolTipText(tooltip);
-			this.chars = chars;
-		}
-		public void setText(String t) {
-			tf.setText(t);
-		}
-		@Override public Dimension getPreferredSize() {
-			return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height);
-		}
-		@Override public Dimension getMinimumSize() {
-			return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height);	
-		}
-	}
-
-	LatLon.CoordinateFormat mCord;
+    /**
+     * The MapView this status belongs to.
+     */
+    final MapView mv;
+
+    /**
+     * A small user interface component that consists of an image label and
+     * a fixed text content to the right of the image.
+     */
+    class ImageLabel extends JPanel {
+        private JLabel tf;
+        private int chars;
+        public ImageLabel(String img, String tooltip, int chars) {
+            super();
+            setLayout(new GridBagLayout());
+            setBackground(Color.decode("#b8cfe5"));
+            add(new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0));
+            add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0));
+            setToolTipText(tooltip);
+            this.chars = chars;
+        }
+        public void setText(String t) {
+            tf.setText(t);
+        }
+        @Override public Dimension getPreferredSize() {
+            return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height);
+        }
+        @Override public Dimension getMinimumSize() {
+            return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height);
+        }
+    }
+
+    LatLon.CoordinateFormat mCord;
 
     ImageLabel lonText = new ImageLabel("lon", tr("The geographic longitude at the mouse pointer."), 11);
@@ -99,161 +99,161 @@
     ImageLabel distText = new ImageLabel("dist", tr("The length of the new way segment being drawn."), 8);
 
-	/**
-	 * The collector class that waits for notification and then update
-	 * the display objects.
-	 *
-	 * @author imi
-	 */
-	private final class Collector implements Runnable {
-		/**
-		 * The last object displayed in status line.
-		 */
-		Collection<OsmPrimitive> osmStatus;
-		/**
-		 * The old modifiers that was pressed the last time this collector ran.
-		 */
-		private int oldModifiers;
-		/**
-		 * The popup displayed to show additional information
-		 */
-		private Popup popup;
-
-		private MapFrame parent;
-
-		public Collector(MapFrame parent) {
-			this.parent = parent;
-		}
-
-		/**
-		 * Execution function for the Collector.
-		 */
-		public void run() {
-			for (;;) {
-				MouseState ms = new MouseState();
-				synchronized (this) {
-					try {wait();} catch (InterruptedException e) {}
-					ms.modifiers = mouseState.modifiers;
-					ms.mousePos = mouseState.mousePos;
-				}
-				if (parent != Main.map)
-					return; // exit, if new parent.
-				if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
-					continue; // freeze display when holding down ctrl
-
-				if (mv.center == null)
-					continue;
-
-				// This try/catch is a hack to stop the flooding bug reports about this.
-				// The exception needed to handle with in the first place, means that this
-				// access to the data need to be restarted, if the main thread modifies
-				// the data.
-				try {
-					OsmPrimitive osmNearest = null;
-					// Set the text label in the bottom status bar
-					osmNearest = mv.getNearest(ms.mousePos);
-					if (osmNearest != null) {
-						NameVisitor visitor = new NameVisitor();
-						osmNearest.visit(visitor);
-						nameText.setText(visitor.name);
-					} else
-						nameText.setText(tr("(no object)"));
-
-					// Popup Information
-					if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 ) {
-						Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos);
-
-						if (osms == null)
-							continue;
-						if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
-							continue;
-
-						if (popup != null) {
-							try {
-	                            EventQueue.invokeAndWait(new Runnable() {
-	                                public void run() {
-	                                	popup.hide();
-	                                }
-	                            });
+    /**
+     * The collector class that waits for notification and then update
+     * the display objects.
+     *
+     * @author imi
+     */
+    private final class Collector implements Runnable {
+        /**
+         * The last object displayed in status line.
+         */
+        Collection<OsmPrimitive> osmStatus;
+        /**
+         * The old modifiers that was pressed the last time this collector ran.
+         */
+        private int oldModifiers;
+        /**
+         * The popup displayed to show additional information
+         */
+        private Popup popup;
+
+        private MapFrame parent;
+
+        public Collector(MapFrame parent) {
+            this.parent = parent;
+        }
+
+        /**
+         * Execution function for the Collector.
+         */
+        public void run() {
+            for (;;) {
+                MouseState ms = new MouseState();
+                synchronized (this) {
+                    try {wait();} catch (InterruptedException e) {}
+                    ms.modifiers = mouseState.modifiers;
+                    ms.mousePos = mouseState.mousePos;
+                }
+                if (parent != Main.map)
+                    return; // exit, if new parent.
+                if ((ms.modifiers & MouseEvent.CTRL_DOWN_MASK) != 0 || ms.mousePos == null)
+                    continue; // freeze display when holding down ctrl
+
+                if (mv.center == null)
+                    continue;
+
+                // This try/catch is a hack to stop the flooding bug reports about this.
+                // The exception needed to handle with in the first place, means that this
+                // access to the data need to be restarted, if the main thread modifies
+                // the data.
+                try {
+                    OsmPrimitive osmNearest = null;
+                    // Set the text label in the bottom status bar
+                    osmNearest = mv.getNearest(ms.mousePos);
+                    if (osmNearest != null) {
+                        NameVisitor visitor = new NameVisitor();
+                        osmNearest.visit(visitor);
+                        nameText.setText(visitor.name);
+                    } else
+                        nameText.setText(tr("(no object)"));
+
+                    // Popup Information
+                    if ((ms.modifiers & MouseEvent.BUTTON2_DOWN_MASK) != 0 ) {
+                        Collection<OsmPrimitive> osms = mv.getAllNearest(ms.mousePos);
+
+                        if (osms == null)
+                            continue;
+                        if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
+                            continue;
+
+                        if (popup != null) {
+                            try {
+                                EventQueue.invokeAndWait(new Runnable() {
+                                    public void run() {
+                                        popup.hide();
+                                    }
+                                });
                             } catch (InterruptedException e) {
                             } catch (InvocationTargetException e) {
-                            	throw new RuntimeException(e);
+                                throw new RuntimeException(e);
                             }
-						}
-
-						JPanel c = new JPanel(new GridBagLayout());
-						for (final OsmPrimitive osm : osms) {
-							NameVisitor visitor = new NameVisitor();
-							osm.visit(visitor);
-							final StringBuilder text = new StringBuilder();
-							if (osm.id == 0 || osm.modified)
-								visitor.name = "<i><b>"+visitor.name+"*</b></i>";
-							text.append(visitor.name);
-							if (osm.id != 0)
-								text.append("<br>id="+osm.id);
-							for (Entry<String, String> e : osm.entrySet())
-								text.append("<br>"+e.getKey()+"="+e.getValue());
-							final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL);
-							l.setFont(l.getFont().deriveFont(Font.PLAIN));
-							l.setVerticalTextPosition(JLabel.TOP);
-							l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
-							l.addMouseListener(new MouseAdapter(){
-								@Override public void mouseEntered(MouseEvent e) {
-									l.setText("<html><u color='blue'>"+text.toString()+"</u></html>");
-								}
-								@Override public void mouseExited(MouseEvent e) {
-									l.setText("<html>"+text.toString()+"</html>");
-								}
-								@Override public void mouseClicked(MouseEvent e) {
-									Main.ds.setSelected(osm);
-									mv.repaint();
-								}
-							});
-							c.add(l, GBC.eol());
-						}
-
-						Point p = mv.getLocationOnScreen();
-						popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
-						final Popup staticPopup = popup;
-						EventQueue.invokeLater(new Runnable(){
-							public void run() {
-								staticPopup.show();
+                        }
+
+                        JPanel c = new JPanel(new GridBagLayout());
+                        for (final OsmPrimitive osm : osms) {
+                            NameVisitor visitor = new NameVisitor();
+                            osm.visit(visitor);
+                            final StringBuilder text = new StringBuilder();
+                            if (osm.id == 0 || osm.modified)
+                                visitor.name = "<i><b>"+visitor.name+"*</b></i>";
+                            text.append(visitor.name);
+                            if (osm.id != 0)
+                                text.append("<br>id="+osm.id);
+                            for (Entry<String, String> e : osm.entrySet())
+                                text.append("<br>"+e.getKey()+"="+e.getValue());
+                            final JLabel l = new JLabel("<html>"+text.toString()+"</html>", visitor.icon, JLabel.HORIZONTAL);
+                            l.setFont(l.getFont().deriveFont(Font.PLAIN));
+                            l.setVerticalTextPosition(JLabel.TOP);
+                            l.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+                            l.addMouseListener(new MouseAdapter(){
+                                @Override public void mouseEntered(MouseEvent e) {
+                                    l.setText("<html><u color='blue'>"+text.toString()+"</u></html>");
+                                }
+                                @Override public void mouseExited(MouseEvent e) {
+                                    l.setText("<html>"+text.toString()+"</html>");
+                                }
+                                @Override public void mouseClicked(MouseEvent e) {
+                                    Main.ds.setSelected(osm);
+                                    mv.repaint();
+                                }
+                            });
+                            c.add(l, GBC.eol());
+                        }
+
+                        Point p = mv.getLocationOnScreen();
+                        popup = PopupFactory.getSharedInstance().getPopup(mv, c, p.x+ms.mousePos.x+16, p.y+ms.mousePos.y+16);
+                        final Popup staticPopup = popup;
+                        EventQueue.invokeLater(new Runnable(){
+                            public void run() {
+                                staticPopup.show();
                             }
-						});
-					} else if (popup != null) {
-						final Popup staticPopup = popup;
-						popup = null;
-						EventQueue.invokeLater(new Runnable(){
-							public void run() {
-								staticPopup.hide();
+                        });
+                    } else if (popup != null) {
+                        final Popup staticPopup = popup;
+                        popup = null;
+                        EventQueue.invokeLater(new Runnable(){
+                            public void run() {
+                                staticPopup.hide();
                             }
-						});
-					}
-				} catch (ConcurrentModificationException x) {
-				} catch (NullPointerException x) {
-				}
-			}
-		}
-	}
-
-	/**
-	 * Everything, the collector is interested of. Access must be synchronized.
-	 * @author imi
-	 */
-	class MouseState {
-		Point mousePos;
-		int modifiers;
-	}
-	/**
-	 * The last sent mouse movement event.
-	 */
-	MouseState mouseState = new MouseState();
-
-	/**
-	 * Construct a new MapStatus and attach it to the map view.
-	 * @param mapFrame The MapFrame the status line is part of.
-	 */
-	public MapStatus(final MapFrame mapFrame) {
-		this.mv = mapFrame.mapView;
-		
+                        });
+                    }
+                } catch (ConcurrentModificationException x) {
+                } catch (NullPointerException x) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Everything, the collector is interested of. Access must be synchronized.
+     * @author imi
+     */
+    class MouseState {
+        Point mousePos;
+        int modifiers;
+    }
+    /**
+     * The last sent mouse movement event.
+     */
+    MouseState mouseState = new MouseState();
+
+    /**
+     * Construct a new MapStatus and attach it to the map view.
+     * @param mapFrame The MapFrame the status line is part of.
+     */
+    public MapStatus(final MapFrame mapFrame) {
+        this.mv = mapFrame.mapView;
+
         try {
             mCord = LatLon.CoordinateFormat.valueOf(Main.pref.get("coordinates"));
@@ -261,23 +261,23 @@
             mCord =LatLon.CoordinateFormat.DECIMAL_DEGREES;
         }
-		// Listen for mouse movements and set the position text field
-		mv.addMouseMotionListener(new MouseMotionListener(){
-			public void mouseDragged(MouseEvent e) {
-				mouseMoved(e);
-			}
-			public void mouseMoved(MouseEvent e) {
-				if (mv.center == null)
-					return;
-				// Do not update the view if ctrl is pressed.
-				if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
-					LatLon p = mv.getLatLon(e.getX(),e.getY());
-					latText.setText(p.latToString(mCord));
-					lonText.setText(p.lonToString(mCord));
-				}
-			}
-		});
-
-		setLayout(new GridBagLayout());
-		setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        // Listen for mouse movements and set the position text field
+        mv.addMouseMotionListener(new MouseMotionListener(){
+            public void mouseDragged(MouseEvent e) {
+                mouseMoved(e);
+            }
+            public void mouseMoved(MouseEvent e) {
+                if (mv.center == null)
+                    return;
+                // Do not update the view if ctrl is pressed.
+                if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
+                    LatLon p = mv.getLatLon(e.getX(),e.getY());
+                    latText.setText(p.latToString(mCord));
+                    lonText.setText(p.lonToString(mCord));
+                }
+            }
+        });
+
+        setLayout(new GridBagLayout());
+        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
 
         add(latText, GBC.std());
@@ -287,73 +287,73 @@
         add(distText, GBC.std().insets(3,0,0,0));
 
-		helpText.setEditable(false);
-		add(nameText, GBC.std().insets(3,0,0,0));
-		add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL));
-		
-		// The background thread
-		final Collector collector = new Collector(mapFrame);
-		new Thread(collector).start();
-
-		// Listen to keyboard/mouse events for pressing/releasing alt key and
-		// inform the collector.
-		try {
-			Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
-				public void eventDispatched(AWTEvent event) {
-					synchronized (collector) {
-						mouseState.modifiers = ((InputEvent)event).getModifiersEx();
-						if (event instanceof MouseEvent)
-							mouseState.mousePos = ((MouseEvent)event).getPoint();
-						collector.notify();
-					}
-				}
-			}, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
-		} catch (SecurityException ex) {
-			mapFrame.mapView.addMouseMotionListener(new MouseMotionListener() {
-				public void mouseMoved(MouseEvent e) {
-					synchronized (collector) {
-						mouseState.modifiers = e.getModifiersEx();
-						mouseState.mousePos = e.getPoint();
-						collector.notify();
-					}
-				}
-
-				public void mouseDragged(MouseEvent e) {
-					mouseMoved(e);
-				}
-			});
-
-			mapFrame.mapView.addKeyListener(new KeyAdapter() {
-				@Override public void keyPressed(KeyEvent e) {
-					synchronized (collector) {
-						mouseState.modifiers = e.getModifiersEx();
-						collector.notify();
-					}
-				}
-
-				@Override public void keyReleased(KeyEvent e) {
-					keyPressed(e);
-				}
-			});
-		}
-	}
-
-	public String helpTopic() {
-		return "Statusline";
-	}
-	
-	public void setHelpText(String t) {
-		helpText.setText(t);
-		helpText.setToolTipText(t);
-	}
-	public void setAngle(double a) {
-		angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + " °");
-	}
-	public void setHeading(double h) {
-		headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + " °");
-	}
-	public void setDist(double dist) {
-		String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10.0 +" m";
-		distText.setText(dist < 0 ? "--" : text);
-	}
-	
+        helpText.setEditable(false);
+        add(nameText, GBC.std().insets(3,0,0,0));
+        add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL));
+
+        // The background thread
+        final Collector collector = new Collector(mapFrame);
+        new Thread(collector).start();
+
+        // Listen to keyboard/mouse events for pressing/releasing alt key and
+        // inform the collector.
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
+                public void eventDispatched(AWTEvent event) {
+                    synchronized (collector) {
+                        mouseState.modifiers = ((InputEvent)event).getModifiersEx();
+                        if (event instanceof MouseEvent)
+                            mouseState.mousePos = ((MouseEvent)event).getPoint();
+                        collector.notify();
+                    }
+                }
+            }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
+        } catch (SecurityException ex) {
+            mapFrame.mapView.addMouseMotionListener(new MouseMotionListener() {
+                public void mouseMoved(MouseEvent e) {
+                    synchronized (collector) {
+                        mouseState.modifiers = e.getModifiersEx();
+                        mouseState.mousePos = e.getPoint();
+                        collector.notify();
+                    }
+                }
+
+                public void mouseDragged(MouseEvent e) {
+                    mouseMoved(e);
+                }
+            });
+
+            mapFrame.mapView.addKeyListener(new KeyAdapter() {
+                @Override public void keyPressed(KeyEvent e) {
+                    synchronized (collector) {
+                        mouseState.modifiers = e.getModifiersEx();
+                        collector.notify();
+                    }
+                }
+
+                @Override public void keyReleased(KeyEvent e) {
+                    keyPressed(e);
+                }
+            });
+        }
+    }
+
+    public String helpTopic() {
+        return "Statusline";
+    }
+
+    public void setHelpText(String t) {
+        helpText.setText(t);
+        helpText.setToolTipText(t);
+    }
+    public void setAngle(double a) {
+        angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + " °");
+    }
+    public void setHeading(double h) {
+        headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + " °");
+    }
+    public void setDist(double dist) {
+        String text = dist > 1000 ? (Math.round(dist/100)/10.0)+" km" : Math.round(dist*10)/10.0 +" m";
+        distText.setText(dist < 0 ? "--" : text);
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 1169)
@@ -56,401 +56,401 @@
 public class MapView extends NavigatableComponent {
 
-	/**
-	 * Interface to notify listeners of the change of the active layer.
-	 * @author imi
-	 * @deprecated Use Layer.LayerChangeListener instead
-	 */
-	@Deprecated public interface LayerChangeListener {
-		void activeLayerChange(Layer oldLayer, Layer newLayer);
-		void layerAdded(Layer newLayer);
-		void layerRemoved(Layer oldLayer);
-	}
-
-	/**
-	 * A list of all layers currently loaded.
-	 */
-	private ArrayList<Layer> layers = new ArrayList<Layer>();
-	/**
-	 * The play head marker: there is only one of these so it isn't in any specific layer
-	 */
-	public PlayHeadMarker playHeadMarker = null;
-	/**
-	 * Direct link to the edit layer (if any) in the layers list.
-	 */
-	public OsmDataLayer editLayer;
-	/**
-	 * The layer from the layers list that is currently active.
-	 */
-	private Layer activeLayer;
-
-	/**
-	 * The last event performed by mouse.
-	 */
-	public MouseEvent lastMEvent;
-
-	private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();
-
-	private BufferedImage offscreenBuffer;
-
-	/**
-	 * The listener of the active layer changes.
-	 * @deprecated Use Layer.listener instead.
-	 */
-	@Deprecated private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>();
-
-	public MapView() {
-		addComponentListener(new ComponentAdapter(){
-			@Override public void componentResized(ComponentEvent e) {
-				removeComponentListener(this);
-
-				if (!zoomToEditLayerBoundingBox())
-					new AutoScaleAction("data").actionPerformed(null);
-
-				new MapMover(MapView.this, Main.contentPane);
-				JosmAction mv;
-				mv = new MoveAction(MoveAction.Direction.UP);
-				if (mv.getShortcut() != null) {
-					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "UP");
-					Main.contentPane.getActionMap().put("UP", mv);
-				}
-				mv = new MoveAction(MoveAction.Direction.DOWN);
-				if (mv.getShortcut() != null) {
-					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "DOWN");
-					Main.contentPane.getActionMap().put("DOWN", mv);
-				}
-				mv = new MoveAction(MoveAction.Direction.LEFT);
-				if (mv.getShortcut() != null) {
-					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "LEFT");
-					Main.contentPane.getActionMap().put("LEFT", mv);
-				}
-				mv = new MoveAction(MoveAction.Direction.RIGHT);
-				if (mv.getShortcut() != null) {
-					Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "RIGHT");
-					Main.contentPane.getActionMap().put("RIGHT", mv);
-				}
-
-				MapSlider zoomSlider = new MapSlider(MapView.this);
-				add(zoomSlider);
-				zoomSlider.setBounds(3, 0, 114, 30);
-
-				MapScaler scaler = new MapScaler(MapView.this, Main.proj);
-				add(scaler);
-				scaler.setLocation(10,30);
-			}
-		});
-
-		// listend to selection changes to redraw the map
-		DataSet.selListeners.add(new SelectionChangedListener(){
-			public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-				repaint();
-			}
-		});
-
-		//store the last mouse action
-		this.addMouseMotionListener(new MouseMotionListener() {
-			public void mouseDragged(MouseEvent e) {
-				mouseMoved(e);
-			}
-			public void mouseMoved(MouseEvent e) {
-				lastMEvent = e;
-			}
-		});
-	}
-
-	/**
-	 * Add a layer to the current MapView. The layer will be added at topmost
-	 * position.
-	 */
-	public void addLayer(Layer layer) {
-		if (layer instanceof OsmDataLayer) {
-			editLayer = (OsmDataLayer)layer;
-			Main.ds = editLayer.data;
-			editLayer.listenerModified.add(new ModifiedChangedListener(){
-				public void modifiedChanged(boolean value, OsmDataLayer source) {
-					JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+tr("Java OpenStreetMap - Editor"));
-				}
-			});
-		}
-		if (layer instanceof MarkerLayer && playHeadMarker == null)
-			playHeadMarker = PlayHeadMarker.create();
-		int pos = layers.size();
-		while(pos > 0 && layers.get(pos-1).background)
-			--pos;
-		layers.add(pos, layer);
-
-		// TODO: Deprecated
-		for (LayerChangeListener l : listeners)
-			l.layerAdded(layer);
-		for (Layer.LayerChangeListener l : Layer.listeners)
-			l.layerAdded(layer);
-		if (layer instanceof OsmDataLayer || activeLayer == null) {
-			// autoselect the new layer
-			Layer old = activeLayer;
-			setActiveLayer(layer);
-			for (Layer.LayerChangeListener l : Layer.listeners)
-				l.activeLayerChange(old, layer);
-		}
-		repaint();
-	}
-
-	@Override
-	protected DataSet getData()
-	{
-		if(activeLayer != null && activeLayer instanceof OsmDataLayer)
-			return ((OsmDataLayer)activeLayer).data;
-		return new DataSet();
-	}
-
-	public Boolean isDrawableLayer()
-	{
-		return activeLayer != null && activeLayer instanceof OsmDataLayer;
-	}
-
-	/**
-	 * Remove the layer from the mapview. If the layer was in the list before,
-	 * an LayerChange event is fired.
-	 */
-	public void removeLayer(Layer layer) {
-		if (layers.remove(layer)) {
-			// TODO: Deprecated
-			for (LayerChangeListener l : listeners)
-				l.layerRemoved(layer);
-			for (Layer.LayerChangeListener l : Layer.listeners)
-				l.layerRemoved(layer);
-		}
-		if (layer == editLayer) {
-			editLayer = null;
-			Main.ds.setSelected();
-		}
-		layer.destroy();
-	}
-
-	private Boolean virtualnodes = false;
-	public void enableVirtualNodes(Boolean state)
-	{
-		if(virtualnodes != state)
-		{
-			virtualnodes = state;
-			repaint();
-		}
-	}
-	public Boolean useVirtualNodes()
-	{
-		return virtualnodes;
-	}
-
-	/**
-	 * Moves the layer to the given new position. No event is fired.
-	 * @param layer		The layer to move
-	 * @param pos		The new position of the layer
-	 */
-	public void moveLayer(Layer layer, int pos) {
-		int curLayerPos = layers.indexOf(layer);
-		if (curLayerPos == -1)
-			throw new IllegalArgumentException(tr("layer not in list."));
-		if (pos == curLayerPos)
-			return; // already in place.
-		layers.remove(curLayerPos);
-		if (pos >= layers.size())
-			layers.add(layer);
-		else
-			layers.add(pos, layer);
-	}
-
-	/**
-	 * Draw the component.
-	 */
-	@Override public void paint(Graphics g) {
-		if (center == null)
-			return; // no data loaded yet.
-
-		// re-create offscreen-buffer if we've been resized, otherwise
-		// just re-use it.
-		if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
-		        || offscreenBuffer.getHeight() != getHeight())
-			offscreenBuffer = new BufferedImage(getWidth(), getHeight(),
-			        BufferedImage.TYPE_INT_ARGB);
-
-		Graphics2D tempG = offscreenBuffer.createGraphics();
-		tempG.setColor(Main.pref.getColor("background", Color.BLACK));
-		tempG.fillRect(0, 0, getWidth(), getHeight());
-
-		for (int i = layers.size()-1; i >= 0; --i) {
-			Layer l = layers.get(i);
-			if (l.visible/* && l != getActiveLayer()*/)
-				l.paint(tempG, this);
-		}
-
-		/*if (getActiveLayer() != null && getActiveLayer().visible)
-			getActiveLayer().paint(tempG, this);*/
-
-		for (MapViewPaintable mvp : temporaryLayers) {
-			mvp.paint(tempG, this);
-		}
-
-		// draw world borders
-		tempG.setColor(Color.WHITE);
-		Bounds b = new Bounds();
-		Point min = getPoint(getProjection().latlon2eastNorth(b.min));
-		Point max = getPoint(getProjection().latlon2eastNorth(b.max));
-		int x1 = Math.min(min.x, max.x);
-		int y1 = Math.min(min.y, max.y);
-		int x2 = Math.max(min.x, max.x);
-		int y2 = Math.max(min.y, max.y);
-		if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
-			tempG.drawRect(x1, y1, x2-x1+1, y2-y1+1);
-
-		if (playHeadMarker != null)
-			playHeadMarker.paint(tempG, this);
-
-		g.drawImage(offscreenBuffer, 0, 0, null);
-		super.paint(g);
-	}
-
-	/**
-	 * Set the new dimension to the projection class. Also adjust the components
-	 * scale, if in autoScale mode.
-	 */
-	public void recalculateCenterScale(BoundingXYVisitor box) {
-		// -20 to leave some border
-		int w = getWidth()-20;
-		if (w < 20)
-			w = 20;
-		int h = getHeight()-20;
-		if (h < 20)
-			h = 20;
-
-		EastNorth oldCenter = center;
-		double oldScale = this.scale;
-
-		if (box == null || box.min == null || box.max == null || box.min.equals(box.max)) {
-			// no bounds means whole world
-			center = getProjection().latlon2eastNorth(new LatLon(0,0));
-			EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
-			double scaleX = world.east()*2/w;
-			double scaleY = world.north()*2/h;
-			scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
-		} else {
-			center = new EastNorth(box.min.east()/2+box.max.east()/2, box.min.north()/2+box.max.north()/2);
-			double scaleX = (box.max.east()-box.min.east())/w;
-			double scaleY = (box.max.north()-box.min.north())/h;
-			scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
-		}
-
-		if (!center.equals(oldCenter))
-			firePropertyChange("center", oldCenter, center);
-		if (oldScale != scale)
-			firePropertyChange("scale", oldScale, scale);
-		repaint();
-	}
-
-	/**
-	 * Add a listener for changes of active layer.
-	 * @param listener The listener that get added.
-	 * @deprecated Use Layer.listener.add instead.
-	 */
-	@Deprecated public void addLayerChangeListener(LayerChangeListener listener) {
-		if (listener != null)
-			listeners.add(listener);
-	}
-
-	/**
-	 * Remove the listener.
-	 * @param listener The listener that get removed from the list.
-	 * @deprecated Use Layer.listener.remove instead
-	 */
-	@Deprecated public void removeLayerChangeListener(LayerChangeListener listener) {
-		listeners.remove(listener);
-	}
-
-	/**
-	 * @return An unmodificable list of all layers
-	 */
-	public Collection<Layer> getAllLayers() {
-		return Collections.unmodifiableCollection(layers);
-	}
-
-	/**
-	 * Set the active selection to the given value and raise an layerchange event.
-	 */
-	public void setActiveLayer(Layer layer) {
-		if (!layers.contains(layer))
-			throw new IllegalArgumentException("Layer must be in layerlist");
-		if (layer instanceof OsmDataLayer) {
-			editLayer = (OsmDataLayer)layer;
-			Main.ds = editLayer.data;
-		}
-		else
-			Main.ds.setSelected();
-		DataSet.fireSelectionChanged(Main.ds.getSelected());
-		Layer old = activeLayer;
-		activeLayer = layer;
-		if (old != layer) {
-			// TODO: Deprecated
-			for (LayerChangeListener l : listeners)
-				l.activeLayerChange(old, layer);
-			for (Layer.LayerChangeListener l : Layer.listeners)
-				l.activeLayerChange(old, layer);
-		}
-		repaint();
-	}
-
-	/**
-	 * @return The current active layer
-	 */
-	public Layer getActiveLayer() {
-		return activeLayer;
-	}
-
-	/**
-	 * In addition to the base class funcitonality, this keep trak of the autoscale
-	 * feature.
-	 */
-	@Override public void zoomTo(EastNorth newCenter, double scale) {
-		EastNorth oldCenter = center;
-		double oldScale = this.scale;
-		super.zoomTo(newCenter, scale);
-		if ((oldCenter == null && center != null) || !oldCenter.equals(center))
-			firePropertyChange("center", oldCenter, center);
-		if (oldScale != scale)
-			firePropertyChange("scale", oldScale, scale);
-	}
-
-	/**
-	 * Tries to zoom to the download boundingbox[es] of the current edit layer
-	 * (aka {@link OsmDataLayer}). If the edit layer has multiple download bounding
-	 * boxes it zooms to a large virtual bounding box containing all smaller ones.
-	 * This implementation can be used for resolving ticket #1461.
-	 *
-	 * @return <code>true</code> if a zoom operation has been performed
-	 * @author Jan Peter Stotz
-	 */
-	public boolean zoomToEditLayerBoundingBox() {
-		// workaround for #1461 (zoom to download bounding box instead of all data)
-		// In case we already have an existing data layer ...
-		Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources;
-		// ... with bounding box[es] of data loaded from OSM or a file...
-		BoundingXYVisitor bbox = new BoundingXYVisitor();
-		for (DataSource ds : dataSources) {
-			if (ds.bounds != null) {
-				bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max));
-				bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min));
-			}
-			if (bbox.max != null && bbox.min != null && !bbox.max.equals(bbox.min)) {
-				// ... we zoom to it's bounding box
-				recalculateCenterScale(bbox);
-				return true;
-			}
-		}
-		return false;
-	}
-
-	public boolean addTemporaryLayer(MapViewPaintable mvp) {
-		if (temporaryLayers.contains(mvp)) return false;
-		return temporaryLayers.add(mvp);
-	}
-
-	public boolean removeTemporaryLayer(MapViewPaintable mvp) {
-		return temporaryLayers.remove(mvp);
-	}
+    /**
+     * Interface to notify listeners of the change of the active layer.
+     * @author imi
+     * @deprecated Use Layer.LayerChangeListener instead
+     */
+    @Deprecated public interface LayerChangeListener {
+        void activeLayerChange(Layer oldLayer, Layer newLayer);
+        void layerAdded(Layer newLayer);
+        void layerRemoved(Layer oldLayer);
+    }
+
+    /**
+     * A list of all layers currently loaded.
+     */
+    private ArrayList<Layer> layers = new ArrayList<Layer>();
+    /**
+     * The play head marker: there is only one of these so it isn't in any specific layer
+     */
+    public PlayHeadMarker playHeadMarker = null;
+    /**
+     * Direct link to the edit layer (if any) in the layers list.
+     */
+    public OsmDataLayer editLayer;
+    /**
+     * The layer from the layers list that is currently active.
+     */
+    private Layer activeLayer;
+
+    /**
+     * The last event performed by mouse.
+     */
+    public MouseEvent lastMEvent;
+
+    private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();
+
+    private BufferedImage offscreenBuffer;
+
+    /**
+     * The listener of the active layer changes.
+     * @deprecated Use Layer.listener instead.
+     */
+    @Deprecated private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>();
+
+    public MapView() {
+        addComponentListener(new ComponentAdapter(){
+            @Override public void componentResized(ComponentEvent e) {
+                removeComponentListener(this);
+
+                if (!zoomToEditLayerBoundingBox())
+                    new AutoScaleAction("data").actionPerformed(null);
+
+                new MapMover(MapView.this, Main.contentPane);
+                JosmAction mv;
+                mv = new MoveAction(MoveAction.Direction.UP);
+                if (mv.getShortcut() != null) {
+                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "UP");
+                    Main.contentPane.getActionMap().put("UP", mv);
+                }
+                mv = new MoveAction(MoveAction.Direction.DOWN);
+                if (mv.getShortcut() != null) {
+                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "DOWN");
+                    Main.contentPane.getActionMap().put("DOWN", mv);
+                }
+                mv = new MoveAction(MoveAction.Direction.LEFT);
+                if (mv.getShortcut() != null) {
+                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "LEFT");
+                    Main.contentPane.getActionMap().put("LEFT", mv);
+                }
+                mv = new MoveAction(MoveAction.Direction.RIGHT);
+                if (mv.getShortcut() != null) {
+                    Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(mv.getShortcut().getKeyStroke(), "RIGHT");
+                    Main.contentPane.getActionMap().put("RIGHT", mv);
+                }
+
+                MapSlider zoomSlider = new MapSlider(MapView.this);
+                add(zoomSlider);
+                zoomSlider.setBounds(3, 0, 114, 30);
+
+                MapScaler scaler = new MapScaler(MapView.this, Main.proj);
+                add(scaler);
+                scaler.setLocation(10,30);
+            }
+        });
+
+        // listend to selection changes to redraw the map
+        DataSet.selListeners.add(new SelectionChangedListener(){
+            public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+                repaint();
+            }
+        });
+
+        //store the last mouse action
+        this.addMouseMotionListener(new MouseMotionListener() {
+            public void mouseDragged(MouseEvent e) {
+                mouseMoved(e);
+            }
+            public void mouseMoved(MouseEvent e) {
+                lastMEvent = e;
+            }
+        });
+    }
+
+    /**
+     * Add a layer to the current MapView. The layer will be added at topmost
+     * position.
+     */
+    public void addLayer(Layer layer) {
+        if (layer instanceof OsmDataLayer) {
+            editLayer = (OsmDataLayer)layer;
+            Main.ds = editLayer.data;
+            editLayer.listenerModified.add(new ModifiedChangedListener(){
+                public void modifiedChanged(boolean value, OsmDataLayer source) {
+                    JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+tr("Java OpenStreetMap - Editor"));
+                }
+            });
+        }
+        if (layer instanceof MarkerLayer && playHeadMarker == null)
+            playHeadMarker = PlayHeadMarker.create();
+        int pos = layers.size();
+        while(pos > 0 && layers.get(pos-1).background)
+            --pos;
+        layers.add(pos, layer);
+
+        // TODO: Deprecated
+        for (LayerChangeListener l : listeners)
+            l.layerAdded(layer);
+        for (Layer.LayerChangeListener l : Layer.listeners)
+            l.layerAdded(layer);
+        if (layer instanceof OsmDataLayer || activeLayer == null) {
+            // autoselect the new layer
+            Layer old = activeLayer;
+            setActiveLayer(layer);
+            for (Layer.LayerChangeListener l : Layer.listeners)
+                l.activeLayerChange(old, layer);
+        }
+        repaint();
+    }
+
+    @Override
+    protected DataSet getData()
+    {
+        if(activeLayer != null && activeLayer instanceof OsmDataLayer)
+            return ((OsmDataLayer)activeLayer).data;
+        return new DataSet();
+    }
+
+    public Boolean isDrawableLayer()
+    {
+        return activeLayer != null && activeLayer instanceof OsmDataLayer;
+    }
+
+    /**
+     * Remove the layer from the mapview. If the layer was in the list before,
+     * an LayerChange event is fired.
+     */
+    public void removeLayer(Layer layer) {
+        if (layers.remove(layer)) {
+            // TODO: Deprecated
+            for (LayerChangeListener l : listeners)
+                l.layerRemoved(layer);
+            for (Layer.LayerChangeListener l : Layer.listeners)
+                l.layerRemoved(layer);
+        }
+        if (layer == editLayer) {
+            editLayer = null;
+            Main.ds.setSelected();
+        }
+        layer.destroy();
+    }
+
+    private Boolean virtualnodes = false;
+    public void enableVirtualNodes(Boolean state)
+    {
+        if(virtualnodes != state)
+        {
+            virtualnodes = state;
+            repaint();
+        }
+    }
+    public Boolean useVirtualNodes()
+    {
+        return virtualnodes;
+    }
+
+    /**
+     * Moves the layer to the given new position. No event is fired.
+     * @param layer     The layer to move
+     * @param pos       The new position of the layer
+     */
+    public void moveLayer(Layer layer, int pos) {
+        int curLayerPos = layers.indexOf(layer);
+        if (curLayerPos == -1)
+            throw new IllegalArgumentException(tr("layer not in list."));
+        if (pos == curLayerPos)
+            return; // already in place.
+        layers.remove(curLayerPos);
+        if (pos >= layers.size())
+            layers.add(layer);
+        else
+            layers.add(pos, layer);
+    }
+
+    /**
+     * Draw the component.
+     */
+    @Override public void paint(Graphics g) {
+        if (center == null)
+            return; // no data loaded yet.
+
+        // re-create offscreen-buffer if we've been resized, otherwise
+        // just re-use it.
+        if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
+                || offscreenBuffer.getHeight() != getHeight())
+            offscreenBuffer = new BufferedImage(getWidth(), getHeight(),
+                    BufferedImage.TYPE_INT_ARGB);
+
+        Graphics2D tempG = offscreenBuffer.createGraphics();
+        tempG.setColor(Main.pref.getColor("background", Color.BLACK));
+        tempG.fillRect(0, 0, getWidth(), getHeight());
+
+        for (int i = layers.size()-1; i >= 0; --i) {
+            Layer l = layers.get(i);
+            if (l.visible/* && l != getActiveLayer()*/)
+                l.paint(tempG, this);
+        }
+
+        /*if (getActiveLayer() != null && getActiveLayer().visible)
+            getActiveLayer().paint(tempG, this);*/
+
+        for (MapViewPaintable mvp : temporaryLayers) {
+            mvp.paint(tempG, this);
+        }
+
+        // draw world borders
+        tempG.setColor(Color.WHITE);
+        Bounds b = new Bounds();
+        Point min = getPoint(getProjection().latlon2eastNorth(b.min));
+        Point max = getPoint(getProjection().latlon2eastNorth(b.max));
+        int x1 = Math.min(min.x, max.x);
+        int y1 = Math.min(min.y, max.y);
+        int x2 = Math.max(min.x, max.x);
+        int y2 = Math.max(min.y, max.y);
+        if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
+            tempG.drawRect(x1, y1, x2-x1+1, y2-y1+1);
+
+        if (playHeadMarker != null)
+            playHeadMarker.paint(tempG, this);
+
+        g.drawImage(offscreenBuffer, 0, 0, null);
+        super.paint(g);
+    }
+
+    /**
+     * Set the new dimension to the projection class. Also adjust the components
+     * scale, if in autoScale mode.
+     */
+    public void recalculateCenterScale(BoundingXYVisitor box) {
+        // -20 to leave some border
+        int w = getWidth()-20;
+        if (w < 20)
+            w = 20;
+        int h = getHeight()-20;
+        if (h < 20)
+            h = 20;
+
+        EastNorth oldCenter = center;
+        double oldScale = this.scale;
+
+        if (box == null || box.min == null || box.max == null || box.min.equals(box.max)) {
+            // no bounds means whole world
+            center = getProjection().latlon2eastNorth(new LatLon(0,0));
+            EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
+            double scaleX = world.east()*2/w;
+            double scaleY = world.north()*2/h;
+            scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
+        } else {
+            center = new EastNorth(box.min.east()/2+box.max.east()/2, box.min.north()/2+box.max.north()/2);
+            double scaleX = (box.max.east()-box.min.east())/w;
+            double scaleY = (box.max.north()-box.min.north())/h;
+            scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
+        }
+
+        if (!center.equals(oldCenter))
+            firePropertyChange("center", oldCenter, center);
+        if (oldScale != scale)
+            firePropertyChange("scale", oldScale, scale);
+        repaint();
+    }
+
+    /**
+     * Add a listener for changes of active layer.
+     * @param listener The listener that get added.
+     * @deprecated Use Layer.listener.add instead.
+     */
+    @Deprecated public void addLayerChangeListener(LayerChangeListener listener) {
+        if (listener != null)
+            listeners.add(listener);
+    }
+
+    /**
+     * Remove the listener.
+     * @param listener The listener that get removed from the list.
+     * @deprecated Use Layer.listener.remove instead
+     */
+    @Deprecated public void removeLayerChangeListener(LayerChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    /**
+     * @return An unmodificable list of all layers
+     */
+    public Collection<Layer> getAllLayers() {
+        return Collections.unmodifiableCollection(layers);
+    }
+
+    /**
+     * Set the active selection to the given value and raise an layerchange event.
+     */
+    public void setActiveLayer(Layer layer) {
+        if (!layers.contains(layer))
+            throw new IllegalArgumentException("Layer must be in layerlist");
+        if (layer instanceof OsmDataLayer) {
+            editLayer = (OsmDataLayer)layer;
+            Main.ds = editLayer.data;
+        }
+        else
+            Main.ds.setSelected();
+        DataSet.fireSelectionChanged(Main.ds.getSelected());
+        Layer old = activeLayer;
+        activeLayer = layer;
+        if (old != layer) {
+            // TODO: Deprecated
+            for (LayerChangeListener l : listeners)
+                l.activeLayerChange(old, layer);
+            for (Layer.LayerChangeListener l : Layer.listeners)
+                l.activeLayerChange(old, layer);
+        }
+        repaint();
+    }
+
+    /**
+     * @return The current active layer
+     */
+    public Layer getActiveLayer() {
+        return activeLayer;
+    }
+
+    /**
+     * In addition to the base class funcitonality, this keep trak of the autoscale
+     * feature.
+     */
+    @Override public void zoomTo(EastNorth newCenter, double scale) {
+        EastNorth oldCenter = center;
+        double oldScale = this.scale;
+        super.zoomTo(newCenter, scale);
+        if ((oldCenter == null && center != null) || !oldCenter.equals(center))
+            firePropertyChange("center", oldCenter, center);
+        if (oldScale != scale)
+            firePropertyChange("scale", oldScale, scale);
+    }
+
+    /**
+     * Tries to zoom to the download boundingbox[es] of the current edit layer
+     * (aka {@link OsmDataLayer}). If the edit layer has multiple download bounding
+     * boxes it zooms to a large virtual bounding box containing all smaller ones.
+     * This implementation can be used for resolving ticket #1461.
+     *
+     * @return <code>true</code> if a zoom operation has been performed
+     * @author Jan Peter Stotz
+     */
+    public boolean zoomToEditLayerBoundingBox() {
+        // workaround for #1461 (zoom to download bounding box instead of all data)
+        // In case we already have an existing data layer ...
+        Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources;
+        // ... with bounding box[es] of data loaded from OSM or a file...
+        BoundingXYVisitor bbox = new BoundingXYVisitor();
+        for (DataSource ds : dataSources) {
+            if (ds.bounds != null) {
+                bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max));
+                bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min));
+            }
+            if (bbox.max != null && bbox.min != null && !bbox.max.equals(bbox.min)) {
+                // ... we zoom to it's bounding box
+                recalculateCenterScale(bbox);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean addTemporaryLayer(MapViewPaintable mvp) {
+        if (temporaryLayers.contains(mvp)) return false;
+        return temporaryLayers.add(mvp);
+    }
+
+    public boolean removeTemporaryLayer(MapViewPaintable mvp) {
+        return temporaryLayers.remove(mvp);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 1169)
@@ -33,327 +33,327 @@
 public class NavigatableComponent extends JComponent implements Helpful {
 
-	public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
-	public static final int snapDistance = sqr(Main.pref.getInteger("node.snap-distance", 10));
-
-	private static int sqr(int a) { return a*a;}
-	/**
-	 * The scale factor in x or y-units per pixel. This means, if scale = 10,
-	 * every physical pixel on screen are 10 x or 10 y units in the
-	 * northing/easting space of the projection.
-	 */
-	protected double scale;
-	/**
-	 * Center n/e coordinate of the desired screen center.
-	 */
-	protected EastNorth center;
-
-	public NavigatableComponent() {
-		setLayout(null);
-	}
-
-	protected DataSet getData()
-	{
-		return Main.ds;
-	}
-
-	/**
-	 * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
-	 */
-	public int zoom() {
-		double sizex = scale * getWidth();
-		double sizey = scale * getHeight();
-		for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
-			if (sizex > world.east() || sizey > world.north())
-				return zoom;
-		return 32;
-	}
-
-	/**
-	 * Return the current scale value.
-	 * @return The scale value currently used in display
-	 */
-	public double getScale() {
-		return scale;
-	}
-
-	/**
-	 * @return Returns the center point. A copy is returned, so users cannot
-	 * 		change the center by accessing the return value. Use zoomTo instead.
-	 */
-	public EastNorth getCenter() {
-		return center;
-	}
-
-	/**
-	 * @param x X-Pixelposition to get coordinate from
-	 * @param y Y-Pixelposition to get coordinate from
-	 *
-	 * @return Geographic coordinates from a specific pixel coordination
-	 * 		on the screen.
-	 */
-	public EastNorth getEastNorth(int x, int y) {
-		return new EastNorth(
-				center.east() + (x - getWidth()/2.0)*scale,
-				center.north() - (y - getHeight()/2.0)*scale);
-	}
-
-	/**
-	 * @param x X-Pixelposition to get coordinate from
-	 * @param y Y-Pixelposition to get coordinate from
-	 *
-	 * @return Geographic unprojected coordinates from a specific pixel coordination
-	 * 		on the screen.
-	 */
-	public LatLon getLatLon(int x, int y) {
-
-		return getProjection().eastNorth2latlon(getEastNorth(x, y));
-	}
-
-	/**
-	 * Return the point on the screen where this Coordinate would be.
-	 * @param p The point, where this geopoint would be drawn.
-	 * @return The point on screen where "point" would be drawn, relative
-	 * 		to the own top/left.
-	 */
-	public Point getPoint(EastNorth p) {
-		if(null == p)
-			return new Point();
-		double x = (p.east()-center.east())/scale + getWidth()/2;
-		double y = (center.north()-p.north())/scale + getHeight()/2;
-		return new Point((int)x,(int)y);
-	}
-
-	/**
-	 * Zoom to the given coordinate.
-	 * @param newCenter The center x-value (easting) to zoom to.
-	 * @param scale The scale to use.
-	 */
-	public void zoomTo(EastNorth newCenter, double scale) {
-		center = newCenter;
-		getProjection().eastNorth2latlon(center);
-		this.scale = scale;
-		repaint();
-	}
-
-	/**
-	 * Return the nearest point to the screen point given.
-	 * If a node within 10 pixel is found, the nearest node is returned.
-	 */
-	public final Node getNearestNode(Point p) {
-		double minDistanceSq = Double.MAX_VALUE;
-		Node minPrimitive = null;
-		for (Node n : getData().nodes) {
-			if (n.deleted || n.incomplete)
-				continue;
-			Point sp = getPoint(n.eastNorth);
-			double dist = p.distanceSq(sp);
-			if (minDistanceSq > dist && dist < snapDistance) {
-				minDistanceSq = p.distanceSq(sp);
-				minPrimitive = n;
-			}
-			// prefer already selected node when multiple nodes on one point
-			else if(minDistanceSq == dist && n.selected && !minPrimitive.selected)
-			{
-				minPrimitive = n;
-			}
-		}
-		return minPrimitive;
-	}
-
-	/**
-	 * @return all way segments within 10px of p, sorted by their
-	 * perpendicular distance.
-	 * 
-	 * @param p the point for which to search the nearest segment.
-	 */
-	public final List<WaySegment> getNearestWaySegments(Point p) {
-		TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
-		for (Way w : getData().ways) {
-			if (w.deleted || w.incomplete) continue;
-			Node lastN = null;
-			int i = -2;
-			for (Node n : w.nodes) {
-				i++;
-				if (n.deleted || n.incomplete) continue;
-				if (lastN == null) {
-					lastN = n;
-					continue;
-				}
-
-				Point A = getPoint(lastN.eastNorth);
-				Point B = getPoint(n.eastNorth);
-				double c = A.distanceSq(B);
-				double a = p.distanceSq(B);
-				double b = p.distanceSq(A);
-				double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
-				if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
-					if(w.selected) // prefer selected ways a little bit
-						perDist -= 0.00001;
-					List<WaySegment> l;
-					if (nearest.containsKey(perDist)) {
-						l = nearest.get(perDist);
-					} else {
-						l = new LinkedList<WaySegment>();
-						nearest.put(perDist, l);
-					}
-					l.add(new WaySegment(w, i));
-				}
-
-				lastN = n;
-			}
-		}
-		ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
-		for (List<WaySegment> wss : nearest.values()) {
-			nearestList.addAll(wss);
-		}
-		return nearestList;
-	}
-
-	/**
-	 * @return the nearest way segment to the screen point given that is not 
-	 * in ignore.
-	 * 
-	 * @param p the point for which to search the nearest segment.
-	 * @param ignore a collection of segments which are not to be returned.
-	 * May be null.
-	 */
-	public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
-		List<WaySegment> nearest = getNearestWaySegments(p);
-		if (ignore != null) nearest.removeAll(ignore);
-		return nearest.isEmpty() ? null : nearest.get(0);
-	}
-
-	/**
-	 * @return the nearest way segment to the screen point given.
-	 */
-	public final WaySegment getNearestWaySegment(Point p) {
-		return getNearestWaySegment(p, null);
-	}
-	
-	/**
-	 * @return the nearest way to the screen point given.
-	 */
-	public final Way getNearestWay(Point p) {
-		WaySegment nearestWaySeg = getNearestWaySegment(p);
-		return nearestWaySeg == null ? null : nearestWaySeg.way;
-	}
-
-	/**
-	 * Return the object, that is nearest to the given screen point.
-	 *
-	 * First, a node will be searched. If a node within 10 pixel is found, the
-	 * nearest node is returned.
-	 *
-	 * If no node is found, search for near ways.
-	 *
-	 * If nothing is found, return <code>null</code>.
-	 *
-	 * @param p The point on screen.
-	 * @return  The primitive that is nearest to the point p.
-	 */
-	public OsmPrimitive getNearest(Point p) {
-		OsmPrimitive osm = getNearestNode(p);
-		if (osm == null)
-		{
-			osm = getNearestWay(p);
-		}
-		return osm;
-	}
-
-	/**
-	 * Returns a singleton of the nearest object, or else an empty collection.
-	 */
-	public Collection<OsmPrimitive> getNearestCollection(Point p) {
-		OsmPrimitive osm = getNearest(p);
-		if (osm == null) 
-			return Collections.emptySet();
-		return Collections.singleton(osm);
-	}
-
-	/**
-	 * @return A list of all objects that are nearest to
-	 * the mouse.  Does a simple sequential scan on all the data.
-	 *
-	 * @return A collection of all items or <code>null</code>
-	 * 		if no item under or near the point. The returned
-	 * 		list is never empty.
-	 */
-	public Collection<OsmPrimitive> getAllNearest(Point p) {
-		Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
-			for (Way w : getData().ways) {
-			if (w.deleted || w.incomplete) continue;
-			Node lastN = null;
-			for (Node n : w.nodes) {
-				if (n.deleted || n.incomplete) continue;
-				if (lastN == null) {
-					lastN = n;
-					continue;
-				}
-				Point A = getPoint(lastN.eastNorth);
-				Point B = getPoint(n.eastNorth);
-				double c = A.distanceSq(B);
-				double a = p.distanceSq(B);
-				double b = p.distanceSq(A);
-				double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
-				if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
-					nearest.add(w);
-						break;
-					}
-				lastN = n;
-				}
-			}
-		for (Node n : getData().nodes) {
-			if (!n.deleted && !n.incomplete
-					&& getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
-				nearest.add(n);
-			}
-		}
-		return nearest.isEmpty() ? null : nearest;
-	}
-
-	/**
-	 * @return A list of all nodes that are nearest to
-	 * the mouse.  Does a simple sequential scan on all the data.
-	 *
-	 * @return A collection of all nodes or <code>null</code>
-	 * 		if no node under or near the point. The returned
-	 * 		list is never empty.
-	 */
-	public Collection<Node> getNearestNodes(Point p) {
-		Collection<Node> nearest = new HashSet<Node>();
-		for (Node n : getData().nodes) {
-			if (!n.deleted && !n.incomplete
-					&& getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
-				nearest.add(n);
-			}
-		}
-		return nearest.isEmpty() ? null : nearest;
-	}
-
-	/**
-	 * @return the nearest nodes to the screen point given that is not 
-	 * in ignore.
-	 * 
-	 * @param p the point for which to search the nearest segment.
-	 * @param ignore a collection of nodes which are not to be returned.
-	 * May be null.
-	 */
-	public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) {
-		Collection<Node> nearest = getNearestNodes(p);
+    public static final EastNorth world = Main.proj.latlon2eastNorth(new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
+    public static final int snapDistance = sqr(Main.pref.getInteger("node.snap-distance", 10));
+
+    private static int sqr(int a) { return a*a;}
+    /**
+     * The scale factor in x or y-units per pixel. This means, if scale = 10,
+     * every physical pixel on screen are 10 x or 10 y units in the
+     * northing/easting space of the projection.
+     */
+    protected double scale;
+    /**
+     * Center n/e coordinate of the desired screen center.
+     */
+    protected EastNorth center;
+
+    public NavigatableComponent() {
+        setLayout(null);
+    }
+
+    protected DataSet getData()
+    {
+        return Main.ds;
+    }
+
+    /**
+     * Return the OSM-conform zoom factor (0 for whole world, 1 for half, 2 for quarter...)
+     */
+    public int zoom() {
+        double sizex = scale * getWidth();
+        double sizey = scale * getHeight();
+        for (int zoom = 0; zoom <= 32; zoom++, sizex *= 2, sizey *= 2)
+            if (sizex > world.east() || sizey > world.north())
+                return zoom;
+        return 32;
+    }
+
+    /**
+     * Return the current scale value.
+     * @return The scale value currently used in display
+     */
+    public double getScale() {
+        return scale;
+    }
+
+    /**
+     * @return Returns the center point. A copy is returned, so users cannot
+     *      change the center by accessing the return value. Use zoomTo instead.
+     */
+    public EastNorth getCenter() {
+        return center;
+    }
+
+    /**
+     * @param x X-Pixelposition to get coordinate from
+     * @param y Y-Pixelposition to get coordinate from
+     *
+     * @return Geographic coordinates from a specific pixel coordination
+     *      on the screen.
+     */
+    public EastNorth getEastNorth(int x, int y) {
+        return new EastNorth(
+                center.east() + (x - getWidth()/2.0)*scale,
+                center.north() - (y - getHeight()/2.0)*scale);
+    }
+
+    /**
+     * @param x X-Pixelposition to get coordinate from
+     * @param y Y-Pixelposition to get coordinate from
+     *
+     * @return Geographic unprojected coordinates from a specific pixel coordination
+     *      on the screen.
+     */
+    public LatLon getLatLon(int x, int y) {
+
+        return getProjection().eastNorth2latlon(getEastNorth(x, y));
+    }
+
+    /**
+     * Return the point on the screen where this Coordinate would be.
+     * @param p The point, where this geopoint would be drawn.
+     * @return The point on screen where "point" would be drawn, relative
+     *      to the own top/left.
+     */
+    public Point getPoint(EastNorth p) {
+        if(null == p)
+            return new Point();
+        double x = (p.east()-center.east())/scale + getWidth()/2;
+        double y = (center.north()-p.north())/scale + getHeight()/2;
+        return new Point((int)x,(int)y);
+    }
+
+    /**
+     * Zoom to the given coordinate.
+     * @param newCenter The center x-value (easting) to zoom to.
+     * @param scale The scale to use.
+     */
+    public void zoomTo(EastNorth newCenter, double scale) {
+        center = newCenter;
+        getProjection().eastNorth2latlon(center);
+        this.scale = scale;
+        repaint();
+    }
+
+    /**
+     * Return the nearest point to the screen point given.
+     * If a node within 10 pixel is found, the nearest node is returned.
+     */
+    public final Node getNearestNode(Point p) {
+        double minDistanceSq = Double.MAX_VALUE;
+        Node minPrimitive = null;
+        for (Node n : getData().nodes) {
+            if (n.deleted || n.incomplete)
+                continue;
+            Point sp = getPoint(n.eastNorth);
+            double dist = p.distanceSq(sp);
+            if (minDistanceSq > dist && dist < snapDistance) {
+                minDistanceSq = p.distanceSq(sp);
+                minPrimitive = n;
+            }
+            // prefer already selected node when multiple nodes on one point
+            else if(minDistanceSq == dist && n.selected && !minPrimitive.selected)
+            {
+                minPrimitive = n;
+            }
+        }
+        return minPrimitive;
+    }
+
+    /**
+     * @return all way segments within 10px of p, sorted by their
+     * perpendicular distance.
+     *
+     * @param p the point for which to search the nearest segment.
+     */
+    public final List<WaySegment> getNearestWaySegments(Point p) {
+        TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
+        for (Way w : getData().ways) {
+            if (w.deleted || w.incomplete) continue;
+            Node lastN = null;
+            int i = -2;
+            for (Node n : w.nodes) {
+                i++;
+                if (n.deleted || n.incomplete) continue;
+                if (lastN == null) {
+                    lastN = n;
+                    continue;
+                }
+
+                Point A = getPoint(lastN.eastNorth);
+                Point B = getPoint(n.eastNorth);
+                double c = A.distanceSq(B);
+                double a = p.distanceSq(B);
+                double b = p.distanceSq(A);
+                double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
+                if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
+                    if(w.selected) // prefer selected ways a little bit
+                        perDist -= 0.00001;
+                    List<WaySegment> l;
+                    if (nearest.containsKey(perDist)) {
+                        l = nearest.get(perDist);
+                    } else {
+                        l = new LinkedList<WaySegment>();
+                        nearest.put(perDist, l);
+                    }
+                    l.add(new WaySegment(w, i));
+                }
+
+                lastN = n;
+            }
+        }
+        ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
+        for (List<WaySegment> wss : nearest.values()) {
+            nearestList.addAll(wss);
+        }
+        return nearestList;
+    }
+
+    /**
+     * @return the nearest way segment to the screen point given that is not
+     * in ignore.
+     *
+     * @param p the point for which to search the nearest segment.
+     * @param ignore a collection of segments which are not to be returned.
+     * May be null.
+     */
+    public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
+        List<WaySegment> nearest = getNearestWaySegments(p);
+        if (ignore != null) nearest.removeAll(ignore);
+        return nearest.isEmpty() ? null : nearest.get(0);
+    }
+
+    /**
+     * @return the nearest way segment to the screen point given.
+     */
+    public final WaySegment getNearestWaySegment(Point p) {
+        return getNearestWaySegment(p, null);
+    }
+
+    /**
+     * @return the nearest way to the screen point given.
+     */
+    public final Way getNearestWay(Point p) {
+        WaySegment nearestWaySeg = getNearestWaySegment(p);
+        return nearestWaySeg == null ? null : nearestWaySeg.way;
+    }
+
+    /**
+     * Return the object, that is nearest to the given screen point.
+     *
+     * First, a node will be searched. If a node within 10 pixel is found, the
+     * nearest node is returned.
+     *
+     * If no node is found, search for near ways.
+     *
+     * If nothing is found, return <code>null</code>.
+     *
+     * @param p The point on screen.
+     * @return  The primitive that is nearest to the point p.
+     */
+    public OsmPrimitive getNearest(Point p) {
+        OsmPrimitive osm = getNearestNode(p);
+        if (osm == null)
+        {
+            osm = getNearestWay(p);
+        }
+        return osm;
+    }
+
+    /**
+     * Returns a singleton of the nearest object, or else an empty collection.
+     */
+    public Collection<OsmPrimitive> getNearestCollection(Point p) {
+        OsmPrimitive osm = getNearest(p);
+        if (osm == null)
+            return Collections.emptySet();
+        return Collections.singleton(osm);
+    }
+
+    /**
+     * @return A list of all objects that are nearest to
+     * the mouse.  Does a simple sequential scan on all the data.
+     *
+     * @return A collection of all items or <code>null</code>
+     *      if no item under or near the point. The returned
+     *      list is never empty.
+     */
+    public Collection<OsmPrimitive> getAllNearest(Point p) {
+        Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
+            for (Way w : getData().ways) {
+            if (w.deleted || w.incomplete) continue;
+            Node lastN = null;
+            for (Node n : w.nodes) {
+                if (n.deleted || n.incomplete) continue;
+                if (lastN == null) {
+                    lastN = n;
+                    continue;
+                }
+                Point A = getPoint(lastN.eastNorth);
+                Point B = getPoint(n.eastNorth);
+                double c = A.distanceSq(B);
+                double a = p.distanceSq(B);
+                double b = p.distanceSq(A);
+                double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
+                if (perDist < snapDistance && a < c+snapDistance && b < c+snapDistance) {
+                    nearest.add(w);
+                        break;
+                    }
+                lastN = n;
+                }
+            }
+        for (Node n : getData().nodes) {
+            if (!n.deleted && !n.incomplete
+                    && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
+                nearest.add(n);
+            }
+        }
+        return nearest.isEmpty() ? null : nearest;
+    }
+
+    /**
+     * @return A list of all nodes that are nearest to
+     * the mouse.  Does a simple sequential scan on all the data.
+     *
+     * @return A collection of all nodes or <code>null</code>
+     *      if no node under or near the point. The returned
+     *      list is never empty.
+     */
+    public Collection<Node> getNearestNodes(Point p) {
+        Collection<Node> nearest = new HashSet<Node>();
+        for (Node n : getData().nodes) {
+            if (!n.deleted && !n.incomplete
+                    && getPoint(n.eastNorth).distanceSq(p) < snapDistance) {
+                nearest.add(n);
+            }
+        }
+        return nearest.isEmpty() ? null : nearest;
+    }
+
+    /**
+     * @return the nearest nodes to the screen point given that is not
+     * in ignore.
+     *
+     * @param p the point for which to search the nearest segment.
+     * @param ignore a collection of nodes which are not to be returned.
+     * May be null.
+     */
+    public final Collection<Node> getNearestNodes(Point p, Collection<Node> ignore) {
+        Collection<Node> nearest = getNearestNodes(p);
                 if (nearest == null) return null;
-		if (ignore != null) nearest.removeAll(ignore);
-		return nearest.isEmpty() ? null : nearest;
-	}
-
-	/**
-	 * @return The projection to be used in calculating stuff.
-	 */
-	protected Projection getProjection() {
-		return Main.proj;
-	}
-
-	public String helpTopic() {
-	    String n = getClass().getName();
-	    return n.substring(n.lastIndexOf('.')+1);
+        if (ignore != null) nearest.removeAll(ignore);
+        return nearest.isEmpty() ? null : nearest;
+    }
+
+    /**
+     * @return The projection to be used in calculating stuff.
+     */
+    protected Projection getProjection() {
+        return Main.proj;
+    }
+
+    public String helpTopic() {
+        String n = getClass().getName();
+        return n.substring(n.lastIndexOf('.')+1);
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java	(revision 1169)
@@ -17,7 +17,7 @@
 /**
  * Renderer that renders the objects from an OsmPrimitive as data.
- * 
+ *
  * Can be used in lists and tables.
- * 
+ *
  * @author imi
  * @author Frederik Ramm <frederik@remote.org>
@@ -25,50 +25,50 @@
 public class OsmPrimitivRenderer implements ListCellRenderer, TableCellRenderer {
 
-	/**
-	 * NameVisitor provides proper names and icons for OsmPrimitives
-	 */
-	private NameVisitor visitor = new NameVisitor();
+    /**
+     * NameVisitor provides proper names and icons for OsmPrimitives
+     */
+    private NameVisitor visitor = new NameVisitor();
 
-	/**
-	 * Default list cell renderer - delegate for ListCellRenderer operation
-	 */
-	private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
-	
-	/**
-	 * Default table cell renderer - delegate for TableCellRenderer operation
-	 */
-	private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
+    /**
+     * Default list cell renderer - delegate for ListCellRenderer operation
+     */
+    private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
 
-	/**
-	 * Adapter method supporting the ListCellRenderer interface.
-	 */
-	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-		Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-		return renderer(def, (OsmPrimitive) value);
-	}
+    /**
+     * Default table cell renderer - delegate for TableCellRenderer operation
+     */
+    private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
 
-	/**
-	 * Adapter method supporting the TableCellRenderer interface. 
-	 */
-	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-		Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-		return renderer(def, (OsmPrimitive) value);
-	}
-	
-	/**
-	 * Internal method that stuffs information into the rendering component
-	 * provided that it's a kind of JLabel.
-	 * @param def the rendering component
-	 * @param value the OsmPrimtive to render
-	 * @return the modified rendering component
-	 */
-	private Component renderer(Component def, OsmPrimitive value) {
-		if (def != null && value != null && def instanceof JLabel) {
-			(value).visit(visitor);
-			((JLabel)def).setText(visitor.name);
-			((JLabel)def).setIcon(visitor.icon);
-		}
-		return def;
-	}
-	
+    /**
+     * Adapter method supporting the ListCellRenderer interface.
+     */
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+        Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+        return renderer(def, (OsmPrimitive) value);
+    }
+
+    /**
+     * Adapter method supporting the TableCellRenderer interface.
+     */
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+        Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        return renderer(def, (OsmPrimitive) value);
+    }
+
+    /**
+     * Internal method that stuffs information into the rendering component
+     * provided that it's a kind of JLabel.
+     * @param def the rendering component
+     * @param value the OsmPrimtive to render
+     * @return the modified rendering component
+     */
+    private Component renderer(Component def, OsmPrimitive value) {
+        if (def != null && value != null && def instanceof JLabel) {
+            (value).visit(visitor);
+            ((JLabel)def).setText(visitor.name);
+            ((JLabel)def).setIcon(visitor.icon);
+        }
+        return def;
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/PleaseWaitDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/PleaseWaitDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/PleaseWaitDialog.java	(revision 1169)
@@ -20,21 +20,21 @@
 public class PleaseWaitDialog extends JDialog {
 
-	private final JProgressBar progressBar = new JProgressBar();
+    private final JProgressBar progressBar = new JProgressBar();
 
-	public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server..."));
-	public final BoundedRangeModel progress = progressBar.getModel();
-	public final JButton cancel = new JButton(I18n.tr("Cancel"));
+    public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server..."));
+    public final BoundedRangeModel progress = progressBar.getModel();
+    public final JButton cancel = new JButton(I18n.tr("Cancel"));
 
-	public PleaseWaitDialog(Component parent) {
-		super(JOptionPane.getFrameForComponent(parent), true);
-		setLayout(new GridBagLayout());
-		JPanel pane = new JPanel(new GridBagLayout());
-		pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
-		pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL));
-		pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL));
-		pane.add(cancel, GBC.eol().anchor(GBC.CENTER));
-		setContentPane(pane);
-		setSize(Main.pref.getInteger("progressdialog.size",400),100);
-		setLocationRelativeTo(Main.parent);
-	}
+    public PleaseWaitDialog(Component parent) {
+        super(JOptionPane.getFrameForComponent(parent), true);
+        setLayout(new GridBagLayout());
+        JPanel pane = new JPanel(new GridBagLayout());
+        pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+        pane.add(currentAction, GBC.eol().fill(GBC.HORIZONTAL));
+        pane.add(progressBar, GBC.eop().fill(GBC.HORIZONTAL));
+        pane.add(cancel, GBC.eol().anchor(GBC.CENTER));
+        setContentPane(pane);
+        setSize(Main.pref.getInteger("progressdialog.size",400),100);
+        setLocationRelativeTo(Main.parent);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java	(revision 1169)
@@ -26,124 +26,124 @@
 public abstract class PleaseWaitRunnable implements Runnable {
 
-	public String errorMessage;
+    public String errorMessage;
 
-	private boolean closeDialogCalled = false;
-	private boolean cancelled = false;
+    private boolean closeDialogCalled = false;
+    private boolean cancelled = false;
 
-	private final String title;
+    private final String title;
 
-	/**
-	 * Create the runnable object with a given message for the user.
-	 */
-	public PleaseWaitRunnable(String title) {
-		this.title = title;
-		Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!cancelled) {
-					cancelled = true;
-					cancel();
-				}
-			}
-		});
-		Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){
-			@Override public void windowClosing(WindowEvent e) {
-				if (!closeDialogCalled) {
-					if (!cancelled) {
-						cancelled = true;
-						cancel();
-					}
-					closeDialog();
-				}
-			}
-		});
-	}
+    /**
+     * Create the runnable object with a given message for the user.
+     */
+    public PleaseWaitRunnable(String title) {
+        this.title = title;
+        Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!cancelled) {
+                    cancelled = true;
+                    cancel();
+                }
+            }
+        });
+        Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){
+            @Override public void windowClosing(WindowEvent e) {
+                if (!closeDialogCalled) {
+                    if (!cancelled) {
+                        cancelled = true;
+                        cancel();
+                    }
+                    closeDialog();
+                }
+            }
+        });
+    }
 
-	public final void run() {
-		try {
-			if (cancelled)
-				return; // since realRun isn't executed, do not call to finish
+    public final void run() {
+        try {
+            if (cancelled)
+                return; // since realRun isn't executed, do not call to finish
 
-			// reset dialog state
-			Main.pleaseWaitDlg.setTitle(title);
-			errorMessage = null;
-			closeDialogCalled = false;
+            // reset dialog state
+            Main.pleaseWaitDlg.setTitle(title);
+            errorMessage = null;
+            closeDialogCalled = false;
 
-			// show the dialog
-			synchronized (this) {
-	            EventQueue.invokeLater(new Runnable() {
-	            	public void run() {
-	            		synchronized (PleaseWaitRunnable.this) {
-	            			PleaseWaitRunnable.this.notifyAll();
-	            		}
-	            		Main.pleaseWaitDlg.setVisible(true);
-	            	}
-	            });
-	            try {wait();} catch (InterruptedException e) {}
-			}
+            // show the dialog
+            synchronized (this) {
+                EventQueue.invokeLater(new Runnable() {
+                    public void run() {
+                        synchronized (PleaseWaitRunnable.this) {
+                            PleaseWaitRunnable.this.notifyAll();
+                        }
+                        Main.pleaseWaitDlg.setVisible(true);
+                    }
+                });
+                try {wait();} catch (InterruptedException e) {}
+            }
 
-			realRun();
-		} catch (SAXException x) {
-			x.printStackTrace();
-			errorMessage = tr("Error while parsing")+": "+x.getMessage();
-		} catch (FileNotFoundException x) {
-			x.printStackTrace();
-			errorMessage = tr("File not found")+": "+x.getMessage();
-		} catch (IOException x) {
-			x.printStackTrace();
-			errorMessage = x.getMessage();
-		} finally {
-			closeDialog();
-		}
-	}
+            realRun();
+        } catch (SAXException x) {
+            x.printStackTrace();
+            errorMessage = tr("Error while parsing")+": "+x.getMessage();
+        } catch (FileNotFoundException x) {
+            x.printStackTrace();
+            errorMessage = tr("File not found")+": "+x.getMessage();
+        } catch (IOException x) {
+            x.printStackTrace();
+            errorMessage = x.getMessage();
+        } finally {
+            closeDialog();
+        }
+    }
 
-	/**
-	 * User pressed cancel button.
-	 */
-	protected abstract void cancel();
+    /**
+     * User pressed cancel button.
+     */
+    protected abstract void cancel();
 
-	/**
-	 * Called in the worker thread to do the actual work. When any of the
-	 * exception is thrown, a message box will be displayed and closeDialog
-	 * is called. finish() is called in any case.
-	 */
-	protected abstract void realRun() throws SAXException, IOException;
+    /**
+     * Called in the worker thread to do the actual work. When any of the
+     * exception is thrown, a message box will be displayed and closeDialog
+     * is called. finish() is called in any case.
+     */
+    protected abstract void realRun() throws SAXException, IOException;
 
-	/**
-	 * Finish up the data work. Is guaranteed to be called if realRun is called.
-	 * Finish is called in the gui thread just after the dialog disappeared.
-	 */
-	protected abstract void finish();
+    /**
+     * Finish up the data work. Is guaranteed to be called if realRun is called.
+     * Finish is called in the gui thread just after the dialog disappeared.
+     */
+    protected abstract void finish();
 
-	/**
-	 * Close the dialog. Usually called from worker thread.
-	 */
-	public void closeDialog() {
-		if (closeDialogCalled)
-			return;
-		closeDialogCalled  = true;
-		try {
-			Runnable runnable = new Runnable(){
-				public void run() {
-					try {
-						finish();
-					} finally {
-						Main.pleaseWaitDlg.setVisible(false);
-						Main.pleaseWaitDlg.dispose();
-					}
-					if (errorMessage != null)
-						JOptionPane.showMessageDialog(Main.parent, errorMessage);
-				}
-			};
+    /**
+     * Close the dialog. Usually called from worker thread.
+     */
+    public void closeDialog() {
+        if (closeDialogCalled)
+            return;
+        closeDialogCalled  = true;
+        try {
+            Runnable runnable = new Runnable(){
+                public void run() {
+                    try {
+                        finish();
+                    } finally {
+                        Main.pleaseWaitDlg.setVisible(false);
+                        Main.pleaseWaitDlg.dispose();
+                    }
+                    if (errorMessage != null)
+                        JOptionPane.showMessageDialog(Main.parent, errorMessage);
+                }
+            };
 
-			// make sure, this is called in the dispatcher thread ASAP
-			if (EventQueue.isDispatchThread())
-				runnable.run();
-			else
-				EventQueue.invokeAndWait(runnable);
+            // make sure, this is called in the dispatcher thread ASAP
+            if (EventQueue.isDispatchThread())
+                runnable.run();
+            else
+                EventQueue.invokeAndWait(runnable);
 
-		} catch (InterruptedException e) {
-		} catch (InvocationTargetException e) {
-			throw new RuntimeException(e);
-		}
-	}
+        } catch (InterruptedException e) {
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/QuadStateCheckBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/QuadStateCheckBox.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/QuadStateCheckBox.java	(revision 1169)
@@ -23,166 +23,166 @@
 public class QuadStateCheckBox extends JCheckBox {
 
-	public enum State { NOT_SELECTED, SELECTED, UNSET, PARTIAL }
+    public enum State { NOT_SELECTED, SELECTED, UNSET, PARTIAL }
 
-	private final QuadStateDecorator model;
-	private State[] allowed;
+    private final QuadStateDecorator model;
+    private State[] allowed;
 
-	public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) {
-		super(text, icon);
-		this.allowed = allowed;
-		// Add a listener for when the mouse is pressed
-		super.addMouseListener(new MouseAdapter() {
-			@Override public void mousePressed(MouseEvent e) {
-				grabFocus();
-				model.nextState();
-			}
-		});
-		// Reset the keyboard action map
-		ActionMap map = new ActionMapUIResource();
-		map.put("pressed", new AbstractAction() {
-			public void actionPerformed(ActionEvent e) {
-				grabFocus();
-				model.nextState();
-			}
-		});
-		map.put("released", null);
-		SwingUtilities.replaceUIActionMap(this, map);
-		// set the model to the adapted model
-		model = new QuadStateDecorator(getModel());
-		setModel(model);
-		setState(initial);
-	}
-	public QuadStateCheckBox(String text, State initial, State[] allowed) {
-		this(text, null, initial, allowed);
-	}
+    public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) {
+        super(text, icon);
+        this.allowed = allowed;
+        // Add a listener for when the mouse is pressed
+        super.addMouseListener(new MouseAdapter() {
+            @Override public void mousePressed(MouseEvent e) {
+                grabFocus();
+                model.nextState();
+            }
+        });
+        // Reset the keyboard action map
+        ActionMap map = new ActionMapUIResource();
+        map.put("pressed", new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                grabFocus();
+                model.nextState();
+            }
+        });
+        map.put("released", null);
+        SwingUtilities.replaceUIActionMap(this, map);
+        // set the model to the adapted model
+        model = new QuadStateDecorator(getModel());
+        setModel(model);
+        setState(initial);
+    }
+    public QuadStateCheckBox(String text, State initial, State[] allowed) {
+        this(text, null, initial, allowed);
+    }
 
-	/** Do not let anyone add mouse listeners */
-	@Override public void addMouseListener(MouseListener l) { }
-	/**
-	 * Set the new state.
-	 */
-	public void setState(State state) { model.setState(state); }
-	/** Return the current state, which is determined by the
-	 * selection status of the model. */
-	public State getState() { return model.getState(); }
-	@Override public void setSelected(boolean b) {
-		if (b) {
-			setState(State.SELECTED);
-		} else {
-			setState(State.NOT_SELECTED);
-		}
-	}
+    /** Do not let anyone add mouse listeners */
+    @Override public void addMouseListener(MouseListener l) { }
+    /**
+     * Set the new state.
+     */
+    public void setState(State state) { model.setState(state); }
+    /** Return the current state, which is determined by the
+     * selection status of the model. */
+    public State getState() { return model.getState(); }
+    @Override public void setSelected(boolean b) {
+        if (b) {
+            setState(State.SELECTED);
+        } else {
+            setState(State.NOT_SELECTED);
+        }
+    }
 
-	private class QuadStateDecorator implements ButtonModel {
-		private final ButtonModel other;
-		private QuadStateDecorator(ButtonModel other) {
-			this.other = other;
-		}
-		private void setState(State state) {
-			if (state == State.NOT_SELECTED) {
-				other.setArmed(false);
-				other.setPressed(false);
-				other.setSelected(false);
-				setToolTipText(tr("false: the property is explicitly switched off"));
-			} else if (state == State.SELECTED) {
-				other.setArmed(false);
-				other.setPressed(false);
-				other.setSelected(true);
-				setToolTipText(tr("true: the property is explicitly switched on"));
-			} else if (state == State.PARTIAL) {
-				other.setArmed(true);
-				other.setPressed(true);
-				other.setSelected(true);
-				setToolTipText(tr("partial: different selected objects have different values, do not change"));
-			} else {
-				other.setArmed(true);
-				other.setPressed(true);
-				other.setSelected(false);
-				setToolTipText(tr("unset: do not set this property on the selected objects"));
-			}
-		}
-		/**
-		 * The current state is embedded in the selection / armed
-		 * state of the model.
-		 * 
-		 * We return the SELECTED state when the checkbox is selected
-		 * but not armed, PARTIAL state when the checkbox is
-		 * selected and armed (grey) and NOT_SELECTED when the
-		 * checkbox is deselected.
-		 */
-		private State getState() {
-			if (isSelected() && !isArmed()) {
-				// normal black tick
-				return State.SELECTED;
-			} else if (isSelected() && isArmed()) {
-				// don't care grey tick
-				return State.PARTIAL;
-			} else if (!isSelected() && !isArmed()) {
-				return State.NOT_SELECTED;
-			} else {
-				return State.UNSET;
-			}
-		}
-		/** Rotate to the next allowed state.*/
-		private void nextState() {
-			State current = getState();
-			for (int i = 0; i < allowed.length; i++) {
-				if (allowed[i] == current) {
-					setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]);
-					break;
-				}
-			}
-		}
-		/** Filter: No one may change the armed/selected/pressed status except us. */
-		public void setArmed(boolean b) { }
-		public void setSelected(boolean b) { }
-		public void setPressed(boolean b) { }
-		/** We disable focusing on the component when it is not
-		 * enabled. */
-		public void setEnabled(boolean b) {
-			setFocusable(b);
-			other.setEnabled(b);
-		}
-		/** All these methods simply delegate to the "other" model
-		 * that is being decorated. */
-		public boolean isArmed() { return other.isArmed(); }
-		public boolean isSelected() { return other.isSelected(); }
-		public boolean isEnabled() { return other.isEnabled(); }
-		public boolean isPressed() { return other.isPressed(); }
-		public boolean isRollover() { return other.isRollover(); }
-		public void setRollover(boolean b) { other.setRollover(b); }
-		public void setMnemonic(int key) { other.setMnemonic(key); }
-		public int getMnemonic() { return other.getMnemonic(); }
-		public void setActionCommand(String s) {
-			other.setActionCommand(s);
-		}
-		public String getActionCommand() {
-			return other.getActionCommand();
-		}
-		public void setGroup(ButtonGroup group) {
-			other.setGroup(group);
-		}
-		public void addActionListener(ActionListener l) {
-			other.addActionListener(l);
-		}
-		public void removeActionListener(ActionListener l) {
-			other.removeActionListener(l);
-		}
-		public void addItemListener(ItemListener l) {
-			other.addItemListener(l);
-		}
-		public void removeItemListener(ItemListener l) {
-			other.removeItemListener(l);
-		}
-		public void addChangeListener(ChangeListener l) {
-			other.addChangeListener(l);
-		}
-		public void removeChangeListener(ChangeListener l) {
-			other.removeChangeListener(l);
-		}
-		public Object[] getSelectedObjects() {
-			return other.getSelectedObjects();
-		}
-	}
+    private class QuadStateDecorator implements ButtonModel {
+        private final ButtonModel other;
+        private QuadStateDecorator(ButtonModel other) {
+            this.other = other;
+        }
+        private void setState(State state) {
+            if (state == State.NOT_SELECTED) {
+                other.setArmed(false);
+                other.setPressed(false);
+                other.setSelected(false);
+                setToolTipText(tr("false: the property is explicitly switched off"));
+            } else if (state == State.SELECTED) {
+                other.setArmed(false);
+                other.setPressed(false);
+                other.setSelected(true);
+                setToolTipText(tr("true: the property is explicitly switched on"));
+            } else if (state == State.PARTIAL) {
+                other.setArmed(true);
+                other.setPressed(true);
+                other.setSelected(true);
+                setToolTipText(tr("partial: different selected objects have different values, do not change"));
+            } else {
+                other.setArmed(true);
+                other.setPressed(true);
+                other.setSelected(false);
+                setToolTipText(tr("unset: do not set this property on the selected objects"));
+            }
+        }
+        /**
+         * The current state is embedded in the selection / armed
+         * state of the model.
+         *
+         * We return the SELECTED state when the checkbox is selected
+         * but not armed, PARTIAL state when the checkbox is
+         * selected and armed (grey) and NOT_SELECTED when the
+         * checkbox is deselected.
+         */
+        private State getState() {
+            if (isSelected() && !isArmed()) {
+                // normal black tick
+                return State.SELECTED;
+            } else if (isSelected() && isArmed()) {
+                // don't care grey tick
+                return State.PARTIAL;
+            } else if (!isSelected() && !isArmed()) {
+                return State.NOT_SELECTED;
+            } else {
+                return State.UNSET;
+            }
+        }
+        /** Rotate to the next allowed state.*/
+        private void nextState() {
+            State current = getState();
+            for (int i = 0; i < allowed.length; i++) {
+                if (allowed[i] == current) {
+                    setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]);
+                    break;
+                }
+            }
+        }
+        /** Filter: No one may change the armed/selected/pressed status except us. */
+        public void setArmed(boolean b) { }
+        public void setSelected(boolean b) { }
+        public void setPressed(boolean b) { }
+        /** We disable focusing on the component when it is not
+         * enabled. */
+        public void setEnabled(boolean b) {
+            setFocusable(b);
+            other.setEnabled(b);
+        }
+        /** All these methods simply delegate to the "other" model
+         * that is being decorated. */
+        public boolean isArmed() { return other.isArmed(); }
+        public boolean isSelected() { return other.isSelected(); }
+        public boolean isEnabled() { return other.isEnabled(); }
+        public boolean isPressed() { return other.isPressed(); }
+        public boolean isRollover() { return other.isRollover(); }
+        public void setRollover(boolean b) { other.setRollover(b); }
+        public void setMnemonic(int key) { other.setMnemonic(key); }
+        public int getMnemonic() { return other.getMnemonic(); }
+        public void setActionCommand(String s) {
+            other.setActionCommand(s);
+        }
+        public String getActionCommand() {
+            return other.getActionCommand();
+        }
+        public void setGroup(ButtonGroup group) {
+            other.setGroup(group);
+        }
+        public void addActionListener(ActionListener l) {
+            other.addActionListener(l);
+        }
+        public void removeActionListener(ActionListener l) {
+            other.removeActionListener(l);
+        }
+        public void addItemListener(ItemListener l) {
+            other.addItemListener(l);
+        }
+        public void removeItemListener(ItemListener l) {
+            other.removeItemListener(l);
+        }
+        public void addChangeListener(ChangeListener l) {
+            other.addChangeListener(l);
+        }
+        public void removeChangeListener(ChangeListener l) {
+            other.removeChangeListener(l);
+        }
+        public Object[] getSelectedObjects() {
+            return other.getSelectedObjects();
+        }
+    }
 }
 
Index: trunk/src/org/openstreetmap/josm/gui/SelectionManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/SelectionManager.java	(revision 1169)
@@ -23,5 +23,5 @@
  * Manages the selection of a rectangle. Listening to left and right mouse button
  * presses and to mouse motions and draw the rectangle accordingly.
- * 
+ *
  * Left mouse button selects a rectangle from the press until release. Pressing
  * right mouse button while left is still pressed enable the rectangle to move
@@ -29,288 +29,288 @@
  * at constructor, except if the right is still pressed, which just remove the
  * selection rectangle and does nothing.
- * 
- * The point where the left mouse button was pressed and the current mouse 
+ *
+ * The point where the left mouse button was pressed and the current mouse
  * position are two opposite corners of the selection rectangle.
- * 
- * It is possible to specify an aspect ratio (width per height) which the 
+ *
+ * It is possible to specify an aspect ratio (width per height) which the
  * selection rectangle always must have. In this case, the selection rectangle
  * will be the largest window with this aspect ratio, where the position the left
- * mouse button was pressed and the corner of the current mouse position are at 
+ * mouse button was pressed and the corner of the current mouse position are at
  * opposite sites (the mouse position corner is the corner nearest to the mouse
- * cursor). 
- * 
- * When the left mouse button was released, an ActionEvent is send to the 
+ * cursor).
+ *
+ * When the left mouse button was released, an ActionEvent is send to the
  * ActionListener given at constructor. The source of this event is this manager.
- * 
+ *
  * @author imi
  */
 public class SelectionManager implements MouseListener, MouseMotionListener, PropertyChangeListener {
 
-	/**
-	 * This is the interface that an user of SelectionManager has to implement
-	 * to get informed when a selection closes.
-	 * @author imi
-	 */
-	public interface SelectionEnded {
-		/**
-		 * Called, when the left mouse button was released.
-		 * @param r The rectangle that is currently the selection.
-		 * @param alt Whether the alt key was pressed
-		 * @param shift Whether the shift key was pressed
-		 * @param ctrl Whether the ctrl key was pressed 
-		 * @see InputEvent#getModifiersEx()
-		 */
-		public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl);
-		/**
-		 * Called to register the selection manager for "active" property.
-		 * @param listener The listener to register
-		 */
-		public void addPropertyChangeListener(PropertyChangeListener listener);
-		/**
-		 * Called to remove the selection manager from the listener list 
-		 * for "active" property.
-		 * @param listener The listener to register
-		 */
-		public void removePropertyChangeListener(PropertyChangeListener listener);
-	}
-	/**
-	 * The listener that receives the events after left mouse button is released.
-	 */
-	private final SelectionEnded selectionEndedListener;
-	/**
-	 * Position of the map when the mouse button was pressed.
-	 * If this is not <code>null</code>, a rectangle is drawn on screen. 
-	 */
-	private Point mousePosStart;
-	/**
-	 * Position of the map when the selection rectangle was last drawn.
-	 */
-	private Point mousePos;
-	/**
-	 * The Component, the selection rectangle is drawn onto.
-	 */
-	private final NavigatableComponent nc;
-	/**
-	 * Whether the selection rectangle must obtain the aspect ratio of the 
-	 * drawComponent.
-	 */
-	private boolean aspectRatio;
-
-	/**
-	 * Create a new SelectionManager.
-	 *
-	 * @param selectionEndedListener The action listener that receives the event when
-	 * 		the left button is released.
-	 * @param aspectRatio If true, the selection window must obtain the aspect
-	 * 		ratio of the drawComponent.
-	 * @param navComp The component, the rectangle is drawn onto.
-	 */
-	public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) {
-		this.selectionEndedListener = selectionEndedListener;
-		this.aspectRatio = aspectRatio;
-		this.nc = navComp;
-	}
-	
-	/**
-	 * Register itself at the given event source.
-	 * @param eventSource The emitter of the mouse events.
-	 */
-	public void register(NavigatableComponent eventSource) {
-		eventSource.addMouseListener(this);
-		eventSource.addMouseMotionListener(this);
-		selectionEndedListener.addPropertyChangeListener(this);
+    /**
+     * This is the interface that an user of SelectionManager has to implement
+     * to get informed when a selection closes.
+     * @author imi
+     */
+    public interface SelectionEnded {
+        /**
+         * Called, when the left mouse button was released.
+         * @param r The rectangle that is currently the selection.
+         * @param alt Whether the alt key was pressed
+         * @param shift Whether the shift key was pressed
+         * @param ctrl Whether the ctrl key was pressed
+         * @see InputEvent#getModifiersEx()
+         */
+        public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl);
+        /**
+         * Called to register the selection manager for "active" property.
+         * @param listener The listener to register
+         */
+        public void addPropertyChangeListener(PropertyChangeListener listener);
+        /**
+         * Called to remove the selection manager from the listener list
+         * for "active" property.
+         * @param listener The listener to register
+         */
+        public void removePropertyChangeListener(PropertyChangeListener listener);
+    }
+    /**
+     * The listener that receives the events after left mouse button is released.
+     */
+    private final SelectionEnded selectionEndedListener;
+    /**
+     * Position of the map when the mouse button was pressed.
+     * If this is not <code>null</code>, a rectangle is drawn on screen.
+     */
+    private Point mousePosStart;
+    /**
+     * Position of the map when the selection rectangle was last drawn.
+     */
+    private Point mousePos;
+    /**
+     * The Component, the selection rectangle is drawn onto.
+     */
+    private final NavigatableComponent nc;
+    /**
+     * Whether the selection rectangle must obtain the aspect ratio of the
+     * drawComponent.
+     */
+    private boolean aspectRatio;
+
+    /**
+     * Create a new SelectionManager.
+     *
+     * @param selectionEndedListener The action listener that receives the event when
+     *      the left button is released.
+     * @param aspectRatio If true, the selection window must obtain the aspect
+     *      ratio of the drawComponent.
+     * @param navComp The component, the rectangle is drawn onto.
+     */
+    public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) {
+        this.selectionEndedListener = selectionEndedListener;
+        this.aspectRatio = aspectRatio;
+        this.nc = navComp;
+    }
+
+    /**
+     * Register itself at the given event source.
+     * @param eventSource The emitter of the mouse events.
+     */
+    public void register(NavigatableComponent eventSource) {
+        eventSource.addMouseListener(this);
+        eventSource.addMouseMotionListener(this);
+        selectionEndedListener.addPropertyChangeListener(this);
         eventSource.addPropertyChangeListener("scale", new PropertyChangeListener(){
-			public void propertyChange(PropertyChangeEvent evt) {
-				if (mousePosStart != null) {
-					paintRect();
-					mousePos = mousePosStart = null;
-				}
+            public void propertyChange(PropertyChangeEvent evt) {
+                if (mousePosStart != null) {
+                    paintRect();
+                    mousePos = mousePosStart = null;
+                }
             }
         });
-	}
-	/**
-	 * Unregister itself from the given event source. If a selection rectangle is
-	 * shown, hide it first.
-	 *
-	 * @param eventSource The emitter of the mouse events.
-	 */
-	public void unregister(Component eventSource) {
-		eventSource.removeMouseListener(this);
-		eventSource.removeMouseMotionListener(this);
-		selectionEndedListener.removePropertyChangeListener(this);
-	}
-
-	/**
-	 * If the correct button, from the "drawing rectangle" mode
-	 */
-	public void mousePressed(MouseEvent e) {
-		if (e.getButton() == MouseEvent.BUTTON1)
-			mousePosStart = mousePos = e.getPoint();
-	}
-
-	/**
-	 * If the correct button is hold, draw the rectangle.
-	 */
-	public void mouseDragged(MouseEvent e) {
-		int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); 
-
-		
-		if (buttonPressed != 0) {
-			if (mousePosStart == null)
-				mousePosStart = mousePos = e.getPoint();
-			paintRect();
-		}
-		
-		if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
-			mousePos = e.getPoint();
-			paintRect();
-		} else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
-			mousePosStart.x += e.getX()-mousePos.x;
-			mousePosStart.y += e.getY()-mousePos.y;
-			mousePos = e.getPoint();
-			paintRect();
-		}
-	}
-
-	/**
-	 * Check the state of the keys and buttons and set the selection accordingly.
-	 */
-	public void mouseReleased(MouseEvent e) {
-		if (e.getButton() != MouseEvent.BUTTON1)
-			return;
-		if (mousePos == null || mousePosStart == null)
-			return; // injected release from outside
-			
-		// disable the selection rect
-		paintRect();
-		Rectangle r = getSelectionRectangle();
-		mousePosStart = null;
-		mousePos = null;
-
-		boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
-		boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
-		boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
-		if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
-			selectionEndedListener.selectionEnded(r, alt, shift, ctrl);
-	}
-
-
-	/**
-	 * Draw a selection rectangle on screen. If already a rectangle is drawn,
-	 * it is removed instead.
-	 */
-	private void paintRect() {
-		if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
-			return;
-		Graphics g = nc.getGraphics();
-		g.setColor(Color.BLACK);
-		g.setXORMode(Color.WHITE);
-
-		Rectangle r = getSelectionRectangle();
-		g.drawRect(r.x,r.y,r.width,r.height);
-	}
-
-	/**
-	 * Calculate and return the current selection rectangle
-	 * @return A rectangle that spans from mousePos to mouseStartPos
-	 */
-	private Rectangle getSelectionRectangle() {
-		int x = mousePosStart.x;
-		int y = mousePosStart.y;
-		int w = mousePos.x - mousePosStart.x;
-		int h = mousePos.y - mousePosStart.y;
-		if (w < 0) {
-			x += w;
-			w = -w;
-		}
-		if (h < 0) {
-			y += h;
-			h = -h;
-		}
-		
-		if (aspectRatio) {
-			/* Keep the aspect ratio by growing the rectangle; the
-			 * rectangle is always under the cursor. */
-			double aspectRatio = (double)nc.getWidth()/nc.getHeight();
-			if ((double)w/h < aspectRatio) {
-				int neww = (int)(h*aspectRatio);
-				if (mousePos.x < mousePosStart.x)
-					x += w - neww;
-				w = neww;
-			} else {
-				int newh = (int)(w/aspectRatio);
-				if (mousePos.y < mousePosStart.y)
-					y += h - newh;
-				h = newh;
-			}
-		}
-		
-		return new Rectangle(x,y,w,h);
-	}
-
-	/**
-	 * If the action goes inactive, remove the selection rectangle from screen
-	 */
-	public void propertyChange(PropertyChangeEvent evt) {
-		if (evt.getPropertyName().equals("active") && !(Boolean)evt.getNewValue() && mousePosStart != null) {
-			paintRect();
-			mousePosStart = null;
-			mousePos = null;
-		}
-	}
-
-	/**
-	 * Return a list of all objects in the rectangle, respecting the different
-	 * modifier.
-	 * @param alt Whether the alt key was pressed, which means select all objects
-	 * 		that are touched, instead those which are completly covered.
-	 */
-	public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
-		Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>();
-
-		// whether user only clicked, not dragged.
-		boolean clicked = r.width <= 2 && r.height <= 2;
-		Point center = new Point(r.x+r.width/2, r.y+r.height/2);
-
-		if (clicked) {
-			OsmPrimitive osm = nc.getNearest(center);
-			if (osm != null)
-				selection.add(osm);
-		} else {
-			// nodes
-			for (Node n : nc.getData().nodes) {
-				if (!n.deleted && !n.incomplete && r.contains(nc.getPoint(n.eastNorth)))
-					selection.add(n);
-			}
-			
-			// ways
-			for (Way w : nc.getData().ways) {
-				if (w.deleted || w.nodes.isEmpty() || w.incomplete)
-						continue;
-				if (alt) {
-					for (Node n : w.nodes) {
-						if (!n.incomplete && r.contains(nc.getPoint(n.eastNorth))) {
-							selection.add(w);
-							break;
-						}
-					}
-				} else {
-					boolean allIn = true;
-					for (Node n : w.nodes) {
-						if (!n.incomplete && !r.contains(nc.getPoint(n.eastNorth))) {
-							allIn = false;
-							break;
-						}
-					}
-					if (allIn) selection.add(w);
-				}
-			}
-		}
-		return selection;
-	}
-	
-	public void mouseClicked(MouseEvent e) {}
-	public void mouseEntered(MouseEvent e) {}
-	public void mouseExited(MouseEvent e) {}
-	public void mouseMoved(MouseEvent e) {}
+    }
+    /**
+     * Unregister itself from the given event source. If a selection rectangle is
+     * shown, hide it first.
+     *
+     * @param eventSource The emitter of the mouse events.
+     */
+    public void unregister(Component eventSource) {
+        eventSource.removeMouseListener(this);
+        eventSource.removeMouseMotionListener(this);
+        selectionEndedListener.removePropertyChangeListener(this);
+    }
+
+    /**
+     * If the correct button, from the "drawing rectangle" mode
+     */
+    public void mousePressed(MouseEvent e) {
+        if (e.getButton() == MouseEvent.BUTTON1)
+            mousePosStart = mousePos = e.getPoint();
+    }
+
+    /**
+     * If the correct button is hold, draw the rectangle.
+     */
+    public void mouseDragged(MouseEvent e) {
+        int buttonPressed = e.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK);
+
+
+        if (buttonPressed != 0) {
+            if (mousePosStart == null)
+                mousePosStart = mousePos = e.getPoint();
+            paintRect();
+        }
+
+        if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
+            mousePos = e.getPoint();
+            paintRect();
+        } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
+            mousePosStart.x += e.getX()-mousePos.x;
+            mousePosStart.y += e.getY()-mousePos.y;
+            mousePos = e.getPoint();
+            paintRect();
+        }
+    }
+
+    /**
+     * Check the state of the keys and buttons and set the selection accordingly.
+     */
+    public void mouseReleased(MouseEvent e) {
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        if (mousePos == null || mousePosStart == null)
+            return; // injected release from outside
+
+        // disable the selection rect
+        paintRect();
+        Rectangle r = getSelectionRectangle();
+        mousePosStart = null;
+        mousePos = null;
+
+        boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
+        boolean alt = (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0;
+        boolean ctrl = (e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
+        if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0)
+            selectionEndedListener.selectionEnded(r, alt, shift, ctrl);
+    }
+
+
+    /**
+     * Draw a selection rectangle on screen. If already a rectangle is drawn,
+     * it is removed instead.
+     */
+    private void paintRect() {
+        if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
+            return;
+        Graphics g = nc.getGraphics();
+        g.setColor(Color.BLACK);
+        g.setXORMode(Color.WHITE);
+
+        Rectangle r = getSelectionRectangle();
+        g.drawRect(r.x,r.y,r.width,r.height);
+    }
+
+    /**
+     * Calculate and return the current selection rectangle
+     * @return A rectangle that spans from mousePos to mouseStartPos
+     */
+    private Rectangle getSelectionRectangle() {
+        int x = mousePosStart.x;
+        int y = mousePosStart.y;
+        int w = mousePos.x - mousePosStart.x;
+        int h = mousePos.y - mousePosStart.y;
+        if (w < 0) {
+            x += w;
+            w = -w;
+        }
+        if (h < 0) {
+            y += h;
+            h = -h;
+        }
+
+        if (aspectRatio) {
+            /* Keep the aspect ratio by growing the rectangle; the
+             * rectangle is always under the cursor. */
+            double aspectRatio = (double)nc.getWidth()/nc.getHeight();
+            if ((double)w/h < aspectRatio) {
+                int neww = (int)(h*aspectRatio);
+                if (mousePos.x < mousePosStart.x)
+                    x += w - neww;
+                w = neww;
+            } else {
+                int newh = (int)(w/aspectRatio);
+                if (mousePos.y < mousePosStart.y)
+                    y += h - newh;
+                h = newh;
+            }
+        }
+
+        return new Rectangle(x,y,w,h);
+    }
+
+    /**
+     * If the action goes inactive, remove the selection rectangle from screen
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt.getPropertyName().equals("active") && !(Boolean)evt.getNewValue() && mousePosStart != null) {
+            paintRect();
+            mousePosStart = null;
+            mousePos = null;
+        }
+    }
+
+    /**
+     * Return a list of all objects in the rectangle, respecting the different
+     * modifier.
+     * @param alt Whether the alt key was pressed, which means select all objects
+     *      that are touched, instead those which are completly covered.
+     */
+    public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
+        Collection<OsmPrimitive> selection = new LinkedList<OsmPrimitive>();
+
+        // whether user only clicked, not dragged.
+        boolean clicked = r.width <= 2 && r.height <= 2;
+        Point center = new Point(r.x+r.width/2, r.y+r.height/2);
+
+        if (clicked) {
+            OsmPrimitive osm = nc.getNearest(center);
+            if (osm != null)
+                selection.add(osm);
+        } else {
+            // nodes
+            for (Node n : nc.getData().nodes) {
+                if (!n.deleted && !n.incomplete && r.contains(nc.getPoint(n.eastNorth)))
+                    selection.add(n);
+            }
+
+            // ways
+            for (Way w : nc.getData().ways) {
+                if (w.deleted || w.nodes.isEmpty() || w.incomplete)
+                        continue;
+                if (alt) {
+                    for (Node n : w.nodes) {
+                        if (!n.incomplete && r.contains(nc.getPoint(n.eastNorth))) {
+                            selection.add(w);
+                            break;
+                        }
+                    }
+                } else {
+                    boolean allIn = true;
+                    for (Node n : w.nodes) {
+                        if (!n.incomplete && !r.contains(nc.getPoint(n.eastNorth))) {
+                            allIn = false;
+                            break;
+                        }
+                    }
+                    if (allIn) selection.add(w);
+                }
+            }
+        }
+        return selection;
+    }
+
+    public void mouseClicked(MouseEvent e) {}
+    public void mouseEntered(MouseEvent e) {}
+    public void mouseExited(MouseEvent e) {}
+    public void mouseMoved(MouseEvent e) {}
 }
Index: trunk/src/org/openstreetmap/josm/gui/SideButton.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/SideButton.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/SideButton.java	(revision 1169)
@@ -12,53 +12,53 @@
 
 public class SideButton extends JButton {
-	public SideButton(Action action)
-	{
-		super(action);
-		doStyle();
-		setText(null);
-	}
-	public SideButton(String imagename, String property, String tooltip, ActionListener actionListener)
-	{
-		super(ImageProvider.get("dialogs", imagename));
-		doStyle();
-		setActionCommand(imagename);
-		addActionListener(actionListener);
-		setToolTipText(tooltip);
-	}
-	@Deprecated
-	public SideButton(String name, String imagename, String property, String tooltip, int mnemonic, ActionListener actionListener)
-	{
-		super(tr(name), ImageProvider.get("dialogs", imagename));
-		setMnemonic(mnemonic);
-		setup(name, property, tooltip, actionListener);
-	}
-	public SideButton(String name, String imagename, String property, String tooltip, Shortcut shortcut, ActionListener actionListener)
-	{
-		super(tr(name), ImageProvider.get("dialogs", imagename));
-		if(shortcut != null)
+    public SideButton(Action action)
+    {
+        super(action);
+        doStyle();
+        setText(null);
+    }
+    public SideButton(String imagename, String property, String tooltip, ActionListener actionListener)
+    {
+        super(ImageProvider.get("dialogs", imagename));
+        doStyle();
+        setActionCommand(imagename);
+        addActionListener(actionListener);
+        setToolTipText(tooltip);
+    }
+    @Deprecated
+    public SideButton(String name, String imagename, String property, String tooltip, int mnemonic, ActionListener actionListener)
+    {
+        super(tr(name), ImageProvider.get("dialogs", imagename));
+        setMnemonic(mnemonic);
+        setup(name, property, tooltip, actionListener);
+    }
+    public SideButton(String name, String imagename, String property, String tooltip, Shortcut shortcut, ActionListener actionListener)
+    {
+        super(tr(name), ImageProvider.get("dialogs", imagename));
+        if(shortcut != null)
                 {
-			shortcut.setMnemonic(this);
+            shortcut.setMnemonic(this);
                         if(tooltip != null)
-				tooltip = Main.platform.makeTooltip(tooltip, shortcut);
+                tooltip = Main.platform.makeTooltip(tooltip, shortcut);
                 }
-		setup(name, property, tooltip, actionListener);
-	}
-	public SideButton(String name, String imagename, String property, String tooltip, ActionListener actionListener)
-	{
-		super(tr(name), ImageProvider.get("dialogs", imagename));
-		setup(name, property, tooltip, actionListener);
-	}
-	private void setup(String name, String property, String tooltip, ActionListener actionListener)
-	{
-		doStyle();
-		setActionCommand(name);
-		addActionListener(actionListener);
-		setToolTipText(tooltip);
-		putClientProperty("help", "Dialog/"+property+"/"+name);
-	}
-	private void doStyle()
-	{
-		setMargin(new Insets(1,1,1,1));
-		setIconTextGap(2);
-	}
+        setup(name, property, tooltip, actionListener);
+    }
+    public SideButton(String name, String imagename, String property, String tooltip, ActionListener actionListener)
+    {
+        super(tr(name), ImageProvider.get("dialogs", imagename));
+        setup(name, property, tooltip, actionListener);
+    }
+    private void setup(String name, String property, String tooltip, ActionListener actionListener)
+    {
+        doStyle();
+        setActionCommand(name);
+        addActionListener(actionListener);
+        setToolTipText(tooltip);
+        putClientProperty("help", "Dialog/"+property+"/"+name);
+    }
+    private void doStyle()
+    {
+        setMargin(new Insets(1,1,1,1));
+        setIconTextGap(2);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/SplashScreen.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/SplashScreen.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/SplashScreen.java	(revision 1169)
@@ -30,139 +30,139 @@
 /**
  * Show a splash screen so the user knows what is happening during startup.
- * 
- * @author cbrill 
+ *
+ * @author cbrill
  */
 public class SplashScreen extends JWindow {
 
-	private JLabel status;
-	private boolean visible;
+    private JLabel status;
+    private boolean visible;
 
-	private Runnable closerRunner;
+    private Runnable closerRunner;
 
-	public SplashScreen(boolean visible) {
-		super();
-		this.visible=visible;
+    public SplashScreen(boolean visible) {
+        super();
+        this.visible=visible;
 
-		if (!visible)
-			return;
+        if (!visible)
+            return;
 
-		// Add a nice border to the main splash screen
-		JPanel contentPane = (JPanel)this.getContentPane();
-		Border margin = new EtchedBorder(1, Color.white, Color.gray);
-		contentPane.setBorder(margin);
+        // Add a nice border to the main splash screen
+        JPanel contentPane = (JPanel)this.getContentPane();
+        Border margin = new EtchedBorder(1, Color.white, Color.gray);
+        contentPane.setBorder(margin);
 
-		// Add a margin from the border to the content
-		JPanel innerContentPane = new JPanel();
-		innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
-		contentPane.add(innerContentPane);
-		innerContentPane.setLayout(new GridBagLayout());
+        // Add a margin from the border to the content
+        JPanel innerContentPane = new JPanel();
+        innerContentPane.setBorder(new EmptyBorder(10, 10, 2, 10));
+        contentPane.add(innerContentPane);
+        innerContentPane.setLayout(new GridBagLayout());
 
-		// Add the logo
-		JLabel logo = new JLabel(ImageProvider.get("logo.png"));
-		GridBagConstraints gbc = new GridBagConstraints();
-		gbc.gridheight = 2;
-		innerContentPane.add(logo, gbc);
+        // Add the logo
+        JLabel logo = new JLabel(ImageProvider.get("logo.png"));
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.gridheight = 2;
+        innerContentPane.add(logo, gbc);
 
-		// Add the name of this application
-		JLabel caption = new JLabel(tr("JOSM - Java OpenStreetMap Editor"));
-		caption.setFont(new Font("Helvetica", Font.BOLD, 20));
-		gbc.gridheight = 1;
-		gbc.gridx = 1;
-		gbc.insets = new Insets(30, 0, 0, 0);
-		innerContentPane.add(caption, gbc);
+        // Add the name of this application
+        JLabel caption = new JLabel(tr("JOSM - Java OpenStreetMap Editor"));
+        caption.setFont(new Font("Helvetica", Font.BOLD, 20));
+        gbc.gridheight = 1;
+        gbc.gridx = 1;
+        gbc.insets = new Insets(30, 0, 0, 0);
+        innerContentPane.add(caption, gbc);
 
-		// Add the version number
-		JLabel version = new JLabel(tr("Version {0}", AboutAction.getVersionString()));
-		gbc.gridy = 1;
-		gbc.insets = new Insets(0, 0, 0, 0);
-		innerContentPane.add(version, gbc);
+        // Add the version number
+        JLabel version = new JLabel(tr("Version {0}", AboutAction.getVersionString()));
+        gbc.gridy = 1;
+        gbc.insets = new Insets(0, 0, 0, 0);
+        innerContentPane.add(version, gbc);
 
-		// Add a separator to the status text
-		JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
-		gbc.gridx = 0;
-		gbc.gridy = 2;
-		gbc.gridwidth = 2;
-		gbc.fill = GridBagConstraints.HORIZONTAL;
-		gbc.insets = new Insets(15, 0, 5, 0);
-		innerContentPane.add(separator, gbc);
+        // Add a separator to the status text
+        JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        gbc.gridwidth = 2;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.insets = new Insets(15, 0, 5, 0);
+        innerContentPane.add(separator, gbc);
 
-		// Add a status message
-		status = new JLabel();
-		gbc.gridy = 3;
-		gbc.insets = new Insets(0, 0, 0, 0);
-		innerContentPane.add(status, gbc);
-		setStatus(tr("Initializing"));
+        // Add a status message
+        status = new JLabel();
+        gbc.gridy = 3;
+        gbc.insets = new Insets(0, 0, 0, 0);
+        innerContentPane.add(status, gbc);
+        setStatus(tr("Initializing"));
 
-		pack();
+        pack();
 
-		// Center the splash screen
-		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-		Dimension labelSize = contentPane.getPreferredSize();
-		setLocation(screenSize.width / 2 - (labelSize.width / 2),
-		        screenSize.height / 2 - (labelSize.height / 2));
+        // Center the splash screen
+        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+        Dimension labelSize = contentPane.getPreferredSize();
+        setLocation(screenSize.width / 2 - (labelSize.width / 2),
+                screenSize.height / 2 - (labelSize.height / 2));
 
-		// Method to close the splash screen when being clicked or when closeSplash is called
-		closerRunner = new Runnable() {
-			public void run() {
-				setVisible(false);
-				dispose();
-			}
-		};
+        // Method to close the splash screen when being clicked or when closeSplash is called
+        closerRunner = new Runnable() {
+            public void run() {
+                setVisible(false);
+                dispose();
+            }
+        };
 
-		// Add ability to hide splash screen by clicking it
-		addMouseListener(new MouseAdapter() {
-			public void mousePressed(MouseEvent event) {
-				try {
-					closerRunner.run();
-				} catch (Exception e) {
-					e.printStackTrace();
-					// can catch InvocationTargetException
-					// can catch InterruptedException
-				}
-			}
-		});
-		
+        // Add ability to hide splash screen by clicking it
+        addMouseListener(new MouseAdapter() {
+            public void mousePressed(MouseEvent event) {
+                try {
+                    closerRunner.run();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    // can catch InvocationTargetException
+                    // can catch InterruptedException
+                }
+            }
+        });
+
         // Hide splashscreen when other window is created
-		Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK);
-		
-		setVisible(true);
-	}
-	
-	private AWTEventListener awtListener = new AWTEventListener() {
-		public void eventDispatched(AWTEvent event) {
-			if (event.getSource() != SplashScreen.this) {
-				closeSplash();
-			}
-		}		
-	};
+        Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK);
 
-	/**
-	 * This method sets the status message. It should be called prior to
-	 * actually doing the action.
-	 * 
-	 * @param message
-	 *            the message to be displayed
-	 */
-	public void setStatus(String message) {
-		if (!visible)
-			return;
-		status.setText(message + " ...");
-	}
+        setVisible(true);
+    }
 
-	/**
-	 * Closes the splashscreen. Call once you are done starting.
-	 */
-	public void closeSplash() {
-		if (!visible)
-			return;
-		Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener);
-		try {
-			SwingUtilities.invokeLater(closerRunner);
-		} catch (Exception e) {
-			e.printStackTrace();
-			// can catch InvocationTargetException
-			// can catch InterruptedException
-		}
-	}
+    private AWTEventListener awtListener = new AWTEventListener() {
+        public void eventDispatched(AWTEvent event) {
+            if (event.getSource() != SplashScreen.this) {
+                closeSplash();
+            }
+        }
+    };
+
+    /**
+     * This method sets the status message. It should be called prior to
+     * actually doing the action.
+     *
+     * @param message
+     *            the message to be displayed
+     */
+    public void setStatus(String message) {
+        if (!visible)
+            return;
+        status.setText(message + " ...");
+    }
+
+    /**
+     * Closes the splashscreen. Call once you are done starting.
+     */
+    public void closeSplash() {
+        if (!visible)
+            return;
+        Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener);
+        try {
+            SwingUtilities.invokeLater(closerRunner);
+        } catch (Exception e) {
+            e.printStackTrace();
+            // can catch InvocationTargetException
+            // can catch InterruptedException
+        }
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 1169)
@@ -24,55 +24,55 @@
 public class CommandStackDialog extends ToggleDialog implements CommandQueueListener {
 
-	private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
+    private DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode());
     private JTree tree = new JTree(treeModel);
 
-	public CommandStackDialog(final MapFrame mapFrame) {
-		super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
-		Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER), 100);
-		Main.main.undoRedo.listenerCommands.add(this);
+    public CommandStackDialog(final MapFrame mapFrame) {
+        super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
+        Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER), 100);
+        Main.main.undoRedo.listenerCommands.add(this);
 
-		tree.setRootVisible(false);
-		tree.setShowsRootHandles(true);
-		tree.expandRow(0);
-		tree.setCellRenderer(new DefaultTreeCellRenderer(){
-			@Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
-				super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
-				DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
-				if (v.getUserObject() instanceof JLabel) {
-					JLabel l = (JLabel)v.getUserObject();
-					setIcon(l.getIcon());
-					setText(l.getText());
-				}
-				return this;
-			}
-		});
-		tree.setVisibleRowCount(8);
-		add(new JScrollPane(tree), BorderLayout.CENTER);
-	}
+        tree.setRootVisible(false);
+        tree.setShowsRootHandles(true);
+        tree.expandRow(0);
+        tree.setCellRenderer(new DefaultTreeCellRenderer(){
+            @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+                super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+                DefaultMutableTreeNode v = (DefaultMutableTreeNode)value;
+                if (v.getUserObject() instanceof JLabel) {
+                    JLabel l = (JLabel)v.getUserObject();
+                    setIcon(l.getIcon());
+                    setText(l.getText());
+                }
+                return this;
+            }
+        });
+        tree.setVisibleRowCount(8);
+        add(new JScrollPane(tree), BorderLayout.CENTER);
+    }
 
-	@Override public void setVisible(boolean v) {
-		if (v)
-			buildList();
-		else if (tree != null)
-			treeModel.setRoot(new DefaultMutableTreeNode());
-		super.setVisible(v);
-	}
+    @Override public void setVisible(boolean v) {
+        if (v)
+            buildList();
+        else if (tree != null)
+            treeModel.setRoot(new DefaultMutableTreeNode());
+        super.setVisible(v);
+    }
 
-	private void buildList() {
-		if (Main.map == null || Main.map.mapView == null || Main.map.mapView.editLayer == null)
-			return;
-		Collection<Command> commands = Main.main.undoRedo.commands;
-		DefaultMutableTreeNode root = new DefaultMutableTreeNode();
-		for (Command c : commands)
-			root.add(c.description());
-		treeModel.setRoot(root);
-		tree.scrollRowToVisible(treeModel.getChildCount(root)-1);
-	}
+    private void buildList() {
+        if (Main.map == null || Main.map.mapView == null || Main.map.mapView.editLayer == null)
+            return;
+        Collection<Command> commands = Main.main.undoRedo.commands;
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode();
+        for (Command c : commands)
+            root.add(c.description());
+        treeModel.setRoot(root);
+        tree.scrollRowToVisible(treeModel.getChildCount(root)-1);
+    }
 
-	public void commandChanged(int queueSize, int redoSize) {
-		if (!isVisible())
-			return;
+    public void commandChanged(int queueSize, int redoSize) {
+        if (!isVisible())
+            return;
         treeModel.setRoot(new DefaultMutableTreeNode());
-		buildList();
+        buildList();
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 1169)
@@ -47,84 +47,84 @@
 public final class ConflictDialog extends ToggleDialog {
 
-	public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
-	private final DefaultListModel model = new DefaultListModel();
-	private final JList displaylist = new JList(model);
+    public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
+    private final DefaultListModel model = new DefaultListModel();
+    private final JList displaylist = new JList(model);
 
-	public ConflictDialog() {
-		super(tr("Conflict"), "conflict", tr("Merging conflicts."),
-		Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
-		displaylist.setCellRenderer(new OsmPrimitivRenderer());
-		displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-		displaylist.addMouseListener(new MouseAdapter(){
-			@Override public void mouseClicked(MouseEvent e) {
-				if (e.getClickCount() >= 2)
-					resolve();
-			}
-		});
-		add(new JScrollPane(displaylist), BorderLayout.CENTER);
+    public ConflictDialog() {
+        super(tr("Conflict"), "conflict", tr("Merging conflicts."),
+        Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
+        displaylist.setCellRenderer(new OsmPrimitivRenderer());
+        displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        displaylist.addMouseListener(new MouseAdapter(){
+            @Override public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() >= 2)
+                    resolve();
+            }
+        });
+        add(new JScrollPane(displaylist), BorderLayout.CENTER);
 
-		JPanel buttonPanel = new JPanel(new GridLayout(1,2));
-		buttonPanel.add(new SideButton(marktr("Resolve"), "conflict", "Conflict",
-		tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				resolve();
-			}
-		}));
+        JPanel buttonPanel = new JPanel(new GridLayout(1,2));
+        buttonPanel.add(new SideButton(marktr("Resolve"), "conflict", "Conflict",
+        tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                resolve();
+            }
+        }));
 
-		buttonPanel.add(new SideButton(marktr("Select"), "select", "Conflict",
-		tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
-				for (Object o : displaylist.getSelectedValues())
-					sel.add((OsmPrimitive)o);
-				Main.ds.setSelected(sel);
-			}
-		}));
-		add(buttonPanel, BorderLayout.SOUTH);
+        buttonPanel.add(new SideButton(marktr("Select"), "select", "Conflict",
+        tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
+                for (Object o : displaylist.getSelectedValues())
+                    sel.add((OsmPrimitive)o);
+                Main.ds.setSelected(sel);
+            }
+        }));
+        add(buttonPanel, BorderLayout.SOUTH);
 
-		DataSet.selListeners.add(new SelectionChangedListener(){
-			public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-				displaylist.clearSelection();
-				for (OsmPrimitive osm : newSelection) {
-					if (conflicts.containsKey(osm)) {
-						int pos = model.indexOf(osm);
-						displaylist.addSelectionInterval(pos, pos);
-					}
-				}
-			}
-		});
-		displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				Main.map.mapView.repaint();
-			}
-		});
-	}
+        DataSet.selListeners.add(new SelectionChangedListener(){
+            public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+                displaylist.clearSelection();
+                for (OsmPrimitive osm : newSelection) {
+                    if (conflicts.containsKey(osm)) {
+                        int pos = model.indexOf(osm);
+                        displaylist.addSelectionInterval(pos, pos);
+                    }
+                }
+            }
+        });
+        displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
+            public void valueChanged(ListSelectionEvent e) {
+                Main.map.mapView.repaint();
+            }
+        });
+    }
 
-	private final void resolve() {
-		if (displaylist.getSelectedIndex() == -1) {
-			JOptionPane.showMessageDialog(Main.parent,tr("Please select something from the conflict list."));
-			return;
-		}
-		Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>();
-		for (int i : displaylist.getSelectedIndices()) {
-			OsmPrimitive s = (OsmPrimitive)model.get(i);
-			sel.put(s, conflicts.get(s));
-		}
-		ConflictResolver resolver = new ConflictResolver(sel);
-		int answer = JOptionPane.showConfirmDialog(Main.parent, resolver, tr("Resolve Conflicts"), JOptionPane.OK_CANCEL_OPTION);
-		if (answer != JOptionPane.OK_OPTION)
-			return;
-		Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel));
-		Main.map.mapView.repaint();
-	}
+    private final void resolve() {
+        if (displaylist.getSelectedIndex() == -1) {
+            JOptionPane.showMessageDialog(Main.parent,tr("Please select something from the conflict list."));
+            return;
+        }
+        Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>();
+        for (int i : displaylist.getSelectedIndices()) {
+            OsmPrimitive s = (OsmPrimitive)model.get(i);
+            sel.put(s, conflicts.get(s));
+        }
+        ConflictResolver resolver = new ConflictResolver(sel);
+        int answer = JOptionPane.showConfirmDialog(Main.parent, resolver, tr("Resolve Conflicts"), JOptionPane.OK_CANCEL_OPTION);
+        if (answer != JOptionPane.OK_OPTION)
+            return;
+        Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel));
+        Main.map.mapView.repaint();
+    }
 
-	public final void rebuildList() {
-		model.removeAllElements();
-		for (OsmPrimitive osm : this.conflicts.keySet())
-			if (osm instanceof Node)
-				model.addElement(osm);
-		for (OsmPrimitive osm : this.conflicts.keySet())
-			if (osm instanceof Way)
-				model.addElement(osm);
+    public final void rebuildList() {
+        model.removeAllElements();
+        for (OsmPrimitive osm : this.conflicts.keySet())
+            if (osm instanceof Node)
+                model.addElement(osm);
+        for (OsmPrimitive osm : this.conflicts.keySet())
+            if (osm instanceof Way)
+                model.addElement(osm);
         for (OsmPrimitive osm : this.conflicts.keySet())
             if (osm instanceof Relation)
@@ -132,45 +132,45 @@
     }
 
-	public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) {
-		this.conflicts.putAll(conflicts);
-		rebuildList();
-	}
+    public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) {
+        this.conflicts.putAll(conflicts);
+        rebuildList();
+    }
 
-	/**
-	 * Paint all conflicts that can be expressed on the main window.
-	 */
-	public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
-		Color preferencesColor = Main.pref.getColor("conflict", Color.gray);
-		if (preferencesColor.equals(Color.BLACK))
-			return;
-		g.setColor(preferencesColor);
-		Visitor conflictPainter = new Visitor(){
-			public void visit(Node n) {
-				Point p = nc.getPoint(n.eastNorth);
-				g.drawRect(p.x-1, p.y-1, 2, 2);
-			}
-			public void visit(Node n1, Node n2) {
-				Point p1 = nc.getPoint(n1.eastNorth);
-				Point p2 = nc.getPoint(n2.eastNorth);
-				g.drawLine(p1.x, p1.y, p2.x, p2.y);
-			}
-			public void visit(Way w) {
-				Node lastN = null;
-				for (Node n : w.nodes) {
-					if (lastN == null) {
-						lastN = n;
-						continue;
-					}
-					visit(lastN, n);
-					lastN = n;
-				}
-			}
-			public void visit(Relation e) {
-				for (RelationMember em : e.members)
-					em.member.visit(this);
-			}
-		};
-		for (Object o : displaylist.getSelectedValues())
-			conflicts.get(o).visit(conflictPainter);
-	}
+    /**
+     * Paint all conflicts that can be expressed on the main window.
+     */
+    public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
+        Color preferencesColor = Main.pref.getColor("conflict", Color.gray);
+        if (preferencesColor.equals(Color.BLACK))
+            return;
+        g.setColor(preferencesColor);
+        Visitor conflictPainter = new Visitor(){
+            public void visit(Node n) {
+                Point p = nc.getPoint(n.eastNorth);
+                g.drawRect(p.x-1, p.y-1, 2, 2);
+            }
+            public void visit(Node n1, Node n2) {
+                Point p1 = nc.getPoint(n1.eastNorth);
+                Point p2 = nc.getPoint(n2.eastNorth);
+                g.drawLine(p1.x, p1.y, p2.x, p2.y);
+            }
+            public void visit(Way w) {
+                Node lastN = null;
+                for (Node n : w.nodes) {
+                    if (lastN == null) {
+                        lastN = n;
+                        continue;
+                    }
+                    visit(lastN, n);
+                    lastN = n;
+                }
+            }
+            public void visit(Relation e) {
+                for (RelationMember em : e.members)
+                    em.member.visit(this);
+            }
+        };
+        for (Object o : displaylist.getSelectedValues())
+            conflicts.get(o).visit(conflictPainter);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 1169)
@@ -54,129 +54,129 @@
 public class HistoryDialog extends ToggleDialog implements SelectionChangedListener {
 
-	public static final Date unifyDate(Date d) {
-		Calendar c = Calendar.getInstance();
-		c.setTime(d);
-		c.set(Calendar.MINUTE, 0);
-		c.set(Calendar.SECOND, 0);
-		return c.getTime();
-	}
+    public static final Date unifyDate(Date d) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(d);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        return c.getTime();
+    }
 
-	private static class HistoryItem implements Comparable<HistoryItem> {
-		OsmPrimitive osm;
-		boolean visible;
+    private static class HistoryItem implements Comparable<HistoryItem> {
+        OsmPrimitive osm;
+        boolean visible;
 
-		public int compareTo(HistoryItem o) {
-			return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp()));
-		}
-	}
+        public int compareTo(HistoryItem o) {
+            return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp()));
+        }
+    }
 
-	private final DefaultTableModel data = new DefaultTableModel(){
-		@Override public boolean isCellEditable(int row, int column) {
-			return false;
-		}
-	};
+    private final DefaultTableModel data = new DefaultTableModel(){
+        @Override public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+    };
 
-	/**
-	 * Main table. 3 columns:
-	 * Object | Date | visible (icon, no text)
-	 */
-	private JTable history = new JTable(data);
-	private JScrollPane historyPane = new JScrollPane(history);
+    /**
+     * Main table. 3 columns:
+     * Object | Date | visible (icon, no text)
+     */
+    private JTable history = new JTable(data);
+    private JScrollPane historyPane = new JScrollPane(history);
 
-	private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>();
-	private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>");
+    private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>();
+    private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>");
 
-	public HistoryDialog() {
-		super(tr("History"), "history", tr("Display the history of all selected items."),
-		Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H,
-		Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
-		historyPane.setVisible(false);
-		notLoaded.setVisible(true);
-		notLoaded.setHorizontalAlignment(JLabel.CENTER);
+    public HistoryDialog() {
+        super(tr("History"), "history", tr("Display the history of all selected items."),
+        Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H,
+        Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
+        historyPane.setVisible(false);
+        notLoaded.setVisible(true);
+        notLoaded.setHorizontalAlignment(JLabel.CENTER);
 
-		history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-			}
-		});
-		data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""});
-		history.getColumnModel().getColumn(0).setPreferredWidth(200);
-		history.getColumnModel().getColumn(1).setPreferredWidth(200);
-		history.getColumnModel().getColumn(2).setPreferredWidth(20);
-		final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer();
-		history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-				if (!value.equals(""))
-					return c;
-				JLabel l = new JLabel(ImageProvider.get("misc","showhide"));
-				l.setForeground(c.getForeground());
-				l.setBackground(c.getBackground());
-				l.setFont(c.getFont());
-				l.setBorder(c.getBorder());
-				l.setOpaque(true);
-				return l;
-			}
-		});
+        history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+            }
+        });
+        data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""});
+        history.getColumnModel().getColumn(0).setPreferredWidth(200);
+        history.getColumnModel().getColumn(1).setPreferredWidth(200);
+        history.getColumnModel().getColumn(2).setPreferredWidth(20);
+        final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer();
+        history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+                if (!value.equals(""))
+                    return c;
+                JLabel l = new JLabel(ImageProvider.get("misc","showhide"));
+                l.setForeground(c.getForeground());
+                l.setBackground(c.getBackground());
+                l.setFont(c.getFont());
+                l.setBorder(c.getBorder());
+                l.setOpaque(true);
+                return l;
+            }
+        });
 
-		JPanel centerPanel = new JPanel(new GridBagLayout());
-		centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH));
-		centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH));
-		add(centerPanel, BorderLayout.CENTER);
+        JPanel centerPanel = new JPanel(new GridBagLayout());
+        centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH));
+        centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH));
+        add(centerPanel, BorderLayout.CENTER);
 
-		JPanel buttons = new JPanel(new GridLayout(1,2));
-		buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."),
-		new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				reload();
-			}
-		}));
-		buttons.add(new SideButton(marktr("Revert"), "revert", "History",
-		tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
-			}
-		}));
-		add(buttons, BorderLayout.SOUTH);
+        JPanel buttons = new JPanel(new GridLayout(1,2));
+        buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."),
+        new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                reload();
+            }
+        }));
+        buttons.add(new SideButton(marktr("Revert"), "revert", "History",
+        tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
+            }
+        }));
+        add(buttons, BorderLayout.SOUTH);
 
-		DataSet.selListeners.add(this);
-	}
+        DataSet.selListeners.add(this);
+    }
 
 
-	@Override public void setVisible(boolean b) {
-		super.setVisible(b);
-		if (b)
-			update();
-	}
+    @Override public void setVisible(boolean b) {
+        super.setVisible(b);
+        if (b)
+            update();
+    }
 
 
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		if (isVisible())
-			update();
-	}
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        if (isVisible())
+            update();
+    }
 
-	/**
-	 * Identify all new objects in the selection and if any, hide the list.
-	 * Else, update the list with the selected items shown.
-	 */
-	private void update() {
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		if (!cache.keySet().containsAll(sel)) {
-			historyPane.setVisible(false);
-			notLoaded.setVisible(true);
-		} else {
-			SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>();
-			for (OsmPrimitive osm : sel)
-				orderedHistory.addAll(cache.get(osm));
-			data.setRowCount(0);
-			for (HistoryItem i : orderedHistory)
-				data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible});
-			historyPane.setVisible(true);
-			notLoaded.setVisible(false);
-		}
-	}
+    /**
+     * Identify all new objects in the selection and if any, hide the list.
+     * Else, update the list with the selected items shown.
+     */
+    private void update() {
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        if (!cache.keySet().containsAll(sel)) {
+            historyPane.setVisible(false);
+            notLoaded.setVisible(true);
+        } else {
+            SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>();
+            for (OsmPrimitive osm : sel)
+                orderedHistory.addAll(cache.get(osm));
+            data.setRowCount(0);
+            for (HistoryItem i : orderedHistory)
+                data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible});
+            historyPane.setVisible(true);
+            notLoaded.setVisible(false);
+        }
+    }
 
-	void reload() {
-		JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
-	}
+    void reload() {
+        JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 1169)
@@ -50,270 +50,270 @@
 public class LayerListDialog extends ToggleDialog implements LayerChangeListener {
 
-	/**
-	 * The last layerlist created. Used to update the list in the Show/Hide and Delete actions.
-	 * TODO: Replace with Listener-Pattern.
-	 */
-	static JList instance;
-	private JScrollPane listScrollPane;
-
-	public final static class DeleteLayerAction extends AbstractAction {
-
-		private final Layer layer;
-
-		public DeleteLayerAction(Layer layer) {
-			super(tr("Delete"), ImageProvider.get("dialogs", "delete"));
-			putValue(SHORT_DESCRIPTION, tr("Delete the selected layer."));
-			putValue("help", "Action/LayerDelete");
-			this.layer = layer;
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			int sel = instance.getSelectedIndex();
-			Layer l = layer != null ? layer : (Layer)instance.getSelectedValue();
-			if(l == null)
-				return;
-			if (l instanceof OsmDataLayer)
-			{
-				if (((OsmDataLayer)l).isModified())
-				{
-					if(JOptionPane.showConfirmDialog(instance, tr("There are unsaved changes. Delete the layer anwyay?"),
-					tr("Unsaved Changes"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
-						return;
-				}
-				else if(!DontShowAgainInfo.show("delete_layer", tr("Do you really want to delete the whole layer?"), false))
-					return;
-			}
-			Main.main.removeLayer(l);
-			if (sel >= instance.getModel().getSize())
-				sel = instance.getModel().getSize()-1;
-			if (instance.getSelectedValue() == null)
-				instance.setSelectedIndex(sel);
-			if (Main.map != null)
-				Main.map.mapView.setActiveLayer((Layer)instance.getSelectedValue());
-		}
-	}
-
-	public final static class ShowHideLayerAction extends AbstractAction {
-		private final Layer layer;
-
-		public ShowHideLayerAction(Layer layer) {
-			super(tr("Show/Hide"), ImageProvider.get("dialogs", "showhide"));
-			putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer."));
-			putValue("help", "Action/LayerShowHide");
-			this.layer = layer;
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
-			if(l == null)
-				return;
-			l.visible = !l.visible;
-			Main.map.mapView.repaint();
-			instance.repaint();
-		}
-	}
-
-	public final static class ShowHideMarkerText extends AbstractAction {
-		private final Layer layer;
-
-		public ShowHideMarkerText(Layer layer) {
-			super(tr("Show/Hide Text/Icons"), ImageProvider.get("dialogs", "showhide"));
-			putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the marker text and icons."));
-			putValue("help", "Action/ShowHideTextIcons");
-			this.layer = layer;
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
-			String current = Main.pref.get("marker.show "+l.name,"show");
-			Main.pref.put("marker.show "+l.name, current.equalsIgnoreCase("show") ? "hide" : "show");
-			Main.map.mapView.repaint();
-			instance.repaint();
-		}
-	}
-
-	/**
-	 * The data model for the list component.
-	 */
-	DefaultListModel model = new DefaultListModel();
-	/**
-	 * The merge action. This is only called, if the current selection and its
-	 * item below are editable datasets and the merge button is clicked.
-	 */
-	private final SideButton mergeButton;
-	/**
-	 * Button for moving layer up.
-	 */
-	private final SideButton upButton;
-	/**
-	 * Button for moving layer down.
-	 */
-	private final SideButton downButton;
-	/**
-	 * Button for delete layer.
-	 */
-	private Action deleteAction = new DeleteLayerAction(null);
-
-	/**
-	 * Create an layerlist and attach it to the given mapView.
-	 */
-	public LayerListDialog(MapFrame mapFrame) {
-		super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
-		Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100);
-		instance = new JList(model);
-		listScrollPane = new JScrollPane(instance);
-		add(listScrollPane, BorderLayout.CENTER);
-		instance.setBackground(UIManager.getColor("Button.background"));
-		instance.setCellRenderer(new DefaultListCellRenderer(){
-			@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-				Layer layer = (Layer)value;
-				JLabel label = (JLabel)super.getListCellRendererComponent(list,
-						layer.name, index, isSelected, cellHasFocus);
-				Icon icon = layer.getIcon();
-				if (!layer.visible)
-					icon = ImageProvider.overlay(icon, "overlay/invisible", OverlayPosition.SOUTHEAST);
-				label.setIcon(icon);
-				label.setToolTipText(layer.getToolTipText());
-				return label;
-			}
-		});
-
-		final MapView mapView = mapFrame.mapView;
-
-		Collection<Layer> data = mapView.getAllLayers();
-		for (Layer l : data)
-			model.addElement(l);
-
-		instance.setSelectedValue(mapView.getActiveLayer(), true);
-		instance.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		instance.addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				if (instance.getModel().getSize() == 0)
-					return;
-				if (instance.getSelectedIndex() == -1)
-					instance.setSelectedIndex(e.getFirstIndex());
-				mapView.setActiveLayer((Layer)instance.getSelectedValue());
-			}
-		});
-		Layer.listeners.add(this);
-
-		instance.addMouseListener(new MouseAdapter(){
-			private void openPopup(MouseEvent e) {
-				Point p = listScrollPane.getMousePosition();
-				if (p == null)
-					return; // user is faster than swing with mouse movement
-				int index = instance.locationToIndex(e.getPoint());
-				Layer layer = (Layer)instance.getModel().getElementAt(index);
-				LayerListPopup menu = new LayerListPopup(instance, layer);
-				menu.show(listScrollPane, p.x, p.y-3);
-			}
-			@Override public void mousePressed(MouseEvent e) {
-				if (e.isPopupTrigger())
-					openPopup(e);
-			}
-			@Override public void mouseReleased(MouseEvent e) {
-				if (e.isPopupTrigger())
-					openPopup(e);
-			}
-			@Override public void mouseClicked(MouseEvent e) {
-				if (e.getClickCount() == 2) {
-					int index = instance.locationToIndex(e.getPoint());
-					Layer layer = (Layer)instance.getModel().getElementAt(index);
-					String current = Main.pref.get("marker.show "+layer.name,"show");
-					Main.pref.put("marker.show "+layer.name, current.equalsIgnoreCase("show") ? "hide" : "show");
-					layer.visible = !layer.visible;
-					Main.map.mapView.repaint();
-					instance.repaint();
-				}
-			}
-		});
-
-
-		// Buttons
-		JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
-
-		ActionListener upDown = new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Layer l = (Layer)instance.getSelectedValue();
-				int sel = instance.getSelectedIndex();
-				int selDest = e.getActionCommand().equals("up") ? sel-1 : sel+1;
-				mapView.moveLayer(l, selDest);
-				model.set(sel, model.get(selDest));
-				model.set(selDest, l);
-				instance.setSelectedIndex(selDest);
-				updateButtonEnabled();
-				mapView.repaint();
-			}
-		};
-
-		upButton = new SideButton("up", "LayerList", tr("Move the selected layer one row up."), upDown);
-		buttonPanel.add(upButton);
-
- 		downButton = new SideButton("down", "LayerList", tr("Move the selected layer one row down."), upDown);
-		buttonPanel.add(downButton);
-
-		buttonPanel.add(new SideButton(new ShowHideLayerAction(null)));
-		buttonPanel.add(new SideButton(deleteAction));
-
-		mergeButton = new SideButton("Merge", "mergedown", "LayerList", tr("Merge the layer directly below into the selected layer."),
-		new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Layer lTo = (Layer)instance.getSelectedValue();
-				Layer lFrom = (Layer)model.get(instance.getSelectedIndex()+1);
-				lTo.mergeFrom(lFrom);
-				mapView.removeLayer(lFrom);
-				updateButtonEnabled();
-				mapView.repaint();
-			}
-		});
-		mergeButton.setText(null);
-		buttonPanel.add(mergeButton);
-
-		add(buttonPanel, BorderLayout.SOUTH);
-
-		updateButtonEnabled();
-	}
-
-	/**
-	 * Updates the state of the Buttons.
-	 */
-	void updateButtonEnabled() {
-		int sel = instance.getSelectedIndex();
-		Layer l = (Layer)instance.getSelectedValue();
-		boolean enable = model.getSize() > 1;
-		enable = enable && sel < model.getSize()-1;
-		enable = enable && ((Layer)model.get(sel+1)).isMergable(l);
-		mergeButton.setEnabled(enable);
-		upButton.setEnabled(sel > 0);
-		downButton.setEnabled(sel >= 0 && sel < model.getSize()-1);
-		deleteAction.setEnabled(!model.isEmpty());
-	}
-
-	/**
-	 * Add the new layer to the list.
-	 */
-	public void layerAdded(Layer newLayer) {
-		model.add(model.size(), newLayer);
-		updateButtonEnabled();
-	}
-
-	public void layerRemoved(Layer oldLayer) {
-		model.removeElement(oldLayer);
-		if (model.isEmpty()) {
-			Layer.listeners.remove(this);
-			return;
-		}
-		if (instance.getSelectedIndex() == -1)
-			instance.setSelectedIndex(0);
-		updateButtonEnabled();
-	}
-
-	/**
-	 * If the newLayer is not the actual selection, select it.
-	 */
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-		if (newLayer != instance.getSelectedValue())
-			instance.setSelectedValue(newLayer, true);
-		updateButtonEnabled();
-	}
+    /**
+     * The last layerlist created. Used to update the list in the Show/Hide and Delete actions.
+     * TODO: Replace with Listener-Pattern.
+     */
+    static JList instance;
+    private JScrollPane listScrollPane;
+
+    public final static class DeleteLayerAction extends AbstractAction {
+
+        private final Layer layer;
+
+        public DeleteLayerAction(Layer layer) {
+            super(tr("Delete"), ImageProvider.get("dialogs", "delete"));
+            putValue(SHORT_DESCRIPTION, tr("Delete the selected layer."));
+            putValue("help", "Action/LayerDelete");
+            this.layer = layer;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            int sel = instance.getSelectedIndex();
+            Layer l = layer != null ? layer : (Layer)instance.getSelectedValue();
+            if(l == null)
+                return;
+            if (l instanceof OsmDataLayer)
+            {
+                if (((OsmDataLayer)l).isModified())
+                {
+                    if(JOptionPane.showConfirmDialog(instance, tr("There are unsaved changes. Delete the layer anwyay?"),
+                    tr("Unsaved Changes"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+                        return;
+                }
+                else if(!DontShowAgainInfo.show("delete_layer", tr("Do you really want to delete the whole layer?"), false))
+                    return;
+            }
+            Main.main.removeLayer(l);
+            if (sel >= instance.getModel().getSize())
+                sel = instance.getModel().getSize()-1;
+            if (instance.getSelectedValue() == null)
+                instance.setSelectedIndex(sel);
+            if (Main.map != null)
+                Main.map.mapView.setActiveLayer((Layer)instance.getSelectedValue());
+        }
+    }
+
+    public final static class ShowHideLayerAction extends AbstractAction {
+        private final Layer layer;
+
+        public ShowHideLayerAction(Layer layer) {
+            super(tr("Show/Hide"), ImageProvider.get("dialogs", "showhide"));
+            putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer."));
+            putValue("help", "Action/LayerShowHide");
+            this.layer = layer;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
+            if(l == null)
+                return;
+            l.visible = !l.visible;
+            Main.map.mapView.repaint();
+            instance.repaint();
+        }
+    }
+
+    public final static class ShowHideMarkerText extends AbstractAction {
+        private final Layer layer;
+
+        public ShowHideMarkerText(Layer layer) {
+            super(tr("Show/Hide Text/Icons"), ImageProvider.get("dialogs", "showhide"));
+            putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the marker text and icons."));
+            putValue("help", "Action/ShowHideTextIcons");
+            this.layer = layer;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            Layer l = layer == null ? (Layer)instance.getSelectedValue() : layer;
+            String current = Main.pref.get("marker.show "+l.name,"show");
+            Main.pref.put("marker.show "+l.name, current.equalsIgnoreCase("show") ? "hide" : "show");
+            Main.map.mapView.repaint();
+            instance.repaint();
+        }
+    }
+
+    /**
+     * The data model for the list component.
+     */
+    DefaultListModel model = new DefaultListModel();
+    /**
+     * The merge action. This is only called, if the current selection and its
+     * item below are editable datasets and the merge button is clicked.
+     */
+    private final SideButton mergeButton;
+    /**
+     * Button for moving layer up.
+     */
+    private final SideButton upButton;
+    /**
+     * Button for moving layer down.
+     */
+    private final SideButton downButton;
+    /**
+     * Button for delete layer.
+     */
+    private Action deleteAction = new DeleteLayerAction(null);
+
+    /**
+     * Create an layerlist and attach it to the given mapView.
+     */
+    public LayerListDialog(MapFrame mapFrame) {
+        super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
+        Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100);
+        instance = new JList(model);
+        listScrollPane = new JScrollPane(instance);
+        add(listScrollPane, BorderLayout.CENTER);
+        instance.setBackground(UIManager.getColor("Button.background"));
+        instance.setCellRenderer(new DefaultListCellRenderer(){
+            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                Layer layer = (Layer)value;
+                JLabel label = (JLabel)super.getListCellRendererComponent(list,
+                        layer.name, index, isSelected, cellHasFocus);
+                Icon icon = layer.getIcon();
+                if (!layer.visible)
+                    icon = ImageProvider.overlay(icon, "overlay/invisible", OverlayPosition.SOUTHEAST);
+                label.setIcon(icon);
+                label.setToolTipText(layer.getToolTipText());
+                return label;
+            }
+        });
+
+        final MapView mapView = mapFrame.mapView;
+
+        Collection<Layer> data = mapView.getAllLayers();
+        for (Layer l : data)
+            model.addElement(l);
+
+        instance.setSelectedValue(mapView.getActiveLayer(), true);
+        instance.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        instance.addListSelectionListener(new ListSelectionListener(){
+            public void valueChanged(ListSelectionEvent e) {
+                if (instance.getModel().getSize() == 0)
+                    return;
+                if (instance.getSelectedIndex() == -1)
+                    instance.setSelectedIndex(e.getFirstIndex());
+                mapView.setActiveLayer((Layer)instance.getSelectedValue());
+            }
+        });
+        Layer.listeners.add(this);
+
+        instance.addMouseListener(new MouseAdapter(){
+            private void openPopup(MouseEvent e) {
+                Point p = listScrollPane.getMousePosition();
+                if (p == null)
+                    return; // user is faster than swing with mouse movement
+                int index = instance.locationToIndex(e.getPoint());
+                Layer layer = (Layer)instance.getModel().getElementAt(index);
+                LayerListPopup menu = new LayerListPopup(instance, layer);
+                menu.show(listScrollPane, p.x, p.y-3);
+            }
+            @Override public void mousePressed(MouseEvent e) {
+                if (e.isPopupTrigger())
+                    openPopup(e);
+            }
+            @Override public void mouseReleased(MouseEvent e) {
+                if (e.isPopupTrigger())
+                    openPopup(e);
+            }
+            @Override public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    int index = instance.locationToIndex(e.getPoint());
+                    Layer layer = (Layer)instance.getModel().getElementAt(index);
+                    String current = Main.pref.get("marker.show "+layer.name,"show");
+                    Main.pref.put("marker.show "+layer.name, current.equalsIgnoreCase("show") ? "hide" : "show");
+                    layer.visible = !layer.visible;
+                    Main.map.mapView.repaint();
+                    instance.repaint();
+                }
+            }
+        });
+
+
+        // Buttons
+        JPanel buttonPanel = new JPanel(new GridLayout(1, 5));
+
+        ActionListener upDown = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                Layer l = (Layer)instance.getSelectedValue();
+                int sel = instance.getSelectedIndex();
+                int selDest = e.getActionCommand().equals("up") ? sel-1 : sel+1;
+                mapView.moveLayer(l, selDest);
+                model.set(sel, model.get(selDest));
+                model.set(selDest, l);
+                instance.setSelectedIndex(selDest);
+                updateButtonEnabled();
+                mapView.repaint();
+            }
+        };
+
+        upButton = new SideButton("up", "LayerList", tr("Move the selected layer one row up."), upDown);
+        buttonPanel.add(upButton);
+
+        downButton = new SideButton("down", "LayerList", tr("Move the selected layer one row down."), upDown);
+        buttonPanel.add(downButton);
+
+        buttonPanel.add(new SideButton(new ShowHideLayerAction(null)));
+        buttonPanel.add(new SideButton(deleteAction));
+
+        mergeButton = new SideButton("Merge", "mergedown", "LayerList", tr("Merge the layer directly below into the selected layer."),
+        new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                Layer lTo = (Layer)instance.getSelectedValue();
+                Layer lFrom = (Layer)model.get(instance.getSelectedIndex()+1);
+                lTo.mergeFrom(lFrom);
+                mapView.removeLayer(lFrom);
+                updateButtonEnabled();
+                mapView.repaint();
+            }
+        });
+        mergeButton.setText(null);
+        buttonPanel.add(mergeButton);
+
+        add(buttonPanel, BorderLayout.SOUTH);
+
+        updateButtonEnabled();
+    }
+
+    /**
+     * Updates the state of the Buttons.
+     */
+    void updateButtonEnabled() {
+        int sel = instance.getSelectedIndex();
+        Layer l = (Layer)instance.getSelectedValue();
+        boolean enable = model.getSize() > 1;
+        enable = enable && sel < model.getSize()-1;
+        enable = enable && ((Layer)model.get(sel+1)).isMergable(l);
+        mergeButton.setEnabled(enable);
+        upButton.setEnabled(sel > 0);
+        downButton.setEnabled(sel >= 0 && sel < model.getSize()-1);
+        deleteAction.setEnabled(!model.isEmpty());
+    }
+
+    /**
+     * Add the new layer to the list.
+     */
+    public void layerAdded(Layer newLayer) {
+        model.add(model.size(), newLayer);
+        updateButtonEnabled();
+    }
+
+    public void layerRemoved(Layer oldLayer) {
+        model.removeElement(oldLayer);
+        if (model.isEmpty()) {
+            Layer.listeners.remove(this);
+            return;
+        }
+        if (instance.getSelectedIndex() == -1)
+            instance.setSelectedIndex(0);
+        updateButtonEnabled();
+    }
+
+    /**
+     * If the newLayer is not the actual selection, select it.
+     */
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        if (newLayer != instance.getSelectedValue())
+            instance.setSelectedValue(newLayer, true);
+        updateButtonEnabled();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 1169)
@@ -21,18 +21,18 @@
 public class LayerListPopup extends JPopupMenu {
 
-	public final static class InfoAction extends AbstractAction {
-	    private final Layer layer;
-	    public InfoAction(Layer layer) {
-	    	super(tr("Info"), ImageProvider.get("info"));
-		    this.layer = layer;
-	    }
-	    public void actionPerformed(ActionEvent e) {
-	    	JOptionPane.showMessageDialog(Main.parent, layer.getInfoComponent());
-	    }
+    public final static class InfoAction extends AbstractAction {
+        private final Layer layer;
+        public InfoAction(Layer layer) {
+            super(tr("Info"), ImageProvider.get("info"));
+            this.layer = layer;
+        }
+        public void actionPerformed(ActionEvent e) {
+            JOptionPane.showMessageDialog(Main.parent, layer.getInfoComponent());
+        }
     }
 
-	public LayerListPopup(final JList layers, final Layer layer) {
-		for (Component c : layer.getMenuEntries())
-			add(c);
-	}
+    public LayerListPopup(final JList layers, final Layer layer) {
+        for (Component c : layer.getMenuEntries())
+            add(c);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 1169)
@@ -85,138 +85,138 @@
 public class PropertiesDialog extends ToggleDialog implements SelectionChangedListener {
 
-	/**
-	 * Used to display relation names in the membership table
-	 */
-	private NameVisitor nameVisitor = new NameVisitor();
-
-	/**
-	 * Watches for double clicks and from editing or new property, depending on the
-	 * location, the click was.
-	 * @author imi
-	 */
-	public class DblClickWatch extends MouseAdapter {
-		@Override public void mouseClicked(MouseEvent e) {
-			if (e.getClickCount() < 2)
-			{
-				if (e.getSource() == propertyTable)
-					membershipTable.clearSelection();
-				else if (e.getSource() == membershipTable)
-					propertyTable.clearSelection();
-			}
-			else if (e.getSource() == propertyTable)
-			{
-				int row = propertyTable.rowAtPoint(e.getPoint());
-				if (row > -1)
-					propertyEdit(row);
-			} else if (e.getSource() == membershipTable) {
-				int row = membershipTable.rowAtPoint(e.getPoint());
-				if (row > -1)
-					membershipEdit(row);
-			}
-			else
-			{
-				add();
-			}
-		}
-	}
-
-	private final Map<String, Map<String, Integer>> valueCount = new TreeMap<String, Map<String, Integer>>();
-	/**
-	 * Edit the value in the properties table row
-	 * @param row The row of the table from which the value is edited.
-	 */
-	void propertyEdit(int row) {
-		String key = propertyData.getValueAt(row, 0).toString();
-		objKey=key;
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		if (sel.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select the objects you want to change properties for."));
-			return;
-		}
-		String msg = "<html>"+trn("This will change up to {0} object.", "This will change up to {0} objects.", sel.size(), sel.size())+"<br><br>("+tr("An empty value deletes the key.", key)+")</html>";
-
-		JPanel panel = new JPanel(new BorderLayout());
-		panel.add(new JLabel(msg), BorderLayout.NORTH);
-
-		final TreeMap<String, TreeSet<String>> allData = createAutoCompletionInfo(true);
-
-		JPanel p = new JPanel(new GridBagLayout());
-		panel.add(p, BorderLayout.CENTER);
-
-		final AutoCompleteComboBox keys = new AutoCompleteComboBox();
-		keys.setPossibleItems(allData.keySet());
-		keys.setEditable(true);
-		keys.setSelectedItem(key);
-
-		p.add(new JLabel(tr("Key")), GBC.std());
-		p.add(Box.createHorizontalStrut(10), GBC.std());
-		p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
-
-		final AutoCompleteComboBox values = new AutoCompleteComboBox();
-		values.setRenderer(new DefaultListCellRenderer() {
-			@Override public Component getListCellRendererComponent(JList list,  Object value, int index, boolean isSelected,  boolean cellHasFocus) {
-			    Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-			    if (c instanceof JLabel) {
-			    	String str = null;
-			    		str=(String) value;
-			    		if (valueCount.containsKey(objKey)){
-			    			Map<String, Integer> m=valueCount.get(objKey);
-			    			if (m.containsKey(str)) {
-			    				str+="("+m.get(str)+")";
-			    				c.setFont(c.getFont().deriveFont(Font.ITALIC+Font.BOLD));
-			    			}
-			    		}
-				    ((JLabel)c).setText(str);
-			    }
-			    return c;
-			}
-		});
-		values.setEditable(true);
-		updateListData(key, allData, values);
-		Map<String, Integer> m=(Map<String, Integer>)propertyData.getValueAt(row, 1);
-		final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
-		values.setSelectedItem(selection);
-		values.getEditor().setItem(selection);
-		p.add(new JLabel(tr("Value")), GBC.std());
-		p.add(Box.createHorizontalStrut(10), GBC.std());
-		p.add(values, GBC.eol().fill(GBC.HORIZONTAL));
-		addFocusAdapter(row, allData, keys, values);
-
-		final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
-			@Override public void selectInitialValue() {
-				values.requestFocusInWindow();
-				values.getEditor().selectAll();
-			}
-		};
-		final JDialog dlg = optionPane.createDialog(Main.parent, tr("Change values?"));
-
-		values.getEditor().addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				dlg.setVisible(false);
-				optionPane.setValue(JOptionPane.OK_OPTION);
-			}
-		});
-
-		String oldValue = values.getEditor().getItem().toString();
-		dlg.setVisible(true);
-
-		Object answer = optionPane.getValue();
-		if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
-				(answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
-			values.getEditor().setItem(oldValue);
-			return;
-		}
-
-		String value = values.getEditor().getItem().toString();
-		// is not Java 1.5
-		//value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
-		if (value.equals(""))
-			value = null; // delete the key
-		String newkey = keys.getEditor().getItem().toString();
-		//newkey = java.text.Normalizer.normalize(newkey, java.text.Normalizer.Form.NFC);
-		if (newkey.equals("")) {
-			newkey = key;
-			value = null; // delete the key instead
-		}
+    /**
+     * Used to display relation names in the membership table
+     */
+    private NameVisitor nameVisitor = new NameVisitor();
+
+    /**
+     * Watches for double clicks and from editing or new property, depending on the
+     * location, the click was.
+     * @author imi
+     */
+    public class DblClickWatch extends MouseAdapter {
+        @Override public void mouseClicked(MouseEvent e) {
+            if (e.getClickCount() < 2)
+            {
+                if (e.getSource() == propertyTable)
+                    membershipTable.clearSelection();
+                else if (e.getSource() == membershipTable)
+                    propertyTable.clearSelection();
+            }
+            else if (e.getSource() == propertyTable)
+            {
+                int row = propertyTable.rowAtPoint(e.getPoint());
+                if (row > -1)
+                    propertyEdit(row);
+            } else if (e.getSource() == membershipTable) {
+                int row = membershipTable.rowAtPoint(e.getPoint());
+                if (row > -1)
+                    membershipEdit(row);
+            }
+            else
+            {
+                add();
+            }
+        }
+    }
+
+    private final Map<String, Map<String, Integer>> valueCount = new TreeMap<String, Map<String, Integer>>();
+    /**
+     * Edit the value in the properties table row
+     * @param row The row of the table from which the value is edited.
+     */
+    void propertyEdit(int row) {
+        String key = propertyData.getValueAt(row, 0).toString();
+        objKey=key;
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        if (sel.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Please select the objects you want to change properties for."));
+            return;
+        }
+        String msg = "<html>"+trn("This will change up to {0} object.", "This will change up to {0} objects.", sel.size(), sel.size())+"<br><br>("+tr("An empty value deletes the key.", key)+")</html>";
+
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(new JLabel(msg), BorderLayout.NORTH);
+
+        final TreeMap<String, TreeSet<String>> allData = createAutoCompletionInfo(true);
+
+        JPanel p = new JPanel(new GridBagLayout());
+        panel.add(p, BorderLayout.CENTER);
+
+        final AutoCompleteComboBox keys = new AutoCompleteComboBox();
+        keys.setPossibleItems(allData.keySet());
+        keys.setEditable(true);
+        keys.setSelectedItem(key);
+
+        p.add(new JLabel(tr("Key")), GBC.std());
+        p.add(Box.createHorizontalStrut(10), GBC.std());
+        p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
+
+        final AutoCompleteComboBox values = new AutoCompleteComboBox();
+        values.setRenderer(new DefaultListCellRenderer() {
+            @Override public Component getListCellRendererComponent(JList list,  Object value, int index, boolean isSelected,  boolean cellHasFocus) {
+                Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+                if (c instanceof JLabel) {
+                    String str = null;
+                        str=(String) value;
+                        if (valueCount.containsKey(objKey)){
+                            Map<String, Integer> m=valueCount.get(objKey);
+                            if (m.containsKey(str)) {
+                                str+="("+m.get(str)+")";
+                                c.setFont(c.getFont().deriveFont(Font.ITALIC+Font.BOLD));
+                            }
+                        }
+                    ((JLabel)c).setText(str);
+                }
+                return c;
+            }
+        });
+        values.setEditable(true);
+        updateListData(key, allData, values);
+        Map<String, Integer> m=(Map<String, Integer>)propertyData.getValueAt(row, 1);
+        final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
+        values.setSelectedItem(selection);
+        values.getEditor().setItem(selection);
+        p.add(new JLabel(tr("Value")), GBC.std());
+        p.add(Box.createHorizontalStrut(10), GBC.std());
+        p.add(values, GBC.eol().fill(GBC.HORIZONTAL));
+        addFocusAdapter(row, allData, keys, values);
+
+        final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
+            @Override public void selectInitialValue() {
+                values.requestFocusInWindow();
+                values.getEditor().selectAll();
+            }
+        };
+        final JDialog dlg = optionPane.createDialog(Main.parent, tr("Change values?"));
+
+        values.getEditor().addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                dlg.setVisible(false);
+                optionPane.setValue(JOptionPane.OK_OPTION);
+            }
+        });
+
+        String oldValue = values.getEditor().getItem().toString();
+        dlg.setVisible(true);
+
+        Object answer = optionPane.getValue();
+        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
+                (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
+            values.getEditor().setItem(oldValue);
+            return;
+        }
+
+        String value = values.getEditor().getItem().toString();
+        // is not Java 1.5
+        //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
+        if (value.equals(""))
+            value = null; // delete the key
+        String newkey = keys.getEditor().getItem().toString();
+        //newkey = java.text.Normalizer.normalize(newkey, java.text.Normalizer.Form.NFC);
+        if (newkey.equals("")) {
+            newkey = key;
+            value = null; // delete the key instead
+        }
         if (newkey.equals("created_by"))
         {
@@ -224,42 +224,42 @@
             return;
         }
-		if (key.equals(newkey) || value == null)
-			Main.main.undoRedo.add(new ChangePropertyCommand(sel, newkey, value));
-		else {
-			Collection<Command> commands=new Vector<Command>();
-			commands.add(new ChangePropertyCommand(sel, key, null));
-			if (value.equals(tr("<different>"))) {
-				HashMap<String, Vector<OsmPrimitive>> map=new HashMap<String, Vector<OsmPrimitive>>();
-				for (OsmPrimitive osm: sel) {
-					if(osm.keys != null)
-					{
-						String val=osm.keys.get(key);
-						if(val != null)
-						{
-							if (map.containsKey(val)) {
-								map.get(val).add(osm);
-							} else {
-								Vector<OsmPrimitive> v = new Vector<OsmPrimitive>();
-								v.add(osm);
-								map.put(val, v);
-							}
-						}
-					}
-				}
-				for (Entry<String, Vector<OsmPrimitive>> e: map.entrySet()) {
-					commands.add(new ChangePropertyCommand(e.getValue(), newkey, e.getKey()));
-				}
-			} else {
-				commands.add(new ChangePropertyCommand(sel, newkey, value));
-			}
-			Main.main.undoRedo.add(new SequenceCommand(trn("Change properties of up to {0} object", "Change properties of up to {0} objects", sel.size(), sel.size()), commands));
-		}
-
-		Main.ds.fireSelectionChanged(sel);
-		selectionChanged(sel); // update whole table
-		Main.parent.repaint(); // repaint all - drawing could have been changed
-	}
-
-	/**
+        if (key.equals(newkey) || value == null)
+            Main.main.undoRedo.add(new ChangePropertyCommand(sel, newkey, value));
+        else {
+            Collection<Command> commands=new Vector<Command>();
+            commands.add(new ChangePropertyCommand(sel, key, null));
+            if (value.equals(tr("<different>"))) {
+                HashMap<String, Vector<OsmPrimitive>> map=new HashMap<String, Vector<OsmPrimitive>>();
+                for (OsmPrimitive osm: sel) {
+                    if(osm.keys != null)
+                    {
+                        String val=osm.keys.get(key);
+                        if(val != null)
+                        {
+                            if (map.containsKey(val)) {
+                                map.get(val).add(osm);
+                            } else {
+                                Vector<OsmPrimitive> v = new Vector<OsmPrimitive>();
+                                v.add(osm);
+                                map.put(val, v);
+                            }
+                        }
+                    }
+                }
+                for (Entry<String, Vector<OsmPrimitive>> e: map.entrySet()) {
+                    commands.add(new ChangePropertyCommand(e.getValue(), newkey, e.getKey()));
+                }
+            } else {
+                commands.add(new ChangePropertyCommand(sel, newkey, value));
+            }
+            Main.main.undoRedo.add(new SequenceCommand(trn("Change properties of up to {0} object", "Change properties of up to {0} objects", sel.size(), sel.size()), commands));
+        }
+
+        Main.ds.fireSelectionChanged(sel);
+        selectionChanged(sel); // update whole table
+        Main.parent.repaint(); // repaint all - drawing could have been changed
+    }
+
+    /**
      * @param key
      * @param allData
@@ -267,432 +267,432 @@
      */
     private void updateListData(String key, final TreeMap<String, TreeSet<String>> allData, final AutoCompleteComboBox values) {
-	    Collection<String> newItems;
-	    if (allData.containsKey(key)) {
-			newItems = allData.get(key);
-		} else {
-			newItems = Collections.emptyList();
-		}
-		values.setPossibleItems(newItems);
-    }
-
-	/**
-	 * This simply fires up an relation editor for the relation shown; everything else
-	 * is the editor's business.
-	 *
-	 * @param row
-	 */
-	void membershipEdit(int row) {
-		final RelationEditor editor = new RelationEditor((Relation)membershipData.getValueAt(row, 0),
-				(Collection<RelationMember>) membershipData.getValueAt(row, 1) );
-		editor.setVisible(true);
-	}
-
-	/**
-	 * Open the add selection dialog and add a new key/value to the table (and
-	 * to the dataset, of course).
-	 */
-	void add() {
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		if (sel.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Please select objects for which you want to change properties."));
-			return;
-		}
-
-		JPanel p = new JPanel(new BorderLayout());
-		p.add(new JLabel("<html>"+trn("This will change up to {0} object.","This will change up to {0} objects.", sel.size(),sel.size())+"<br><br>"+tr("Please select a key")),
-				BorderLayout.NORTH);
-		final TreeMap<String, TreeSet<String>> allData = createAutoCompletionInfo(false);
-		final AutoCompleteComboBox keys = new AutoCompleteComboBox();
-		keys.setPossibleItems(allData.keySet());
-		keys.setEditable(true);
-
-		p.add(keys, BorderLayout.CENTER);
-
-		JPanel p2 = new JPanel(new BorderLayout());
-		p.add(p2, BorderLayout.SOUTH);
-		p2.add(new JLabel(tr("Please select a value")), BorderLayout.NORTH);
-		final AutoCompleteComboBox values = new AutoCompleteComboBox();
-		values.setEditable(true);
-		p2.add(values, BorderLayout.CENTER);
-
-		addFocusAdapter(-1, allData, keys, values);
-		JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
-			@Override public void selectInitialValue() {
-				keys.requestFocusInWindow();
-				keys.getEditor().selectAll();
-			}
-		};
-		pane.createDialog(Main.parent, tr("Change values?")).setVisible(true);
-		if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
-			return;
-		String key = keys.getEditor().getItem().toString();
-		String value = values.getEditor().getItem().toString();
-		if (value.equals(""))
-			return;
+        Collection<String> newItems;
+        if (allData.containsKey(key)) {
+            newItems = allData.get(key);
+        } else {
+            newItems = Collections.emptyList();
+        }
+        values.setPossibleItems(newItems);
+    }
+
+    /**
+     * This simply fires up an relation editor for the relation shown; everything else
+     * is the editor's business.
+     *
+     * @param row
+     */
+    void membershipEdit(int row) {
+        final RelationEditor editor = new RelationEditor((Relation)membershipData.getValueAt(row, 0),
+                (Collection<RelationMember>) membershipData.getValueAt(row, 1) );
+        editor.setVisible(true);
+    }
+
+    /**
+     * Open the add selection dialog and add a new key/value to the table (and
+     * to the dataset, of course).
+     */
+    void add() {
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        if (sel.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Please select objects for which you want to change properties."));
+            return;
+        }
+
+        JPanel p = new JPanel(new BorderLayout());
+        p.add(new JLabel("<html>"+trn("This will change up to {0} object.","This will change up to {0} objects.", sel.size(),sel.size())+"<br><br>"+tr("Please select a key")),
+                BorderLayout.NORTH);
+        final TreeMap<String, TreeSet<String>> allData = createAutoCompletionInfo(false);
+        final AutoCompleteComboBox keys = new AutoCompleteComboBox();
+        keys.setPossibleItems(allData.keySet());
+        keys.setEditable(true);
+
+        p.add(keys, BorderLayout.CENTER);
+
+        JPanel p2 = new JPanel(new BorderLayout());
+        p.add(p2, BorderLayout.SOUTH);
+        p2.add(new JLabel(tr("Please select a value")), BorderLayout.NORTH);
+        final AutoCompleteComboBox values = new AutoCompleteComboBox();
+        values.setEditable(true);
+        p2.add(values, BorderLayout.CENTER);
+
+        addFocusAdapter(-1, allData, keys, values);
+        JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
+            @Override public void selectInitialValue() {
+                keys.requestFocusInWindow();
+                keys.getEditor().selectAll();
+            }
+        };
+        pane.createDialog(Main.parent, tr("Change values?")).setVisible(true);
+        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
+            return;
+        String key = keys.getEditor().getItem().toString();
+        String value = values.getEditor().getItem().toString();
+        if (value.equals(""))
+            return;
         if (key.equals("created_by"))
             return;
-		Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
-		Main.ds.fireSelectionChanged(sel);
-		selectionChanged(sel); // update table
-		Main.parent.repaint(); // repaint all - drawing could have been changed
-	}
-
-	/**
-	 * @param allData
-	 * @param keys
-	 * @param values
-	 */
-	private void addFocusAdapter(final int row, final TreeMap<String, TreeSet<String>> allData,final AutoCompleteComboBox keys, final AutoCompleteComboBox values) {
-		// get the combo box' editor component
-		JTextComponent editor = (JTextComponent)values.getEditor()
-		        .getEditorComponent();
-		// Refresh the values model when focus is gained
-		editor.addFocusListener(new FocusAdapter() {
-			@Override public void focusGained(FocusEvent e) {
-				String key = keys.getEditor().getItem().toString();
-				updateListData(key, allData, values);
-				objKey=key;
-			}
-		});
-	}
-	private String objKey;
-	/**
-	 * @return
-	 */
-	private TreeMap<String, TreeSet<String>> createAutoCompletionInfo(
-	        boolean edit) {
-		final TreeMap<String, TreeSet<String>> allData = new TreeMap<String, TreeSet<String>>();
-		for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
-			for (String key : osm.keySet()) {
-				TreeSet<String> values = null;
-				if (allData.containsKey(key))
-					values = allData.get(key);
-				else {
-					values = new TreeSet<String>();
-					allData.put(key, values);
-				}
-				values.add(osm.get(key));
-			}
-		}
-		if (!edit) {
-			for (int i = 0; i < propertyData.getRowCount(); ++i)
-				allData.remove(propertyData.getValueAt(i, 0));
-		}
-		return allData;
-	}
-
-	/**
-	 * Delete the keys from the given row.
-	 * @param row	The row, which key gets deleted from the dataset.
-	 */
-	private void delete(int row) {
-		String key = propertyData.getValueAt(row, 0).toString();
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, null));
-		Main.ds.fireSelectionChanged(sel);
-		selectionChanged(sel); // update table
-	}
-
-	/**
-	 * The property data.
-	 */
-	private final DefaultTableModel propertyData = new DefaultTableModel() {
-		@Override public boolean isCellEditable(int row, int column) {
-			return false;
-		}
-		@Override public Class<?> getColumnClass(int columnIndex) {
-			return String.class;
-		}
-	};
-
-	/**
-	 * The membership data.
-	 */
-	private final DefaultTableModel membershipData = new DefaultTableModel() {
-		@Override public boolean isCellEditable(int row, int column) {
-			return false;
-		}
-		@Override public Class<?> getColumnClass(int columnIndex) {
-			return String.class;
-		}
-	};
-
-	/**
-	 * The properties list.
-	 */
-	private final JTable propertyTable = new JTable(propertyData);
-	private final JTable membershipTable = new JTable(membershipData);
-
-	public JComboBox taggingPresets = new JComboBox();
-
-
-	/**
-	 * Create a new PropertiesDialog
-	 */
-	public PropertiesDialog(MapFrame mapFrame) {
-		super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."),
-		Shortcut.registerShortcut("subwindow:properties", tr("Toggle: {0}", tr("Properties/Memberships")), KeyEvent.VK_P,
-		Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
-
-		// ---------------------------------------
-		// This drop-down is really deprecated but we offer people a chance to
-		// activate it if they really want. Presets should be used from the
-		// menu.
-		if (TaggingPresetPreference.taggingPresets.size() > 0 &&
-				Main.pref.getBoolean("taggingpreset.in-properties-dialog", false)) {
-			Vector<ActionListener> allPresets = new Vector<ActionListener>();
-			for (final TaggingPreset p : TaggingPresetPreference.taggingPresets)
-				allPresets.add(new ForwardActionListener(this, p));
-
-			TaggingPreset empty = new TaggingPreset();
-			// empty.setName("this drop-down will be removed soon");
-			allPresets.add(0, new ForwardActionListener(this, empty));
-			taggingPresets.setModel(new DefaultComboBoxModel(allPresets));
-			JPanel north = new JPanel(new GridBagLayout());
-			north.add(getComponent(0),GBC.eol().fill(GBC.HORIZONTAL));
-			north.add(taggingPresets,GBC.eol().fill(GBC.HORIZONTAL));
-			add(north, BorderLayout.NORTH);
-		}
-		taggingPresets.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				TaggingPreset preset = ((ForwardActionListener)taggingPresets.getSelectedItem()).preset;
-				preset.actionPerformed(e);
-				taggingPresets.setSelectedItem(null);
-			}
-		});
-		taggingPresets.setRenderer(new TaggingCellRenderer());
-
-		// setting up the properties table
-
-		propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
-		propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
-		propertyTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer(){
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
-				if (c instanceof JLabel) {
-					String str = null;
-					switch (column) {
-					case 0:
-						str = (String) value;
-					break;
-					case 1:
-						Map<String, Integer> v = (Map<String,Integer>) value;
-						if (v.size()!=1) {
-							str=tr("<different>");
-							c.setFont(c.getFont().deriveFont(Font.ITALIC));
-						} else {
-							str=v.entrySet().iterator().next().getKey();
-						}
-					break;
-					}
-					((JLabel)c).setText(str);
-				}
-				return c;
-			}
-		});
-
-		// setting up the membership table
-
-		membershipData.setColumnIdentifiers(new String[]{tr("Member Of"),tr("Role")});
-		membershipTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
-		membershipTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
-				if (c instanceof JLabel) {
-					nameVisitor.visit((Relation)value);
-					((JLabel)c).setText(nameVisitor.name);
-				}
-				return c;
-			}
-		});
-
-		membershipTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
-			@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-				Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
-				if (c instanceof JLabel) {
-					Collection<RelationMember> col = (Collection<RelationMember>) value;
-
-					String text = null;
-					for (RelationMember r : col) {
-						if (text == null) {
-							text = r.role;
-						}
-						else if (!text.equals(r.role)) {
-							text = tr("<different>");
-							break;
-						}
-					}
-
-					((JLabel)c).setText(text);
-				}
-				return c;
-			}
-		});
-
-		// combine both tables and wrap them in a scrollPane
-		JPanel bothTables = new JPanel();
-		bothTables.setLayout(new GridBagLayout());
-		bothTables.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
-		bothTables.add(propertyTable, GBC.eol().fill(GBC.BOTH));
-		bothTables.add(membershipTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
-		bothTables.add(membershipTable, GBC.eol().fill(GBC.BOTH));
-
-		DblClickWatch dblClickWatch = new DblClickWatch();
-		propertyTable.addMouseListener(dblClickWatch);
-		membershipTable.addMouseListener(dblClickWatch);
-		JScrollPane scrollPane = new JScrollPane(bothTables);
-		scrollPane.addMouseListener(dblClickWatch);
-		add(scrollPane, BorderLayout.CENTER);
-
-		JPanel buttonPanel = new JPanel(new GridLayout(1,3));
-		ActionListener buttonAction = new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				int row = membershipTable.getSelectedRow();
-				if (e.getActionCommand().equals("Add"))
-					add();
-				else if(row >= 0)
-				{
-					if (e.getActionCommand().equals("Edit"))
-						membershipEdit(row);
-					else if (e.getActionCommand().equals("Delete")) {
-						Relation cur = (Relation)membershipData.getValueAt(row, 0);
-						NameVisitor n = new NameVisitor();
-						cur.visit(n);
-						if(JOptionPane.showConfirmDialog(Main.parent, tr("Really delete selection from relation {0}?", n.name),
-						tr("Change relation"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_NO_OPTION)
-						{
-							Relation rel = new Relation(cur);
-							Collection<OsmPrimitive> sel = Main.ds.getSelected();
-							for (RelationMember rm : cur.members) {
-								for (OsmPrimitive osm : sel) {
-									if (rm.member == osm)
-									{
-										RelationMember mem = new RelationMember();
-										mem.role = rm.role;
-										mem.member = rm.member;
-										rel.members.remove(mem);
-										break;
-									}
-								}
-							}
-							Main.main.undoRedo.add(new ChangeCommand(cur, rel));
-							Main.ds.fireSelectionChanged(sel);
-							selectionChanged(sel); // update whole table
-						}
-
-					}
-				}
-				else
-				{
-					int sel = propertyTable.getSelectedRow();
-					if (e.getActionCommand().equals("Edit")) {
-						if(propertyTable.getRowCount() == 1)
-							sel = 0;
-						if (sel == -1)
-							JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
-						else
-							propertyEdit(sel);
-					} else if (e.getActionCommand().equals("Delete")) {
-						if (sel == -1)
-							JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."));
-						else
-							delete(sel);
-					}
-				}
-			}
-		};
-
-		Shortcut s = Shortcut.registerShortcut("properties:add", tr("Add Properties"), KeyEvent.VK_B,
-		Shortcut.GROUP_MNEMONIC);
-		buttonPanel.add(new SideButton(marktr("Add"),"add","Properties",
+        Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
+        Main.ds.fireSelectionChanged(sel);
+        selectionChanged(sel); // update table
+        Main.parent.repaint(); // repaint all - drawing could have been changed
+    }
+
+    /**
+     * @param allData
+     * @param keys
+     * @param values
+     */
+    private void addFocusAdapter(final int row, final TreeMap<String, TreeSet<String>> allData,final AutoCompleteComboBox keys, final AutoCompleteComboBox values) {
+        // get the combo box' editor component
+        JTextComponent editor = (JTextComponent)values.getEditor()
+                .getEditorComponent();
+        // Refresh the values model when focus is gained
+        editor.addFocusListener(new FocusAdapter() {
+            @Override public void focusGained(FocusEvent e) {
+                String key = keys.getEditor().getItem().toString();
+                updateListData(key, allData, values);
+                objKey=key;
+            }
+        });
+    }
+    private String objKey;
+    /**
+     * @return
+     */
+    private TreeMap<String, TreeSet<String>> createAutoCompletionInfo(
+            boolean edit) {
+        final TreeMap<String, TreeSet<String>> allData = new TreeMap<String, TreeSet<String>>();
+        for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
+            for (String key : osm.keySet()) {
+                TreeSet<String> values = null;
+                if (allData.containsKey(key))
+                    values = allData.get(key);
+                else {
+                    values = new TreeSet<String>();
+                    allData.put(key, values);
+                }
+                values.add(osm.get(key));
+            }
+        }
+        if (!edit) {
+            for (int i = 0; i < propertyData.getRowCount(); ++i)
+                allData.remove(propertyData.getValueAt(i, 0));
+        }
+        return allData;
+    }
+
+    /**
+     * Delete the keys from the given row.
+     * @param row   The row, which key gets deleted from the dataset.
+     */
+    private void delete(int row) {
+        String key = propertyData.getValueAt(row, 0).toString();
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, null));
+        Main.ds.fireSelectionChanged(sel);
+        selectionChanged(sel); // update table
+    }
+
+    /**
+     * The property data.
+     */
+    private final DefaultTableModel propertyData = new DefaultTableModel() {
+        @Override public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+        @Override public Class<?> getColumnClass(int columnIndex) {
+            return String.class;
+        }
+    };
+
+    /**
+     * The membership data.
+     */
+    private final DefaultTableModel membershipData = new DefaultTableModel() {
+        @Override public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+        @Override public Class<?> getColumnClass(int columnIndex) {
+            return String.class;
+        }
+    };
+
+    /**
+     * The properties list.
+     */
+    private final JTable propertyTable = new JTable(propertyData);
+    private final JTable membershipTable = new JTable(membershipData);
+
+    public JComboBox taggingPresets = new JComboBox();
+
+
+    /**
+     * Create a new PropertiesDialog
+     */
+    public PropertiesDialog(MapFrame mapFrame) {
+        super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."),
+        Shortcut.registerShortcut("subwindow:properties", tr("Toggle: {0}", tr("Properties/Memberships")), KeyEvent.VK_P,
+        Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
+
+        // ---------------------------------------
+        // This drop-down is really deprecated but we offer people a chance to
+        // activate it if they really want. Presets should be used from the
+        // menu.
+        if (TaggingPresetPreference.taggingPresets.size() > 0 &&
+                Main.pref.getBoolean("taggingpreset.in-properties-dialog", false)) {
+            Vector<ActionListener> allPresets = new Vector<ActionListener>();
+            for (final TaggingPreset p : TaggingPresetPreference.taggingPresets)
+                allPresets.add(new ForwardActionListener(this, p));
+
+            TaggingPreset empty = new TaggingPreset();
+            // empty.setName("this drop-down will be removed soon");
+            allPresets.add(0, new ForwardActionListener(this, empty));
+            taggingPresets.setModel(new DefaultComboBoxModel(allPresets));
+            JPanel north = new JPanel(new GridBagLayout());
+            north.add(getComponent(0),GBC.eol().fill(GBC.HORIZONTAL));
+            north.add(taggingPresets,GBC.eol().fill(GBC.HORIZONTAL));
+            add(north, BorderLayout.NORTH);
+        }
+        taggingPresets.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                TaggingPreset preset = ((ForwardActionListener)taggingPresets.getSelectedItem()).preset;
+                preset.actionPerformed(e);
+                taggingPresets.setSelectedItem(null);
+            }
+        });
+        taggingPresets.setRenderer(new TaggingCellRenderer());
+
+        // setting up the properties table
+
+        propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
+        propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+        propertyTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer(){
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
+                if (c instanceof JLabel) {
+                    String str = null;
+                    switch (column) {
+                    case 0:
+                        str = (String) value;
+                    break;
+                    case 1:
+                        Map<String, Integer> v = (Map<String,Integer>) value;
+                        if (v.size()!=1) {
+                            str=tr("<different>");
+                            c.setFont(c.getFont().deriveFont(Font.ITALIC));
+                        } else {
+                            str=v.entrySet().iterator().next().getKey();
+                        }
+                    break;
+                    }
+                    ((JLabel)c).setText(str);
+                }
+                return c;
+            }
+        });
+
+        // setting up the membership table
+
+        membershipData.setColumnIdentifiers(new String[]{tr("Member Of"),tr("Role")});
+        membershipTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+        membershipTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
+                if (c instanceof JLabel) {
+                    nameVisitor.visit((Relation)value);
+                    ((JLabel)c).setText(nameVisitor.name);
+                }
+                return c;
+            }
+        });
+
+        membershipTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
+            @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+                Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
+                if (c instanceof JLabel) {
+                    Collection<RelationMember> col = (Collection<RelationMember>) value;
+
+                    String text = null;
+                    for (RelationMember r : col) {
+                        if (text == null) {
+                            text = r.role;
+                        }
+                        else if (!text.equals(r.role)) {
+                            text = tr("<different>");
+                            break;
+                        }
+                    }
+
+                    ((JLabel)c).setText(text);
+                }
+                return c;
+            }
+        });
+
+        // combine both tables and wrap them in a scrollPane
+        JPanel bothTables = new JPanel();
+        bothTables.setLayout(new GridBagLayout());
+        bothTables.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
+        bothTables.add(propertyTable, GBC.eol().fill(GBC.BOTH));
+        bothTables.add(membershipTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
+        bothTables.add(membershipTable, GBC.eol().fill(GBC.BOTH));
+
+        DblClickWatch dblClickWatch = new DblClickWatch();
+        propertyTable.addMouseListener(dblClickWatch);
+        membershipTable.addMouseListener(dblClickWatch);
+        JScrollPane scrollPane = new JScrollPane(bothTables);
+        scrollPane.addMouseListener(dblClickWatch);
+        add(scrollPane, BorderLayout.CENTER);
+
+        JPanel buttonPanel = new JPanel(new GridLayout(1,3));
+        ActionListener buttonAction = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                int row = membershipTable.getSelectedRow();
+                if (e.getActionCommand().equals("Add"))
+                    add();
+                else if(row >= 0)
+                {
+                    if (e.getActionCommand().equals("Edit"))
+                        membershipEdit(row);
+                    else if (e.getActionCommand().equals("Delete")) {
+                        Relation cur = (Relation)membershipData.getValueAt(row, 0);
+                        NameVisitor n = new NameVisitor();
+                        cur.visit(n);
+                        if(JOptionPane.showConfirmDialog(Main.parent, tr("Really delete selection from relation {0}?", n.name),
+                        tr("Change relation"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_NO_OPTION)
+                        {
+                            Relation rel = new Relation(cur);
+                            Collection<OsmPrimitive> sel = Main.ds.getSelected();
+                            for (RelationMember rm : cur.members) {
+                                for (OsmPrimitive osm : sel) {
+                                    if (rm.member == osm)
+                                    {
+                                        RelationMember mem = new RelationMember();
+                                        mem.role = rm.role;
+                                        mem.member = rm.member;
+                                        rel.members.remove(mem);
+                                        break;
+                                    }
+                                }
+                            }
+                            Main.main.undoRedo.add(new ChangeCommand(cur, rel));
+                            Main.ds.fireSelectionChanged(sel);
+                            selectionChanged(sel); // update whole table
+                        }
+
+                    }
+                }
+                else
+                {
+                    int sel = propertyTable.getSelectedRow();
+                    if (e.getActionCommand().equals("Edit")) {
+                        if(propertyTable.getRowCount() == 1)
+                            sel = 0;
+                        if (sel == -1)
+                            JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
+                        else
+                            propertyEdit(sel);
+                    } else if (e.getActionCommand().equals("Delete")) {
+                        if (sel == -1)
+                            JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."));
+                        else
+                            delete(sel);
+                    }
+                }
+            }
+        };
+
+        Shortcut s = Shortcut.registerShortcut("properties:add", tr("Add Properties"), KeyEvent.VK_B,
+        Shortcut.GROUP_MNEMONIC);
+        buttonPanel.add(new SideButton(marktr("Add"),"add","Properties",
                 tr("Add a new key/value pair to all objects"), s, buttonAction));
 
-		s = Shortcut.registerShortcut("properties:edit", tr("Edit Properties"), KeyEvent.VK_I,
-		Shortcut.GROUP_MNEMONIC);
-		buttonPanel.add(new SideButton(marktr("Edit"),"edit","Properties",
+        s = Shortcut.registerShortcut("properties:edit", tr("Edit Properties"), KeyEvent.VK_I,
+        Shortcut.GROUP_MNEMONIC);
+        buttonPanel.add(new SideButton(marktr("Edit"),"edit","Properties",
                 tr("Edit the value of the selected key for all objects"), s, buttonAction));
 
-		s = Shortcut.registerShortcut("properties:delete", tr("Delete Properties"), KeyEvent.VK_Q,
-		Shortcut.GROUP_MNEMONIC);
-		buttonPanel.add(new SideButton(marktr("Delete"),"delete","Properties",
+        s = Shortcut.registerShortcut("properties:delete", tr("Delete Properties"), KeyEvent.VK_Q,
+        Shortcut.GROUP_MNEMONIC);
+        buttonPanel.add(new SideButton(marktr("Delete"),"delete","Properties",
                 tr("Delete the selected key in all objects"), s, buttonAction));
-		add(buttonPanel, BorderLayout.SOUTH);
-
-		DataSet.selListeners.add(this);
-	}
-
-	@Override public void setVisible(boolean b) {
-		super.setVisible(b);
-		if (b)
-			selectionChanged(Main.ds.getSelected());
-	}
-
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		if (!isVisible())
-			return;
-		if (propertyTable == null)
-			return; // selection changed may be received in base class constructor before init
-		if (propertyTable.getCellEditor() != null)
-			propertyTable.getCellEditor().cancelCellEditing();
-
-		// re-load property data
-
-		propertyData.setRowCount(0);
-
-		Map<String, Integer> keyCount = new HashMap<String, Integer>();
-		valueCount.clear();
-		for (OsmPrimitive osm : newSelection) {
-			for (Entry<String, String> e : osm.entrySet()) {
-				keyCount.put(e.getKey(), keyCount.containsKey(e.getKey()) ? keyCount.get(e.getKey())+1 : 1);
-				if (valueCount.containsKey(e.getKey())) {
-					Map<String, Integer> v = valueCount.get(e.getKey());
-					v.put(e.getValue(), v.containsKey(e.getValue())? v.get(e.getValue())+1 : 1 );
-				} else {
-					TreeMap<String,Integer> v = new TreeMap<String, Integer>();
-					v.put(e.getValue(), 1);
-					valueCount.put(e.getKey(), v);
-				}
-			}
-		}
-		for (Entry<String, Map<String, Integer>> e : valueCount.entrySet()) {
-			int count=0;
-			for (Entry<String, Integer> e1: e.getValue().entrySet()) {
-				count+=e1.getValue();
-			}
-			if (count < newSelection.size()) {
-				e.getValue().put("", newSelection.size()-count);
-			}
-			propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
-		}
-
-		// re-load membership data
-		// this is rather expensive since we have to walk through all members of all existing relationships.
-		// could use back references here for speed if necessary.
-
-		membershipData.setRowCount(0);
-
-		Map<Relation, Collection<RelationMember>> roles = new HashMap<Relation, Collection<RelationMember>>();
-		for (Relation r : Main.ds.relations) {
-			if (!r.deleted && !r.incomplete) {
-				for (RelationMember m : r.members) {
-					if (newSelection.contains(m.member)) {
-						Collection<RelationMember> value = roles.get(r);
-						if (value == null) {
-							value = new HashSet<RelationMember>();
-							roles.put(r, value);
-						}
-						value.add(m);
-					}
-				}
-			}
-		}
-
-		for (Entry<Relation, Collection<RelationMember>> e : roles.entrySet()) {
-			membershipData.addRow(new Object[]{e.getKey(), e.getValue()});
-		}
-
-		membershipTable.getTableHeader().setVisible(membershipData.getRowCount() > 0);
-	}
+        add(buttonPanel, BorderLayout.SOUTH);
+
+        DataSet.selListeners.add(this);
+    }
+
+    @Override public void setVisible(boolean b) {
+        super.setVisible(b);
+        if (b)
+            selectionChanged(Main.ds.getSelected());
+    }
+
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        if (!isVisible())
+            return;
+        if (propertyTable == null)
+            return; // selection changed may be received in base class constructor before init
+        if (propertyTable.getCellEditor() != null)
+            propertyTable.getCellEditor().cancelCellEditing();
+
+        // re-load property data
+
+        propertyData.setRowCount(0);
+
+        Map<String, Integer> keyCount = new HashMap<String, Integer>();
+        valueCount.clear();
+        for (OsmPrimitive osm : newSelection) {
+            for (Entry<String, String> e : osm.entrySet()) {
+                keyCount.put(e.getKey(), keyCount.containsKey(e.getKey()) ? keyCount.get(e.getKey())+1 : 1);
+                if (valueCount.containsKey(e.getKey())) {
+                    Map<String, Integer> v = valueCount.get(e.getKey());
+                    v.put(e.getValue(), v.containsKey(e.getValue())? v.get(e.getValue())+1 : 1 );
+                } else {
+                    TreeMap<String,Integer> v = new TreeMap<String, Integer>();
+                    v.put(e.getValue(), 1);
+                    valueCount.put(e.getKey(), v);
+                }
+            }
+        }
+        for (Entry<String, Map<String, Integer>> e : valueCount.entrySet()) {
+            int count=0;
+            for (Entry<String, Integer> e1: e.getValue().entrySet()) {
+                count+=e1.getValue();
+            }
+            if (count < newSelection.size()) {
+                e.getValue().put("", newSelection.size()-count);
+            }
+            propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
+        }
+
+        // re-load membership data
+        // this is rather expensive since we have to walk through all members of all existing relationships.
+        // could use back references here for speed if necessary.
+
+        membershipData.setRowCount(0);
+
+        Map<Relation, Collection<RelationMember>> roles = new HashMap<Relation, Collection<RelationMember>>();
+        for (Relation r : Main.ds.relations) {
+            if (!r.deleted && !r.incomplete) {
+                for (RelationMember m : r.members) {
+                    if (newSelection.contains(m.member)) {
+                        Collection<RelationMember> value = roles.get(r);
+                        if (value == null) {
+                            value = new HashSet<RelationMember>();
+                            roles.put(r, value);
+                        }
+                        value.add(m);
+                    }
+                }
+            }
+        }
+
+        for (Entry<Relation, Collection<RelationMember>> e : roles.entrySet()) {
+            membershipData.addRow(new Object[]{e.getKey(), e.getValue()});
+        }
+
+        membershipTable.getTableHeader().setVisible(membershipData.getRowCount() > 0);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/RelationEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/RelationEditor.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/RelationEditor.java	(revision 1169)
@@ -65,11 +65,11 @@
 public class RelationEditor extends JFrame {
 
-	/**
-	 * The relation that this editor is working on, and the clone made for
-	 * editing.
-	 */
-	private final Relation relation;
-	private final Relation clone;
-	private JLabel status;
+    /**
+     * The relation that this editor is working on, and the clone made for
+     * editing.
+     */
+    private final Relation relation;
+    private final Relation clone;
+    private JLabel status;
 
     /**
@@ -78,231 +78,231 @@
     boolean ordered;
 
-	/**
-	 * The property data.
-	 */
-	private final DefaultTableModel propertyData = new DefaultTableModel() {
-		@Override public boolean isCellEditable(int row, int column) {
-			return true;
-		}
-		@Override public Class<?> getColumnClass(int columnIndex) {
-			return String.class;
-		}
-	};
-
-	/**
-	 * The membership data.
-	 */
-	private final DefaultTableModel memberData = new DefaultTableModel() {
-		@Override public boolean isCellEditable(int row, int column) {
-			return column == 0;
-		}
-		@Override public Class<?> getColumnClass(int columnIndex) {
-			return columnIndex == 1 ? OsmPrimitive.class : String.class;
-		}
-	};
-
-	/**
-	 * The properties and membership lists.
-	 */
-	private final JTable propertyTable = new JTable(propertyData);
-	private final JTable memberTable = new JTable(memberData);
+    /**
+     * The property data.
+     */
+    private final DefaultTableModel propertyData = new DefaultTableModel() {
+        @Override public boolean isCellEditable(int row, int column) {
+            return true;
+        }
+        @Override public Class<?> getColumnClass(int columnIndex) {
+            return String.class;
+        }
+    };
+
+    /**
+     * The membership data.
+     */
+    private final DefaultTableModel memberData = new DefaultTableModel() {
+        @Override public boolean isCellEditable(int row, int column) {
+            return column == 0;
+        }
+        @Override public Class<?> getColumnClass(int columnIndex) {
+            return columnIndex == 1 ? OsmPrimitive.class : String.class;
+        }
+    };
+
+    /**
+     * The properties and membership lists.
+     */
+    private final JTable propertyTable = new JTable(propertyData);
+    private final JTable memberTable = new JTable(memberData);
 
     // =================== FIXME FIXME FIXME =====================
     // As soon as API 0.5 is dead, drop all the collation stuff from here ...
-    
-	/**
-	 * Collator for sorting the roles and entries of the member table.
-	 */
-	private static final Collator collator;
-	static {
-		collator = Collator.getInstance();
-		collator.setStrength(Collator.PRIMARY);
-	}
-
-	/**
-	 * Compare role strings.
-	 */
-	private static int compareRole(String s1, String s2) {
-		int last1 = s1.lastIndexOf('_');
-		if (last1 > 0) {
-			int last2 = s2.lastIndexOf('_');
-			if (last2 == last1) {
-				String prefix1 = s1.substring(0, last1);
-				String prefix2 = s2.substring(0, last2);
-
-				if (prefix1.equalsIgnoreCase(prefix2)) {
-					// Both roles have the same prefix, now determine the
-					// suffix.
-					String suffix1 = s1.substring(last1 + 1, s1.length());
-					String suffix2 = s2.substring(last2 + 1, s2.length());
-
-					if (suffix1.matches("\\d+") && suffix2.matches("\\d+")) {
-						// Suffix is an number -> compare it.
-						int i1 = Integer.parseInt(suffix1);
-						int i2 = Integer.parseInt(suffix2);
-
-						return i1 - i2;
-					}
-				}
-			}
-		}
-		if(s1.length() == 0 && s2.length() != 0)
-			return 1;
-		else if(s2.length() == 0 && s1.length() != 0)
-			return -1;
-
-		// Default handling if the role name is nothing like "stop_xx"
-		return collator.compare(s1, s2);
-	}
-
-
-	/**
-	 * Compare two OsmPrimitives.
-	 */
-	private static int compareMemebers(OsmPrimitive o1, OsmPrimitive o2) {
-		return collator.compare(o1.getName(), o2.getName());
-	}
-
-	private final Comparator<RelationMember> memberComparator = new Comparator<RelationMember>() {
-		public int compare(RelationMember r1, RelationMember r2) {
-			int roleResult = compareRole(r1.role, r2.role);
-
-			if (roleResult == 0)
-				roleResult = compareMemebers(r1.member, r2.member);
-
-			return roleResult;
-		}
-	};
+
+    /**
+     * Collator for sorting the roles and entries of the member table.
+     */
+    private static final Collator collator;
+    static {
+        collator = Collator.getInstance();
+        collator.setStrength(Collator.PRIMARY);
+    }
+
+    /**
+     * Compare role strings.
+     */
+    private static int compareRole(String s1, String s2) {
+        int last1 = s1.lastIndexOf('_');
+        if (last1 > 0) {
+            int last2 = s2.lastIndexOf('_');
+            if (last2 == last1) {
+                String prefix1 = s1.substring(0, last1);
+                String prefix2 = s2.substring(0, last2);
+
+                if (prefix1.equalsIgnoreCase(prefix2)) {
+                    // Both roles have the same prefix, now determine the
+                    // suffix.
+                    String suffix1 = s1.substring(last1 + 1, s1.length());
+                    String suffix2 = s2.substring(last2 + 1, s2.length());
+
+                    if (suffix1.matches("\\d+") && suffix2.matches("\\d+")) {
+                        // Suffix is an number -> compare it.
+                        int i1 = Integer.parseInt(suffix1);
+                        int i2 = Integer.parseInt(suffix2);
+
+                        return i1 - i2;
+                    }
+                }
+            }
+        }
+        if(s1.length() == 0 && s2.length() != 0)
+            return 1;
+        else if(s2.length() == 0 && s1.length() != 0)
+            return -1;
+
+        // Default handling if the role name is nothing like "stop_xx"
+        return collator.compare(s1, s2);
+    }
+
+
+    /**
+     * Compare two OsmPrimitives.
+     */
+    private static int compareMemebers(OsmPrimitive o1, OsmPrimitive o2) {
+        return collator.compare(o1.getName(), o2.getName());
+    }
+
+    private final Comparator<RelationMember> memberComparator = new Comparator<RelationMember>() {
+        public int compare(RelationMember r1, RelationMember r2) {
+            int roleResult = compareRole(r1.role, r2.role);
+
+            if (roleResult == 0)
+                roleResult = compareMemebers(r1.member, r2.member);
+
+            return roleResult;
+        }
+    };
 
     // =================== FIXME FIXME FIXME =====================
     // ... until here, and also get rid of the "Collections.sort..." below.
-    
-	/**
-	 * Creates a new relation editor for the given relation. The relation
-	 * will be saved if the user selects "ok" in the editor.
-	 * 
-	 * If no relation is given, will create an editor for a new relation.
-	 * 
-	 * @param relation relation to edit, or null to create a new one.
-	 */
-	public RelationEditor(Relation relation)
-	{
-		this(relation, null);
-	}
-
-	/**
-	 * Creates a new relation editor for the given relation. The relation
-	 * will be saved if the user selects "ok" in the editor.
-	 * 
-	 * If no relation is given, will create an editor for a new relation.
-	 * 
-	 * @param relation relation to edit, or null to create a new one.
-	 */
-	public RelationEditor(Relation relation, Collection<RelationMember> selectedMembers )
-	{
-		super(relation == null ? tr("Create new relation") :
-			relation.id == 0 ? tr ("Edit new relation") :
-			tr("Edit relation #{0}", relation.id));
-		this.relation = relation;
+
+    /**
+     * Creates a new relation editor for the given relation. The relation
+     * will be saved if the user selects "ok" in the editor.
+     *
+     * If no relation is given, will create an editor for a new relation.
+     *
+     * @param relation relation to edit, or null to create a new one.
+     */
+    public RelationEditor(Relation relation)
+    {
+        this(relation, null);
+    }
+
+    /**
+     * Creates a new relation editor for the given relation. The relation
+     * will be saved if the user selects "ok" in the editor.
+     *
+     * If no relation is given, will create an editor for a new relation.
+     *
+     * @param relation relation to edit, or null to create a new one.
+     */
+    public RelationEditor(Relation relation, Collection<RelationMember> selectedMembers )
+    {
+        super(relation == null ? tr("Create new relation") :
+            relation.id == 0 ? tr ("Edit new relation") :
+            tr("Edit relation #{0}", relation.id));
+        this.relation = relation;
 
         ordered = Main.pref.get("osm-server.version", "0.5").equals("0.6");
-        
-		if (relation == null) {
-			// create a new relation
-			this.clone = new Relation();
-		} else {
-			// edit an existing relation
-			this.clone = new Relation(relation);
-			if (!ordered) Collections.sort(this.clone.members, memberComparator);
-		}
-
-		getContentPane().setLayout(new BorderLayout());
-		JTabbedPane tabPane = new JTabbedPane();
-		getContentPane().add(tabPane, BorderLayout.CENTER);
-
-		// (ab)use JOptionPane to make this look familiar;
-		// hook up with JOptionPane's property change event
-		// to detect button click
-		final JOptionPane okcancel = new JOptionPane("",
-			JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
-		getContentPane().add(okcancel, BorderLayout.SOUTH);
-
-		okcancel.addPropertyChangeListener(new PropertyChangeListener() {
-			public void propertyChange(PropertyChangeEvent event) {
-				if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY) && event.getNewValue() != null) {
-					if ((Integer)event.getNewValue() == JOptionPane.OK_OPTION) {
-						// clicked ok!
-						if (RelationEditor.this.relation == null) {
-							Main.main.undoRedo.add(new AddCommand(clone));
-							DataSet.fireSelectionChanged(Main.ds.getSelected());
-						} else if (!RelationEditor.this.relation.realEqual(clone, true)) {
-							Main.main.undoRedo.add(new ChangeCommand(RelationEditor.this.relation, clone));
-							DataSet.fireSelectionChanged(Main.ds.getSelected());
-						}
-					}
-					setVisible(false);
-				}
-			}
-		});
-
-		JLabel help = new JLabel("<html><em>"+
-			tr("This is the basic relation editor which allows you to change the relation's tags " +
-			"as well as the members. In addition to this we should have a smart editor that " +
-			"detects the type of relationship and limits your choices in a sensible way.")+"</em></html>");
-		getContentPane().add(help, BorderLayout.NORTH);
-		try { setAlwaysOnTop(true); } catch (SecurityException sx) {}
-
-		// Basic Editor panel has two blocks;
-		// a tag table at the top and a membership list below.
-
-		// setting up the properties table
-
-		propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
-		propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		propertyData.addTableModelListener(new TableModelListener() {
-			public void tableChanged(TableModelEvent tme) {
-				if (tme.getType() == TableModelEvent.UPDATE) {
-					int row = tme.getFirstRow();
-
-					if (!(tme.getColumn() == 0 && row == propertyData.getRowCount() -1)) {
-						clone.entrySet().clear();
-						for (int i = 0; i < propertyData.getRowCount(); i++) {
-							String key = propertyData.getValueAt(i, 0).toString();
-							String value = propertyData.getValueAt(i, 1).toString();
-							if (key.length() > 0 && value.length() > 0) clone.put(key, value);
-						}
-						refreshTables();
-					}
-				}
-			}
-		});
-		propertyTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
-
-		// setting up the member table
-
-		memberData.setColumnIdentifiers(new String[]{tr("Role"),tr("Occupied By")});
-		memberTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-		memberTable.getColumnModel().getColumn(1).setCellRenderer(new OsmPrimitivRenderer());
-		memberData.addTableModelListener(new TableModelListener() {
-			public void tableChanged(TableModelEvent tme) {
-				if (tme.getType() == TableModelEvent.UPDATE && tme.getColumn() == 0) {
-					int row = tme.getFirstRow();
-					clone.members.get(row).role = memberData.getValueAt(row, 0).toString();
-				}
-			}
-		});
-		memberTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
-
-		// combine both tables and wrap them in a scrollPane
-		JPanel bothTables = new JPanel();
-		bothTables.setLayout(new GridBagLayout());
-		bothTables.add(new JLabel(tr("Tags (empty value deletes tag)")), GBC.eol().fill(GBC.HORIZONTAL));
-		bothTables.add(new JScrollPane(propertyTable), GBC.eop().fill(GBC.BOTH));
-		bothTables.add(status = new JLabel(tr("Members")), GBC.eol().fill(GBC.HORIZONTAL));
+
+        if (relation == null) {
+            // create a new relation
+            this.clone = new Relation();
+        } else {
+            // edit an existing relation
+            this.clone = new Relation(relation);
+            if (!ordered) Collections.sort(this.clone.members, memberComparator);
+        }
+
+        getContentPane().setLayout(new BorderLayout());
+        JTabbedPane tabPane = new JTabbedPane();
+        getContentPane().add(tabPane, BorderLayout.CENTER);
+
+        // (ab)use JOptionPane to make this look familiar;
+        // hook up with JOptionPane's property change event
+        // to detect button click
+        final JOptionPane okcancel = new JOptionPane("",
+            JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
+        getContentPane().add(okcancel, BorderLayout.SOUTH);
+
+        okcancel.addPropertyChangeListener(new PropertyChangeListener() {
+            public void propertyChange(PropertyChangeEvent event) {
+                if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY) && event.getNewValue() != null) {
+                    if ((Integer)event.getNewValue() == JOptionPane.OK_OPTION) {
+                        // clicked ok!
+                        if (RelationEditor.this.relation == null) {
+                            Main.main.undoRedo.add(new AddCommand(clone));
+                            DataSet.fireSelectionChanged(Main.ds.getSelected());
+                        } else if (!RelationEditor.this.relation.realEqual(clone, true)) {
+                            Main.main.undoRedo.add(new ChangeCommand(RelationEditor.this.relation, clone));
+                            DataSet.fireSelectionChanged(Main.ds.getSelected());
+                        }
+                    }
+                    setVisible(false);
+                }
+            }
+        });
+
+        JLabel help = new JLabel("<html><em>"+
+            tr("This is the basic relation editor which allows you to change the relation's tags " +
+            "as well as the members. In addition to this we should have a smart editor that " +
+            "detects the type of relationship and limits your choices in a sensible way.")+"</em></html>");
+        getContentPane().add(help, BorderLayout.NORTH);
+        try { setAlwaysOnTop(true); } catch (SecurityException sx) {}
+
+        // Basic Editor panel has two blocks;
+        // a tag table at the top and a membership list below.
+
+        // setting up the properties table
+
+        propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
+        propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        propertyData.addTableModelListener(new TableModelListener() {
+            public void tableChanged(TableModelEvent tme) {
+                if (tme.getType() == TableModelEvent.UPDATE) {
+                    int row = tme.getFirstRow();
+
+                    if (!(tme.getColumn() == 0 && row == propertyData.getRowCount() -1)) {
+                        clone.entrySet().clear();
+                        for (int i = 0; i < propertyData.getRowCount(); i++) {
+                            String key = propertyData.getValueAt(i, 0).toString();
+                            String value = propertyData.getValueAt(i, 1).toString();
+                            if (key.length() > 0 && value.length() > 0) clone.put(key, value);
+                        }
+                        refreshTables();
+                    }
+                }
+            }
+        });
+        propertyTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
+
+        // setting up the member table
+
+        memberData.setColumnIdentifiers(new String[]{tr("Role"),tr("Occupied By")});
+        memberTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        memberTable.getColumnModel().getColumn(1).setCellRenderer(new OsmPrimitivRenderer());
+        memberData.addTableModelListener(new TableModelListener() {
+            public void tableChanged(TableModelEvent tme) {
+                if (tme.getType() == TableModelEvent.UPDATE && tme.getColumn() == 0) {
+                    int row = tme.getFirstRow();
+                    clone.members.get(row).role = memberData.getValueAt(row, 0).toString();
+                }
+            }
+        });
+        memberTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
+
+        // combine both tables and wrap them in a scrollPane
+        JPanel bothTables = new JPanel();
+        bothTables.setLayout(new GridBagLayout());
+        bothTables.add(new JLabel(tr("Tags (empty value deletes tag)")), GBC.eol().fill(GBC.HORIZONTAL));
+        bothTables.add(new JScrollPane(propertyTable), GBC.eop().fill(GBC.BOTH));
+        bothTables.add(status = new JLabel(tr("Members")), GBC.eol().fill(GBC.HORIZONTAL));
         if (ordered) {
             JPanel upDownPanel = new JPanel();
             upDownPanel.setLayout(new BoxLayout(upDownPanel, BoxLayout.Y_AXIS));
 
-            
+
 
             upDownPanel.add(createButton(null, "moveup", tr("Move the currently selected member(s) up"),
@@ -319,5 +319,5 @@
             }));
 
-            
+
             bothTables.add(new JScrollPane(memberTable), GBC.std().fill(GBC.BOTH));
             bothTables.add(upDownPanel, GBC.eol().fill(GBC.VERTICAL));
@@ -325,124 +325,124 @@
             bothTables.add(new JScrollPane(memberTable), GBC.eol().fill(GBC.BOTH));
         }
-        
-		JPanel buttonPanel = new JPanel(new GridLayout(1,3));
-
-		buttonPanel.add(createButton(marktr("Add Selected"),"addselected",
-		tr("Add all currently selected objects as members"), KeyEvent.VK_A, new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				addSelected();
-			}
-		}));
-
-		buttonPanel.add(createButton(marktr("Delete Selected"),"deleteselected",
-		tr("Delete all currently selected objects from relation"), KeyEvent.VK_R, new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				deleteSelected();
-			}
-		}));
-
-		buttonPanel.add(createButton(marktr("Delete"),"delete",
-		tr("Remove the member in the current table row from this relation"), KeyEvent.VK_D, new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				int[] rows = memberTable.getSelectedRows();
-				RelationMember mem = new RelationMember();
-				for (int row : rows) {
-					mem.role = memberTable.getValueAt(row, 0).toString();
-					mem.member = (OsmPrimitive) memberTable.getValueAt(row, 1);
-					clone.members.remove(mem);
-				}
-				refreshTables();
-			}
-		}));
-
-		buttonPanel.add(createButton(marktr("Select"),"select",
-		tr("Highlight the member from the current table row as JOSM's selection"), KeyEvent.VK_S, new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				ArrayList<OsmPrimitive> sel;
-				int cnt = memberTable.getSelectedRowCount();
-				if(cnt > 0)
-				{
-					sel = new ArrayList<OsmPrimitive>(cnt);
-					for (int i : memberTable.getSelectedRows())
-						sel.add((OsmPrimitive)memberTable.getValueAt(i, 1));
-				}
-				else
-				{
-					cnt = memberTable.getRowCount();
-					sel = new ArrayList<OsmPrimitive>(cnt);
-					for (int i = 0; i < cnt; ++i)
-						sel.add((OsmPrimitive)memberTable.getValueAt(i, 1));
-				}
-				Main.ds.setSelected(sel);
-			}
-		}));
-		buttonPanel.add(createButton(marktr("Download Members"),"down",
-		tr("Download all incomplete ways and nodes in relation"), KeyEvent.VK_L, new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				downloadRelationMembers();
-				refreshTables();
-			}
-		}));
-
-		bothTables.add(buttonPanel, GBC.eop().fill(GBC.HORIZONTAL));
-
-		tabPane.add(bothTables, "Basic");
-
-		refreshTables();
-
-		if (selectedMembers != null) {
-			boolean scrolled = false;
-			for (int i = 0; i < memberData.getRowCount(); i++) {		
-				for (RelationMember m : selectedMembers) {
-					if (m.member == memberData.getValueAt(i, 1)
-					        && m.role.equals(memberData.getValueAt(i, 0))) {
-						memberTable.addRowSelectionInterval(i, i);
-						if (!scrolled) {
-							// Ensure that the first member is visible
-							memberTable.scrollRectToVisible(memberTable.getCellRect(i, 0, true));
-							scrolled = true;
-						}
-						break;
-					}
-				}
-				
-			}	
-		}
-
-		setSize(new Dimension(600, 500));
-		setLocationRelativeTo(Main.parent);
-	}
-
-	private void refreshTables() {
-		// re-load property data
-
-		propertyData.setRowCount(0);
-		for (Entry<String, String> e : clone.entrySet()) {
-			propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
-		}
-		propertyData.addRow(new Object[]{"", ""});
-
-		// re-load membership data
-
-		memberData.setRowCount(0);
-		for (RelationMember em : clone.members) {
-			memberData.addRow(new Object[]{em.role, em.member});
-		}
-		status.setText(tr("Members: {0}", clone.members.size()));
-	}
-
-	private JButton createButton(String name, String iconName, String tooltip, int mnemonic, ActionListener actionListener) {
-		JButton b = new JButton(tr(name), ImageProvider.get("dialogs", iconName));
-		b.setActionCommand(name);
-		b.addActionListener(actionListener);
-		b.setToolTipText(tooltip);
-		b.setMnemonic(mnemonic);
-		b.putClientProperty("help", "Dialog/Properties/"+name);
-		return b;
-	}
-
-	private void addSelected() {
-		for (OsmPrimitive p : Main.ds.getSelected()) {
-			boolean skip = false;
+
+        JPanel buttonPanel = new JPanel(new GridLayout(1,3));
+
+        buttonPanel.add(createButton(marktr("Add Selected"),"addselected",
+        tr("Add all currently selected objects as members"), KeyEvent.VK_A, new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                addSelected();
+            }
+        }));
+
+        buttonPanel.add(createButton(marktr("Delete Selected"),"deleteselected",
+        tr("Delete all currently selected objects from relation"), KeyEvent.VK_R, new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                deleteSelected();
+            }
+        }));
+
+        buttonPanel.add(createButton(marktr("Delete"),"delete",
+        tr("Remove the member in the current table row from this relation"), KeyEvent.VK_D, new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                int[] rows = memberTable.getSelectedRows();
+                RelationMember mem = new RelationMember();
+                for (int row : rows) {
+                    mem.role = memberTable.getValueAt(row, 0).toString();
+                    mem.member = (OsmPrimitive) memberTable.getValueAt(row, 1);
+                    clone.members.remove(mem);
+                }
+                refreshTables();
+            }
+        }));
+
+        buttonPanel.add(createButton(marktr("Select"),"select",
+        tr("Highlight the member from the current table row as JOSM's selection"), KeyEvent.VK_S, new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                ArrayList<OsmPrimitive> sel;
+                int cnt = memberTable.getSelectedRowCount();
+                if(cnt > 0)
+                {
+                    sel = new ArrayList<OsmPrimitive>(cnt);
+                    for (int i : memberTable.getSelectedRows())
+                        sel.add((OsmPrimitive)memberTable.getValueAt(i, 1));
+                }
+                else
+                {
+                    cnt = memberTable.getRowCount();
+                    sel = new ArrayList<OsmPrimitive>(cnt);
+                    for (int i = 0; i < cnt; ++i)
+                        sel.add((OsmPrimitive)memberTable.getValueAt(i, 1));
+                }
+                Main.ds.setSelected(sel);
+            }
+        }));
+        buttonPanel.add(createButton(marktr("Download Members"),"down",
+        tr("Download all incomplete ways and nodes in relation"), KeyEvent.VK_L, new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                downloadRelationMembers();
+                refreshTables();
+            }
+        }));
+
+        bothTables.add(buttonPanel, GBC.eop().fill(GBC.HORIZONTAL));
+
+        tabPane.add(bothTables, "Basic");
+
+        refreshTables();
+
+        if (selectedMembers != null) {
+            boolean scrolled = false;
+            for (int i = 0; i < memberData.getRowCount(); i++) {
+                for (RelationMember m : selectedMembers) {
+                    if (m.member == memberData.getValueAt(i, 1)
+                            && m.role.equals(memberData.getValueAt(i, 0))) {
+                        memberTable.addRowSelectionInterval(i, i);
+                        if (!scrolled) {
+                            // Ensure that the first member is visible
+                            memberTable.scrollRectToVisible(memberTable.getCellRect(i, 0, true));
+                            scrolled = true;
+                        }
+                        break;
+                    }
+                }
+
+            }
+        }
+
+        setSize(new Dimension(600, 500));
+        setLocationRelativeTo(Main.parent);
+    }
+
+    private void refreshTables() {
+        // re-load property data
+
+        propertyData.setRowCount(0);
+        for (Entry<String, String> e : clone.entrySet()) {
+            propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
+        }
+        propertyData.addRow(new Object[]{"", ""});
+
+        // re-load membership data
+
+        memberData.setRowCount(0);
+        for (RelationMember em : clone.members) {
+            memberData.addRow(new Object[]{em.role, em.member});
+        }
+        status.setText(tr("Members: {0}", clone.members.size()));
+    }
+
+    private JButton createButton(String name, String iconName, String tooltip, int mnemonic, ActionListener actionListener) {
+        JButton b = new JButton(tr(name), ImageProvider.get("dialogs", iconName));
+        b.setActionCommand(name);
+        b.addActionListener(actionListener);
+        b.setToolTipText(tooltip);
+        b.setMnemonic(mnemonic);
+        b.putClientProperty("help", "Dialog/Properties/"+name);
+        return b;
+    }
+
+    private void addSelected() {
+        for (OsmPrimitive p : Main.ds.getSelected()) {
+            boolean skip = false;
             // ordered relations may have the same member multiple times.
             // TODO: visual indication of the fact that one is there more than once?
@@ -457,9 +457,9 @@
                 }
             }
-			if (!skip)
-			{
-				RelationMember em = new RelationMember();
-				em.member = p;
-				em.role = "";
+            if (!skip)
+            {
+                RelationMember em = new RelationMember();
+                em.member = p;
+                em.role = "";
                 // when working with ordered relations, we make an effort to
                 // add the element before the first selected member.
@@ -470,42 +470,42 @@
                     clone.members.add(em);
                 }
-			}
-		}
-		refreshTables();
-	}
-
-	private void deleteSelected() {
-		for (OsmPrimitive p : Main.ds.getSelected()) {
-			Relation c = new Relation(clone);
-			for (RelationMember rm : c.members) {
-				if (rm.member == p)
-				{
-					RelationMember mem = new RelationMember();
-					mem.role = rm.role;
-					mem.member = rm.member;
-					clone.members.remove(mem);
-				}
-			}
-		}
-		refreshTables();
-	}
-
-	private void moveMembers(int direction) {
-	    int[] rows = memberTable.getSelectedRows();
+            }
+        }
+        refreshTables();
+    }
+
+    private void deleteSelected() {
+        for (OsmPrimitive p : Main.ds.getSelected()) {
+            Relation c = new Relation(clone);
+            for (RelationMember rm : c.members) {
+                if (rm.member == p)
+                {
+                    RelationMember mem = new RelationMember();
+                    mem.role = rm.role;
+                    mem.member = rm.member;
+                    clone.members.remove(mem);
+                }
+            }
+        }
+        refreshTables();
+    }
+
+    private void moveMembers(int direction) {
+        int[] rows = memberTable.getSelectedRows();
         if (rows.length == 0) return;
-        
+
         // check if user attempted to move anything beyond the boundary of the list
         if (rows[0] + direction < 0) return;
         if (rows[rows.length-1] + direction >= clone.members.size()) return;
-        
+
         RelationMember m[] = new RelationMember[clone.members.size()];
-        
+
         // first move all selected rows from the member list into a new array,
         // displaced by the move amount
         for (Integer i: rows) {
             m[i+direction] = clone.members.get(i);
-            clone.members.set(i, null);            
-        }
-        
+            clone.members.set(i, null);
+        }
+
         // now fill the empty spots in the destination array with the remaining
         // elements.
@@ -517,9 +517,9 @@
             }
         }
-        
+
         // and write the array back into the member list.
         clone.members.clear();
-        clone.members.addAll(Arrays.asList(m));        
-	    refreshTables();
+        clone.members.addAll(Arrays.asList(m));
+        refreshTables();
         ListSelectionModel lsm = memberTable.getSelectionModel();
         lsm.setValueIsAdjusting(true);
@@ -528,51 +528,51 @@
         }
         lsm.setValueIsAdjusting(false);
-	}
-
-	private void downloadRelationMembers() {
-		boolean download = false;
-		for (RelationMember member : clone.members) {
-			if (member.member.incomplete) {
-				download = true;
-				break;
-			}
-		}
-		if (download) {
-			OsmServerObjectReader reader = new OsmServerObjectReader(clone.id, OsmServerObjectReader.TYPE_REL, true);
-			try {
-				DataSet dataSet = reader.parseOsm();
-				if (dataSet != null) {
-					final MergeVisitor visitor = new MergeVisitor(Main.main
-							.editLayer().data, dataSet);
-					for (final OsmPrimitive osm : dataSet.allPrimitives())
-						osm.visit(visitor);
-					visitor.fixReferences();
-
-					// copy the merged layer's data source info
-					for (DataSource src : dataSet.dataSources)
-						Main.main.editLayer().data.dataSources.add(src);
-					Main.main.editLayer().fireDataChange();
-
-					if (visitor.conflicts.isEmpty())
-						return;
-					final ConflictDialog dlg = Main.map.conflictDialog;
-					dlg.add(visitor.conflicts);
-					JOptionPane.showMessageDialog(Main.parent,
-							tr("There were conflicts during import."));
-					if (!dlg.isVisible())
-						dlg.action
-								.actionPerformed(new ActionEvent(this, 0, ""));
-				}
-
-			} catch (SAXException e) {
-				e.printStackTrace();
-				JOptionPane.showMessageDialog(this,tr("Error parsing server response.")+": "+e.getMessage(),
-				tr("Error"), JOptionPane.ERROR_MESSAGE);
-			} catch (IOException e) {
-				e.printStackTrace();
-				JOptionPane.showMessageDialog(this,tr("Cannot connect to server.")+": "+e.getMessage(),
-				tr("Error"), JOptionPane.ERROR_MESSAGE);
-			}
-		}
-	}
+    }
+
+    private void downloadRelationMembers() {
+        boolean download = false;
+        for (RelationMember member : clone.members) {
+            if (member.member.incomplete) {
+                download = true;
+                break;
+            }
+        }
+        if (download) {
+            OsmServerObjectReader reader = new OsmServerObjectReader(clone.id, OsmServerObjectReader.TYPE_REL, true);
+            try {
+                DataSet dataSet = reader.parseOsm();
+                if (dataSet != null) {
+                    final MergeVisitor visitor = new MergeVisitor(Main.main
+                            .editLayer().data, dataSet);
+                    for (final OsmPrimitive osm : dataSet.allPrimitives())
+                        osm.visit(visitor);
+                    visitor.fixReferences();
+
+                    // copy the merged layer's data source info
+                    for (DataSource src : dataSet.dataSources)
+                        Main.main.editLayer().data.dataSources.add(src);
+                    Main.main.editLayer().fireDataChange();
+
+                    if (visitor.conflicts.isEmpty())
+                        return;
+                    final ConflictDialog dlg = Main.map.conflictDialog;
+                    dlg.add(visitor.conflicts);
+                    JOptionPane.showMessageDialog(Main.parent,
+                            tr("There were conflicts during import."));
+                    if (!dlg.isVisible())
+                        dlg.action
+                                .actionPerformed(new ActionEvent(this, 0, ""));
+                }
+
+            } catch (SAXException e) {
+                e.printStackTrace();
+                JOptionPane.showMessageDialog(this,tr("Error parsing server response.")+": "+e.getMessage(),
+                tr("Error"), JOptionPane.ERROR_MESSAGE);
+            } catch (IOException e) {
+                e.printStackTrace();
+                JOptionPane.showMessageDialog(this,tr("Cannot connect to server.")+": "+e.getMessage(),
+                tr("Error"), JOptionPane.ERROR_MESSAGE);
+            }
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 1169)
@@ -45,132 +45,132 @@
 public class RelationListDialog extends ToggleDialog implements LayerChangeListener, DataChangeListener {
 
-	/**
-	 * The selection's list data.
-	 */
-	private final DefaultListModel list = new DefaultListModel();
+    /**
+     * The selection's list data.
+     */
+    private final DefaultListModel list = new DefaultListModel();
 
-	/**
-	 * The display list.
-	 */
-	private JList displaylist = new JList(list);
+    /**
+     * The display list.
+     */
+    private JList displaylist = new JList(list);
 
-	public RelationListDialog() {
-		super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
-		Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), KeyEvent.VK_R, Shortcut.GROUP_LAYER), 150);
-		displaylist.setCellRenderer(new OsmPrimitivRenderer());
-		displaylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		displaylist.addMouseListener(new MouseAdapter(){
-			@Override public void mouseClicked(MouseEvent e) {
-				if (e.getClickCount() < 2)
-					return;
-				Relation toEdit = (Relation) displaylist.getSelectedValue();
-				if (toEdit != null)
-					new RelationEditor(toEdit).setVisible(true);
-			}
-		});
+    public RelationListDialog() {
+        super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
+        Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), KeyEvent.VK_R, Shortcut.GROUP_LAYER), 150);
+        displaylist.setCellRenderer(new OsmPrimitivRenderer());
+        displaylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        displaylist.addMouseListener(new MouseAdapter(){
+            @Override public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() < 2)
+                    return;
+                Relation toEdit = (Relation) displaylist.getSelectedValue();
+                if (toEdit != null)
+                    new RelationEditor(toEdit).setVisible(true);
+            }
+        });
 
-		add(new JScrollPane(displaylist), BorderLayout.CENTER);
+        add(new JScrollPane(displaylist), BorderLayout.CENTER);
 
-		JPanel buttonPanel = new JPanel(new GridLayout(1,4));
+        JPanel buttonPanel = new JPanel(new GridLayout(1,4));
 
-		buttonPanel.add(new SideButton(marktr("New"), "addrelation", "Selection", tr("Create a new relation"), new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				// call relation editor with null argument to create new relation
-				new RelationEditor(null).setVisible(true);
-			}
-		}), GBC.std());
+        buttonPanel.add(new SideButton(marktr("New"), "addrelation", "Selection", tr("Create a new relation"), new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                // call relation editor with null argument to create new relation
+                new RelationEditor(null).setVisible(true);
+            }
+        }), GBC.std());
 
-		buttonPanel.add(new SideButton(marktr("Select"), "select", "Selection", tr("Select this relation"), new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				// replace selection with the relation from the list
-				Main.ds.setSelected((Relation)displaylist.getSelectedValue());
-			}
-		}), GBC.std());
+        buttonPanel.add(new SideButton(marktr("Select"), "select", "Selection", tr("Select this relation"), new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                // replace selection with the relation from the list
+                Main.ds.setSelected((Relation)displaylist.getSelectedValue());
+            }
+        }), GBC.std());
 
-		buttonPanel.add(new SideButton(marktr("Edit"), "edit", "Selection", tr( "Open an editor for the selected relation"), new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				Relation toEdit = (Relation) displaylist.getSelectedValue();
-				if (toEdit != null)
-					new RelationEditor(toEdit).setVisible(true);
-			}
-		}), GBC.std());
+        buttonPanel.add(new SideButton(marktr("Edit"), "edit", "Selection", tr( "Open an editor for the selected relation"), new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                Relation toEdit = (Relation) displaylist.getSelectedValue();
+                if (toEdit != null)
+                    new RelationEditor(toEdit).setVisible(true);
+            }
+        }), GBC.std());
 
-		buttonPanel.add(new SideButton(marktr("Delete"), "delete", "Selection", tr("Delete the selected relation"), new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				Relation toDelete = (Relation) displaylist.getSelectedValue();
-				if (toDelete != null) {
-					Main.main.undoRedo.add(
-						new DeleteCommand(Collections.singleton(toDelete)));
-				}
-			}
-		}), GBC.eol());
-		Layer.listeners.add(this);
-		add(buttonPanel, BorderLayout.SOUTH);
-	}
+        buttonPanel.add(new SideButton(marktr("Delete"), "delete", "Selection", tr("Delete the selected relation"), new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                Relation toDelete = (Relation) displaylist.getSelectedValue();
+                if (toDelete != null) {
+                    Main.main.undoRedo.add(
+                        new DeleteCommand(Collections.singleton(toDelete)));
+                }
+            }
+        }), GBC.eol());
+        Layer.listeners.add(this);
+        add(buttonPanel, BorderLayout.SOUTH);
+    }
 
-	@Override public void setVisible(boolean b) {
-		super.setVisible(b);
-		if (b) updateList();
-	}
+    @Override public void setVisible(boolean b) {
+        super.setVisible(b);
+        if (b) updateList();
+    }
 
-	public void updateList() {
-		list.setSize(Main.ds.relations.size());
-		int i = 0;
-		for (OsmPrimitive e : DataSet.sort(Main.ds.relations)) {
-			if (!e.deleted && !e.incomplete)
-				list.setElementAt(e, i++);
-		}
-		list.setSize(i);
-	}
+    public void updateList() {
+        list.setSize(Main.ds.relations.size());
+        int i = 0;
+        for (OsmPrimitive e : DataSet.sort(Main.ds.relations)) {
+            if (!e.deleted && !e.incomplete)
+                list.setElementAt(e, i++);
+        }
+        list.setSize(i);
+    }
 
-	public void activeLayerChange(Layer a, Layer b) {
-		if ((a == null || a instanceof OsmDataLayer) && b instanceof OsmDataLayer) {
-			if (a != null) ((OsmDataLayer)a).listenerDataChanged.remove(this);
-			((OsmDataLayer)b).listenerDataChanged.add(this);
-			updateList();
-			repaint();
-		}
-	}
+    public void activeLayerChange(Layer a, Layer b) {
+        if ((a == null || a instanceof OsmDataLayer) && b instanceof OsmDataLayer) {
+            if (a != null) ((OsmDataLayer)a).listenerDataChanged.remove(this);
+            ((OsmDataLayer)b).listenerDataChanged.add(this);
+            updateList();
+            repaint();
+        }
+    }
 
-	public void layerRemoved(Layer a) {
-		if (a instanceof OsmDataLayer) {
-			((OsmDataLayer)a).listenerDataChanged.remove(this);
-		}
-	}
-	public void layerAdded(Layer a) {
-		if (a instanceof OsmDataLayer) {
-			((OsmDataLayer)a).listenerDataChanged.add(this);
-		}
-	}
-	public void dataChanged(OsmDataLayer l) {
-		updateList();
-		repaint();
-	}
+    public void layerRemoved(Layer a) {
+        if (a instanceof OsmDataLayer) {
+            ((OsmDataLayer)a).listenerDataChanged.remove(this);
+        }
+    }
+    public void layerAdded(Layer a) {
+        if (a instanceof OsmDataLayer) {
+            ((OsmDataLayer)a).listenerDataChanged.add(this);
+        }
+    }
+    public void dataChanged(OsmDataLayer l) {
+        updateList();
+        repaint();
+    }
 
-	/**
-	 * Returns the currently selected relation, or null.
-	 *
-	 * @return the currently selected relation, or null
-	 */
-	public Relation getCurrentRelation() {
-		return (Relation) displaylist.getSelectedValue();
-	}
+    /**
+     * Returns the currently selected relation, or null.
+     *
+     * @return the currently selected relation, or null
+     */
+    public Relation getCurrentRelation() {
+        return (Relation) displaylist.getSelectedValue();
+    }
 
-	/**
-	 * Adds a selection listener to the relation list.
-	 *
-	 * @param listener the listener to add
-	 */
-	public void addListSelectionListener(ListSelectionListener listener) {
-		displaylist.addListSelectionListener(listener);
-	}
+    /**
+     * Adds a selection listener to the relation list.
+     *
+     * @param listener the listener to add
+     */
+    public void addListSelectionListener(ListSelectionListener listener) {
+        displaylist.addListSelectionListener(listener);
+    }
 
-	/**
-	 * Removes a selection listener from the relation list.
-	 *
-	 * @param listener the listener to remove
-	 */
-	public void removeListSelectionListener(ListSelectionListener listener) {
-		displaylist.removeListSelectionListener(listener);
-	}
+    /**
+     * Removes a selection listener from the relation list.
+     *
+     * @param listener the listener to remove
+     */
+    public void removeListSelectionListener(ListSelectionListener listener) {
+        displaylist.removeListSelectionListener(listener);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 1169)
@@ -36,116 +36,116 @@
 public class ToggleDialog extends JPanel implements Helpful {
 
-	public final class ToggleDialogAction extends JosmAction {
-		public final String prefname;
-		public AbstractButton button;
+    public final class ToggleDialogAction extends JosmAction {
+        public final String prefname;
+        public AbstractButton button;
 
-		private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
-			super(name, iconName, tooltip, shortcut, false);
-			this.prefname = prefname;
-		}
+        private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
+            super(name, iconName, tooltip, shortcut, false);
+            this.prefname = prefname;
+        }
 
-		public void actionPerformed(ActionEvent e) {
-			if (e != null && !(e.getSource() instanceof AbstractButton))
-				button.setSelected(!button.isSelected());
-			setVisible(button.isSelected());
-			Main.pref.put(prefname+".visible", button.isSelected());
-		}
-	}
+        public void actionPerformed(ActionEvent e) {
+            if (e != null && !(e.getSource() instanceof AbstractButton))
+                button.setSelected(!button.isSelected());
+            setVisible(button.isSelected());
+            Main.pref.put(prefname+".visible", button.isSelected());
+        }
+    }
 
-	/**
-	 * The action to toggle this dialog.
-	 */
-	public ToggleDialogAction action;
-	public final String prefName;
+    /**
+     * The action to toggle this dialog.
+     */
+    public ToggleDialogAction action;
+    public final String prefName;
 
-	public JPanel parent;
-	private final JPanel titleBar = new JPanel(new GridBagLayout());
+    public JPanel parent;
+    private final JPanel titleBar = new JPanel(new GridBagLayout());
 
-	@Deprecated
-	public ToggleDialog(final String name, String iconName, String tooltip, int shortcut, int preferredHeight) {
-		super(new BorderLayout());
-		this.prefName = iconName;
-		ToggleDialogInit(name, iconName, tooltip, Shortcut.registerShortcut("auto:"+name, tooltip, shortcut, Shortcut.GROUP_LAYER), preferredHeight);
-	}
+    @Deprecated
+    public ToggleDialog(final String name, String iconName, String tooltip, int shortcut, int preferredHeight) {
+        super(new BorderLayout());
+        this.prefName = iconName;
+        ToggleDialogInit(name, iconName, tooltip, Shortcut.registerShortcut("auto:"+name, tooltip, shortcut, Shortcut.GROUP_LAYER), preferredHeight);
+    }
 
-	public ToggleDialog(final String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
-		super(new BorderLayout());
-		this.prefName = iconName;
-		ToggleDialogInit(name, iconName, tooltip, shortcut, preferredHeight);
-	}
+    public ToggleDialog(final String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
+        super(new BorderLayout());
+        this.prefName = iconName;
+        ToggleDialogInit(name, iconName, tooltip, shortcut, preferredHeight);
+    }
 
-	private void ToggleDialogInit(final String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
-		setPreferredSize(new Dimension(330,preferredHeight));
-		action = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortcut, iconName);
-		String helpId = "Dialog/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
-		action.putValue("help", helpId.substring(0, helpId.length()-6));
-		setLayout(new BorderLayout());
+    private void ToggleDialogInit(final String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
+        setPreferredSize(new Dimension(330,preferredHeight));
+        action = new ToggleDialogAction(name, "dialogs/"+iconName, tooltip, shortcut, iconName);
+        String helpId = "Dialog/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
+        action.putValue("help", helpId.substring(0, helpId.length()-6));
+        setLayout(new BorderLayout());
 
-		titleBar.add(new JLabel(name), GBC.std());
-		titleBar.add(Box.createHorizontalGlue(),GBC.std().fill(GBC.HORIZONTAL));
+        titleBar.add(new JLabel(name), GBC.std());
+        titleBar.add(Box.createHorizontalGlue(),GBC.std().fill(GBC.HORIZONTAL));
 
-		JButton sticky = new JButton(ImageProvider.get("misc", "sticky"));
-		sticky.setBorder(BorderFactory.createEmptyBorder());
-		final ActionListener stickyActionListener = new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				final JFrame f = new JFrame(name);
-				try {f.setAlwaysOnTop(true);} catch (SecurityException e1) {}
-				parent.remove(ToggleDialog.this);
-				f.getContentPane().add(ToggleDialog.this);
-				f.addWindowListener(new WindowAdapter(){
-					@Override public void windowClosing(WindowEvent e) {
-						titleBar.setVisible(true);
-						f.getContentPane().removeAll();
-						parent.add(ToggleDialog.this);
-						f.dispose();
+        JButton sticky = new JButton(ImageProvider.get("misc", "sticky"));
+        sticky.setBorder(BorderFactory.createEmptyBorder());
+        final ActionListener stickyActionListener = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                final JFrame f = new JFrame(name);
+                try {f.setAlwaysOnTop(true);} catch (SecurityException e1) {}
+                parent.remove(ToggleDialog.this);
+                f.getContentPane().add(ToggleDialog.this);
+                f.addWindowListener(new WindowAdapter(){
+                    @Override public void windowClosing(WindowEvent e) {
+                        titleBar.setVisible(true);
+                        f.getContentPane().removeAll();
+                        parent.add(ToggleDialog.this);
+                        f.dispose();
 
-						// doLayout() - workaround
-						setVisible(false);
-						setVisible(true);
+                        // doLayout() - workaround
+                        setVisible(false);
+                        setVisible(true);
 
-						Main.pref.put(action.prefname+".docked", true);
-					}
-				});
-				f.addComponentListener(new ComponentAdapter(){
-					@Override public void componentMoved(ComponentEvent e) {
-						Main.pref.put(action.prefname+".bounds", f.getX()+","+f.getY()+","+f.getWidth()+","+f.getHeight());
+                        Main.pref.put(action.prefname+".docked", true);
                     }
-				});
-				String bounds = Main.pref.get(action.prefname+".bounds",null);
-				if (bounds != null) {
-					String[] b = bounds.split(",");
-					f.setBounds(Integer.parseInt(b[0]),Integer.parseInt(b[1]),Integer.parseInt(b[2]),Integer.parseInt(b[3]));
-				} else
-					f.pack();
-				Main.pref.put(action.prefname+".docked", false);
-				f.setVisible(true);
-				titleBar.setVisible(false);
+                });
+                f.addComponentListener(new ComponentAdapter(){
+                    @Override public void componentMoved(ComponentEvent e) {
+                        Main.pref.put(action.prefname+".bounds", f.getX()+","+f.getY()+","+f.getWidth()+","+f.getHeight());
+                    }
+                });
+                String bounds = Main.pref.get(action.prefname+".bounds",null);
+                if (bounds != null) {
+                    String[] b = bounds.split(",");
+                    f.setBounds(Integer.parseInt(b[0]),Integer.parseInt(b[1]),Integer.parseInt(b[2]),Integer.parseInt(b[3]));
+                } else
+                    f.pack();
+                Main.pref.put(action.prefname+".docked", false);
+                f.setVisible(true);
+                titleBar.setVisible(false);
 
-				// doLayout() - workaround
-				parent.setVisible(false);
-				parent.setVisible(true);
-			}
-		};
-		sticky.addActionListener(stickyActionListener);
+                // doLayout() - workaround
+                parent.setVisible(false);
+                parent.setVisible(true);
+            }
+        };
+        sticky.addActionListener(stickyActionListener);
 
-		titleBar.add(sticky);
-		add(titleBar, BorderLayout.NORTH);
+        titleBar.add(sticky);
+        add(titleBar, BorderLayout.NORTH);
 
-		setVisible(false);
-		setBorder(BorderFactory.createEtchedBorder());
+        setVisible(false);
+        setBorder(BorderFactory.createEtchedBorder());
 
-		if (!Main.pref.getBoolean(action.prefname+".docked", true)) {
-			EventQueue.invokeLater(new Runnable(){
-				public void run() {
-					stickyActionListener.actionPerformed(null);
+        if (!Main.pref.getBoolean(action.prefname+".docked", true)) {
+            EventQueue.invokeLater(new Runnable(){
+                public void run() {
+                    stickyActionListener.actionPerformed(null);
                 }
-			});
-		}
-	}
+            });
+        }
+    }
 
-	public String helpTopic() {
-		String help = getClass().getName();
-		help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
-		return "Dialog/"+help;
-	}
+    public String helpTopic() {
+        String help = getClass().getName();
+        help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
+        return "Dialog/"+help;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 1169)
@@ -34,60 +34,60 @@
 public class UserListDialog extends ToggleDialog implements SelectionChangedListener, MouseListener{
 
-	/**
-	 * The display list.
-	 */
-	private final DefaultTableModel data = new DefaultTableModel() {
-		@Override public boolean isCellEditable(int row, int column) {
-			return false;
-		}
-		@Override public Class<?> getColumnClass(int columnIndex) {
-			return columnIndex == 0 ? String.class : Integer.class;
-		}
-	};
+    /**
+     * The display list.
+     */
+    private final DefaultTableModel data = new DefaultTableModel() {
+        @Override public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+        @Override public Class<?> getColumnClass(int columnIndex) {
+            return columnIndex == 0 ? String.class : Integer.class;
+        }
+    };
 
-	private JTable userTable = new JTable(data);
+    private JTable userTable = new JTable(data);
 
     private static User anonymousUser = User.get("(anonymous users)");
 
-	public UserListDialog() {
-		super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."),
-		Shortcut.registerShortcut("subwindow:authors", tr("Toggle: {0}", tr("Authors")), KeyEvent.VK_A, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
+    public UserListDialog() {
+        super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."),
+        Shortcut.registerShortcut("subwindow:authors", tr("Toggle: {0}", tr("Authors")), KeyEvent.VK_A, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
 
-		data.setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
-		userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		add(new JScrollPane(userTable), BorderLayout.CENTER);
-		selectionChanged(Main.ds.getSelected());
-		userTable.addMouseListener(this);
-		DataSet.selListeners.add(this);
-	}
+        data.setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
+        userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        add(new JScrollPane(userTable), BorderLayout.CENTER);
+        selectionChanged(Main.ds.getSelected());
+        userTable.addMouseListener(this);
+        DataSet.selListeners.add(this);
+    }
 
-	@Override public void setVisible(boolean b) {
-		super.setVisible(b);
-		if (b)
-			selectionChanged(Main.ds.getSelected());
-	}
+    @Override public void setVisible(boolean b) {
+        super.setVisible(b);
+        if (b)
+            selectionChanged(Main.ds.getSelected());
+    }
 
-	/**
-	 * Called when the selection in the dataset changed.
-	 * @param newSelection The new selection array.
-	 */
-	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-		if (!isVisible())
-			return;
+    /**
+     * Called when the selection in the dataset changed.
+     * @param newSelection The new selection array.
+     */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        if (!isVisible())
+            return;
 
-		class UserCount {
-			User user;
-			int count;
-			UserCount(User user, int count) { this.user=user; this.count=count; }
-		}
+        class UserCount {
+            User user;
+            int count;
+            UserCount(User user, int count) { this.user=user; this.count=count; }
+        }
 
-		if (data == null)
-			return; // selection changed may be received in base class constructor before init
+        if (data == null)
+            return; // selection changed may be received in base class constructor before init
 
-		data.setRowCount(0);
+        data.setRowCount(0);
 
-		HashMap<User,UserCount> counters = new HashMap<User,UserCount>();
-		int all = 0;
-		for (OsmPrimitive p : newSelection) {
+        HashMap<User,UserCount> counters = new HashMap<User,UserCount>();
+        int all = 0;
+        for (OsmPrimitive p : newSelection) {
             User u = p.user;
             if (u == null) u = anonymousUser;
@@ -97,17 +97,17 @@
             uc.count++;
             all++;
-		}
-		UserCount[] ucArr = new UserCount[counters.size()];
-		counters.values().toArray(ucArr);
-		Arrays.sort(ucArr, new Comparator<UserCount>() {
-			public int compare(UserCount a, UserCount b) {
-				return (a.count<b.count) ? 1 : (a.count>b.count) ? -1 : 0;
-			}
-		});
+        }
+        UserCount[] ucArr = new UserCount[counters.size()];
+        counters.values().toArray(ucArr);
+        Arrays.sort(ucArr, new Comparator<UserCount>() {
+            public int compare(UserCount a, UserCount b) {
+                return (a.count<b.count) ? 1 : (a.count>b.count) ? -1 : 0;
+            }
+        });
 
-		for (UserCount uc : ucArr) {
-			data.addRow(new Object[] { uc.user.name, uc.count, uc.count * 100 / all });
-		}
-	}
+        for (UserCount uc : ucArr) {
+            data.addRow(new Object[] { uc.user.name, uc.count, uc.count * 100 / all });
+        }
+    }
 
     public void mouseClicked(MouseEvent e) {
@@ -115,5 +115,5 @@
             int index = userTable.getSelectedRow();
             String userName = (String) data.getValueAt(index, 0);
-            if (userName==null) 
+            if (userName==null)
                 return;
             Collection<OsmPrimitive> selected = Main.ds.getSelected();
Index: trunk/src/org/openstreetmap/josm/gui/download/BookmarkSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/BookmarkSelection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/BookmarkSelection.java	(revision 1169)
@@ -27,8 +27,8 @@
 /**
  * Bookmark selector.
- * 
+ *
  * Provides selection, creation and deletion of bookmarks.
  * Extracted from old DownloadAction.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -36,81 +36,81 @@
 public class BookmarkSelection implements DownloadSelection {
 
-	private Preferences.Bookmark tempBookmark = null;
-	private BookmarkList bookmarks; 
-	
-	public void addGui(final DownloadDialog gui) {
-		
-		JPanel dlg = new JPanel(new GridBagLayout());
-		gui.tabpane.addTab(tr("Bookmarks"), dlg);
+    private Preferences.Bookmark tempBookmark = null;
+    private BookmarkList bookmarks;
 
-		bookmarks = new BookmarkList();
-		
-		/* add a handler for "double click" mouse events */
-		MouseListener mouseListener = new MouseAdapter() {
-			@Override public void mouseClicked(MouseEvent e) {
-				if (e.getClickCount() == 2) {
-					//int index = bookmarks.locationToIndex(e.getPoint());
-					gui.closeDownloadDialog(true);
-				}
-			}
-		};
- 		bookmarks.addMouseListener(mouseListener);
-		
-		bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-			public void valueChanged(ListSelectionEvent e) {
-				Preferences.Bookmark b = (Preferences.Bookmark)bookmarks.getSelectedValue();
-				if (b != null) {
-					gui.minlat = b.latlon[0];
-					gui.minlon = b.latlon[1];
-					gui.maxlat = b.latlon[2];
-					gui.maxlon = b.latlon[3];
-					gui.boundingBoxChanged(BookmarkSelection.this);
-				}
-			}
-		});
-		//wc.addListMarker(bookmarks);
-		dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
+    public void addGui(final DownloadDialog gui) {
 
-		JPanel buttons = new JPanel(new GridLayout(1,2));
-		JButton add = new JButton(tr("Add"));
-		add.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				
-				if (tempBookmark == null) {
-					JOptionPane.showMessageDialog(Main.parent, tr("Please enter the desired coordinates first."));
-					return;
-				}
-				tempBookmark.name = JOptionPane.showInputDialog(Main.parent,tr("Please enter a name for the location."));
-				if (tempBookmark.name != null && !tempBookmark.name.equals("")) {
-					((DefaultListModel)bookmarks.getModel()).addElement(tempBookmark);
-					bookmarks.save();
-				}
-			}
-		});
-		buttons.add(add);
-		JButton remove = new JButton(tr("Remove"));
-		remove.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Object sel = bookmarks.getSelectedValue();
-				if (sel == null) {
-					JOptionPane.showMessageDialog(Main.parent,tr("Select a bookmark first."));
-					return;
-				}
-				((DefaultListModel)bookmarks.getModel()).removeElement(sel);
-				bookmarks.save();
-			}
-		});
-		buttons.add(remove);
-		dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
-	}		
+        JPanel dlg = new JPanel(new GridBagLayout());
+        gui.tabpane.addTab(tr("Bookmarks"), dlg);
 
-	public void boundingBoxChanged(DownloadDialog gui) {
-		tempBookmark = new Preferences.Bookmark();
-		tempBookmark.latlon[0] = gui.minlat;
-		tempBookmark.latlon[1] = gui.minlon;
-		tempBookmark.latlon[2] = gui.maxlat;
-		tempBookmark.latlon[3] = gui.maxlon;
-		bookmarks.clearSelection();
-	}
+        bookmarks = new BookmarkList();
+
+        /* add a handler for "double click" mouse events */
+        MouseListener mouseListener = new MouseAdapter() {
+            @Override public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    //int index = bookmarks.locationToIndex(e.getPoint());
+                    gui.closeDownloadDialog(true);
+                }
+            }
+        };
+        bookmarks.addMouseListener(mouseListener);
+
+        bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+            public void valueChanged(ListSelectionEvent e) {
+                Preferences.Bookmark b = (Preferences.Bookmark)bookmarks.getSelectedValue();
+                if (b != null) {
+                    gui.minlat = b.latlon[0];
+                    gui.minlon = b.latlon[1];
+                    gui.maxlat = b.latlon[2];
+                    gui.maxlon = b.latlon[3];
+                    gui.boundingBoxChanged(BookmarkSelection.this);
+                }
+            }
+        });
+        //wc.addListMarker(bookmarks);
+        dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
+
+        JPanel buttons = new JPanel(new GridLayout(1,2));
+        JButton add = new JButton(tr("Add"));
+        add.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+
+                if (tempBookmark == null) {
+                    JOptionPane.showMessageDialog(Main.parent, tr("Please enter the desired coordinates first."));
+                    return;
+                }
+                tempBookmark.name = JOptionPane.showInputDialog(Main.parent,tr("Please enter a name for the location."));
+                if (tempBookmark.name != null && !tempBookmark.name.equals("")) {
+                    ((DefaultListModel)bookmarks.getModel()).addElement(tempBookmark);
+                    bookmarks.save();
+                }
+            }
+        });
+        buttons.add(add);
+        JButton remove = new JButton(tr("Remove"));
+        remove.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                Object sel = bookmarks.getSelectedValue();
+                if (sel == null) {
+                    JOptionPane.showMessageDialog(Main.parent,tr("Select a bookmark first."));
+                    return;
+                }
+                ((DefaultListModel)bookmarks.getModel()).removeElement(sel);
+                bookmarks.save();
+            }
+        });
+        buttons.add(remove);
+        dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
+    }
+
+    public void boundingBoxChanged(DownloadDialog gui) {
+        tempBookmark = new Preferences.Bookmark();
+        tempBookmark.latlon[0] = gui.minlat;
+        tempBookmark.latlon[1] = gui.minlon;
+        tempBookmark.latlon[2] = gui.maxlat;
+        tempBookmark.latlon[3] = gui.maxlon;
+        bookmarks.clearSelection();
+    }
 
 
Index: trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 1169)
@@ -26,7 +26,7 @@
 /**
  * Bounding box selector.
- * 
+ *
  * Provides max/min lat/lon input fields as well as the "URL from www.openstreetmap.org" text field.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -34,175 +34,175 @@
 public class BoundingBoxSelection implements DownloadSelection {
 
-	private JTextField[] latlon = new JTextField[] {
-			new JTextField(11),
-			new JTextField(11),
-			new JTextField(11),
-			new JTextField(11) };
-	final JTextArea osmUrl = new JTextArea();
-	final JTextArea showUrl = new JTextArea();
-	String noteUrl = tr("You can paste an URL here to download the area.");
-	
-	public void addGui(final DownloadDialog gui) {
-
-		JPanel dlg = new JPanel(new GridBagLayout());
-		osmUrl.setText(noteUrl);
-
-		final FocusListener dialogUpdater = new FocusAdapter() {
-			@Override public void focusLost(FocusEvent e) {
-				SwingUtilities.invokeLater(new Runnable() {
-					public void run() {
-						try {
-							double minlat = Double.parseDouble(latlon[0].getText());
-							double minlon = Double.parseDouble(latlon[1].getText());
-							double maxlat = Double.parseDouble(latlon[2].getText());
-							double maxlon = Double.parseDouble(latlon[3].getText());
-							if (minlat != gui.minlat || minlon != gui.minlon || maxlat != gui.maxlat || maxlon != gui.maxlon) {
-								gui.minlat = minlat; gui.minlon = minlon; 
-								gui.maxlat = maxlat; gui.maxlon = maxlon;
-								gui.boundingBoxChanged(BoundingBoxSelection.this);
-							}
-						} catch (NumberFormatException x) {
-							// ignore
-						}
-						updateUrl(gui);
-					}
-				});
-			}
-		};
-		
-		for (JTextField f : latlon) {
-			f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
-			f.addFocusListener(dialogUpdater);
-		}
-		class osmUrlRefresher implements DocumentListener {
-			public void changedUpdate(DocumentEvent e) { dowork(); }
-			public void insertUpdate(DocumentEvent e) { dowork(); }
-			public void removeUpdate(DocumentEvent e) { dowork(); }
-			private void dowork() {
-				Bounds b = osmurl2bounds(osmUrl.getText());
-				if (b != null) {
-					gui.minlon = b.min.lon();
-					gui.minlat = b.min.lat();
-					gui.maxlon = b.max.lon();
-					gui.maxlat = b.max.lat();
-					gui.boundingBoxChanged(BoundingBoxSelection.this);
-					updateBboxFields(gui);
-					updateUrl(gui);
-				}
-			}
-		}
-		
-		osmUrl.getDocument().addDocumentListener(new osmUrlRefresher());
-		
-		// select content on receiving focus. this seems to be the default in the
-		// windows look+feel but not for others. needs invokeLater to avoid strange
-		// side effects that will cancel out the newly made selection otherwise.
-		osmUrl.addFocusListener(new FocusAdapter() {
-			@Override public void focusGained(FocusEvent e) {
-		        SwingUtilities.invokeLater(new Runnable() {
-		                public void run() {
-		                	osmUrl.selectAll();
-		        		}
-				});
-			}
-		});
-		osmUrl.setLineWrap(true);
-		osmUrl.setBorder(latlon[0].getBorder());
-		
-		dlg.add(new JLabel(tr("min lat")), GBC.std().insets(10,20,5,0));
-		dlg.add(latlon[0], GBC.std().insets(0,20,0,0));
-		dlg.add(new JLabel(tr("min lon")), GBC.std().insets(10,20,5,0));
-		dlg.add(latlon[1], GBC.eol().insets(0,20,0,0));
-		dlg.add(new JLabel(tr("max lat")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[2], GBC.std());
-		dlg.add(new JLabel(tr("max lon")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[3], GBC.eol());
-		
-		dlg.add(new JLabel(tr("URL from www.openstreetmap.org")), GBC.eol().insets(10,20,5,0));
-		dlg.add(osmUrl, GBC.eop().insets(10,0,5,0).fill());
-		dlg.add(showUrl, GBC.eop().insets(10,0,5,5));
-		showUrl.setEditable(false);
-		showUrl.setBackground(dlg.getBackground());
-		showUrl.addFocusListener(new FocusAdapter(){
-		   @Override
-		    public void focusGained(FocusEvent e) {
-		        showUrl.selectAll();
-		    } 
-		});
-
-		gui.tabpane.addTab(tr("Bounding Box"), dlg);
-	}
-	
-	/**
-	 * Called when bounding box is changed by one of the other download dialog tabs.
-	 */
-	public void boundingBoxChanged(DownloadDialog gui) {
-		updateBboxFields(gui);
-		updateUrl(gui);
-	}
-	
-	private void updateBboxFields(DownloadDialog gui) {
-		latlon[0].setText(Double.toString(gui.minlat));
-		latlon[1].setText(Double.toString(gui.minlon));
-		latlon[2].setText(Double.toString(gui.maxlat));
-		latlon[3].setText(Double.toString(gui.maxlon));
-		for (JTextField f : latlon) 
-			f.setCaretPosition(0);
-	}
-	
-	private void updateUrl(DownloadDialog gui) {	
-		double lat = (gui.minlat + gui.maxlat)/2;
-		double lon = (gui.minlon + gui.maxlon)/2;
-		// convert to mercator (for calculation of zoom only)
-		double latMin = Math.log(Math.tan(Math.PI/4.0+gui.minlat/180.0*Math.PI/2.0))*180.0/Math.PI;
-		double latMax = Math.log(Math.tan(Math.PI/4.0+gui.maxlat/180.0*Math.PI/2.0))*180.0/Math.PI;
-		double size = Math.max(Math.abs(latMax-latMin), Math.abs(gui.maxlon-gui.minlon));
-		int zoom = 0;
-		while (zoom <= 20) {
-			if (size >= 180)
-				break;
-			size *= 2;
-			zoom++;
-		}
-		showUrl.setText("http://www.openstreetmap.org/index.html?mlat="+lat+"&mlon="+lon+"&zoom="+zoom);
-	}
-	
-	public static Bounds osmurl2bounds(String url) {
-		int i = url.indexOf('?');
-		if (i == -1)
-			return null;
-		String[] args = url.substring(i+1).split("&");
-		HashMap<String, String> map = new HashMap<String, String>();
-		for (String arg : args) {
-			int eq = arg.indexOf('=');
-			if (eq != -1) {
-				map.put(arg.substring(0, eq), arg.substring(eq + 1));
-			}
-		}
-
-		Bounds b = null;
-		try {
-			if (map.containsKey("bbox")) {
-				String bbox[] = map.get("bbox").split(",");
-				b = new Bounds(
-					new LatLon(Double.parseDouble(bbox[1]), Double.parseDouble(bbox[0])),
-					new LatLon(Double.parseDouble(bbox[3]), Double.parseDouble(bbox[2])));
-			
-			} else {
-				double size = 180.0 / Math.pow(2, Integer.parseInt(map.get("zoom")));
-				b = new Bounds(
-	            	new LatLon(parseDouble(map, "lat") - size/2, parseDouble(map, "lon") - size),
-	            	new LatLon(parseDouble(map, "lat") + size/2, parseDouble(map, "lon") + size));
-			}
-		} catch (NumberFormatException x) {
-		} catch (NullPointerException x) {
-		}
-		return b;
-	}
-
-	private static double parseDouble(HashMap<String, String> map, String key) {
-		if (map.containsKey(key))
-			return Double.parseDouble(map.get(key));
-		return Double.parseDouble(map.get("m"+key));
+    private JTextField[] latlon = new JTextField[] {
+            new JTextField(11),
+            new JTextField(11),
+            new JTextField(11),
+            new JTextField(11) };
+    final JTextArea osmUrl = new JTextArea();
+    final JTextArea showUrl = new JTextArea();
+    String noteUrl = tr("You can paste an URL here to download the area.");
+
+    public void addGui(final DownloadDialog gui) {
+
+        JPanel dlg = new JPanel(new GridBagLayout());
+        osmUrl.setText(noteUrl);
+
+        final FocusListener dialogUpdater = new FocusAdapter() {
+            @Override public void focusLost(FocusEvent e) {
+                SwingUtilities.invokeLater(new Runnable() {
+                    public void run() {
+                        try {
+                            double minlat = Double.parseDouble(latlon[0].getText());
+                            double minlon = Double.parseDouble(latlon[1].getText());
+                            double maxlat = Double.parseDouble(latlon[2].getText());
+                            double maxlon = Double.parseDouble(latlon[3].getText());
+                            if (minlat != gui.minlat || minlon != gui.minlon || maxlat != gui.maxlat || maxlon != gui.maxlon) {
+                                gui.minlat = minlat; gui.minlon = minlon;
+                                gui.maxlat = maxlat; gui.maxlon = maxlon;
+                                gui.boundingBoxChanged(BoundingBoxSelection.this);
+                            }
+                        } catch (NumberFormatException x) {
+                            // ignore
+                        }
+                        updateUrl(gui);
+                    }
+                });
+            }
+        };
+
+        for (JTextField f : latlon) {
+            f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
+            f.addFocusListener(dialogUpdater);
+        }
+        class osmUrlRefresher implements DocumentListener {
+            public void changedUpdate(DocumentEvent e) { dowork(); }
+            public void insertUpdate(DocumentEvent e) { dowork(); }
+            public void removeUpdate(DocumentEvent e) { dowork(); }
+            private void dowork() {
+                Bounds b = osmurl2bounds(osmUrl.getText());
+                if (b != null) {
+                    gui.minlon = b.min.lon();
+                    gui.minlat = b.min.lat();
+                    gui.maxlon = b.max.lon();
+                    gui.maxlat = b.max.lat();
+                    gui.boundingBoxChanged(BoundingBoxSelection.this);
+                    updateBboxFields(gui);
+                    updateUrl(gui);
+                }
+            }
+        }
+
+        osmUrl.getDocument().addDocumentListener(new osmUrlRefresher());
+
+        // select content on receiving focus. this seems to be the default in the
+        // windows look+feel but not for others. needs invokeLater to avoid strange
+        // side effects that will cancel out the newly made selection otherwise.
+        osmUrl.addFocusListener(new FocusAdapter() {
+            @Override public void focusGained(FocusEvent e) {
+                SwingUtilities.invokeLater(new Runnable() {
+                        public void run() {
+                            osmUrl.selectAll();
+                        }
+                });
+            }
+        });
+        osmUrl.setLineWrap(true);
+        osmUrl.setBorder(latlon[0].getBorder());
+
+        dlg.add(new JLabel(tr("min lat")), GBC.std().insets(10,20,5,0));
+        dlg.add(latlon[0], GBC.std().insets(0,20,0,0));
+        dlg.add(new JLabel(tr("min lon")), GBC.std().insets(10,20,5,0));
+        dlg.add(latlon[1], GBC.eol().insets(0,20,0,0));
+        dlg.add(new JLabel(tr("max lat")), GBC.std().insets(10,0,5,0));
+        dlg.add(latlon[2], GBC.std());
+        dlg.add(new JLabel(tr("max lon")), GBC.std().insets(10,0,5,0));
+        dlg.add(latlon[3], GBC.eol());
+
+        dlg.add(new JLabel(tr("URL from www.openstreetmap.org")), GBC.eol().insets(10,20,5,0));
+        dlg.add(osmUrl, GBC.eop().insets(10,0,5,0).fill());
+        dlg.add(showUrl, GBC.eop().insets(10,0,5,5));
+        showUrl.setEditable(false);
+        showUrl.setBackground(dlg.getBackground());
+        showUrl.addFocusListener(new FocusAdapter(){
+           @Override
+            public void focusGained(FocusEvent e) {
+                showUrl.selectAll();
+            }
+        });
+
+        gui.tabpane.addTab(tr("Bounding Box"), dlg);
+    }
+
+    /**
+     * Called when bounding box is changed by one of the other download dialog tabs.
+     */
+    public void boundingBoxChanged(DownloadDialog gui) {
+        updateBboxFields(gui);
+        updateUrl(gui);
+    }
+
+    private void updateBboxFields(DownloadDialog gui) {
+        latlon[0].setText(Double.toString(gui.minlat));
+        latlon[1].setText(Double.toString(gui.minlon));
+        latlon[2].setText(Double.toString(gui.maxlat));
+        latlon[3].setText(Double.toString(gui.maxlon));
+        for (JTextField f : latlon)
+            f.setCaretPosition(0);
+    }
+
+    private void updateUrl(DownloadDialog gui) {
+        double lat = (gui.minlat + gui.maxlat)/2;
+        double lon = (gui.minlon + gui.maxlon)/2;
+        // convert to mercator (for calculation of zoom only)
+        double latMin = Math.log(Math.tan(Math.PI/4.0+gui.minlat/180.0*Math.PI/2.0))*180.0/Math.PI;
+        double latMax = Math.log(Math.tan(Math.PI/4.0+gui.maxlat/180.0*Math.PI/2.0))*180.0/Math.PI;
+        double size = Math.max(Math.abs(latMax-latMin), Math.abs(gui.maxlon-gui.minlon));
+        int zoom = 0;
+        while (zoom <= 20) {
+            if (size >= 180)
+                break;
+            size *= 2;
+            zoom++;
+        }
+        showUrl.setText("http://www.openstreetmap.org/index.html?mlat="+lat+"&mlon="+lon+"&zoom="+zoom);
+    }
+
+    public static Bounds osmurl2bounds(String url) {
+        int i = url.indexOf('?');
+        if (i == -1)
+            return null;
+        String[] args = url.substring(i+1).split("&");
+        HashMap<String, String> map = new HashMap<String, String>();
+        for (String arg : args) {
+            int eq = arg.indexOf('=');
+            if (eq != -1) {
+                map.put(arg.substring(0, eq), arg.substring(eq + 1));
+            }
+        }
+
+        Bounds b = null;
+        try {
+            if (map.containsKey("bbox")) {
+                String bbox[] = map.get("bbox").split(",");
+                b = new Bounds(
+                    new LatLon(Double.parseDouble(bbox[1]), Double.parseDouble(bbox[0])),
+                    new LatLon(Double.parseDouble(bbox[3]), Double.parseDouble(bbox[2])));
+
+            } else {
+                double size = 180.0 / Math.pow(2, Integer.parseInt(map.get("zoom")));
+                b = new Bounds(
+                    new LatLon(parseDouble(map, "lat") - size/2, parseDouble(map, "lon") - size),
+                    new LatLon(parseDouble(map, "lat") + size/2, parseDouble(map, "lon") + size));
+            }
+        } catch (NumberFormatException x) {
+        } catch (NullPointerException x) {
+        }
+        return b;
+    }
+
+    private static double parseDouble(HashMap<String, String> map, String key) {
+        if (map.containsKey(key))
+            return Double.parseDouble(map.get(key));
+        return Double.parseDouble(map.get("m"+key));
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 1169)
@@ -36,163 +36,163 @@
 public class DownloadDialog extends JPanel {
 
-	// the JOptionPane that contains this dialog. required for the closeDialog() method.
-	private JOptionPane optionPane;
+    // the JOptionPane that contains this dialog. required for the closeDialog() method.
+    private JOptionPane optionPane;
 
-	public interface DownloadTask {
-		/**
-		 * Execute the download.
-		 */
-		void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon);
+    public interface DownloadTask {
+        /**
+         * Execute the download.
+         */
+        void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon);
         void loadUrl(boolean newLayer, String url);
-		/**
-		 * @return The checkbox presented to the user
-		 */
-		JCheckBox getCheckBox();
-		/**
-		 * @return The name of the preferences suffix to use for storing the
-		 * selection state.
-		 */
-		String getPreferencesSuffix();
-	}
+        /**
+         * @return The checkbox presented to the user
+         */
+        JCheckBox getCheckBox();
+        /**
+         * @return The name of the preferences suffix to use for storing the
+         * selection state.
+         */
+        String getPreferencesSuffix();
+    }
 
-	/**
-	 * The list of download tasks. First entry should be the osm data entry
-	 * and the second the gps entry. After that, plugins can register additional
-	 * download possibilities.
-	 */
-	public final List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>(5);
+    /**
+     * The list of download tasks. First entry should be the osm data entry
+     * and the second the gps entry. After that, plugins can register additional
+     * download possibilities.
+     */
+    public final List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>(5);
 
-	public final List<DownloadSelection> downloadSelections = new ArrayList<DownloadSelection>();
-	public final JTabbedPane tabpane = new JTabbedPane();
-	public final JCheckBox newLayer;
-	public final JLabel sizeCheck = new JLabel();
+    public final List<DownloadSelection> downloadSelections = new ArrayList<DownloadSelection>();
+    public final JTabbedPane tabpane = new JTabbedPane();
+    public final JCheckBox newLayer;
+    public final JLabel sizeCheck = new JLabel();
 
-	public double minlon;
-	public double minlat;
-	public double maxlon;
-	public double maxlat;
+    public double minlon;
+    public double minlat;
+    public double maxlon;
+    public double maxlat;
 
 
-	public DownloadDialog() {
-		setLayout(new GridBagLayout());
+    public DownloadDialog() {
+        setLayout(new GridBagLayout());
 
-		downloadTasks.add(new DownloadOsmTask());
-		downloadTasks.add(new DownloadGpsTask());
+        downloadTasks.add(new DownloadOsmTask());
+        downloadTasks.add(new DownloadGpsTask());
 
-		// adding the download tasks
-		add(new JLabel(tr("Data Sources and Types")), GBC.eol().insets(0,5,0,0));
-		for (DownloadTask task : downloadTasks) {
-			add(task.getCheckBox(), GBC.eol().insets(20,0,0,0));
-			// don't override defaults, if we (initially) don't have any preferences
-			if(Main.pref.hasKey("download."+task.getPreferencesSuffix())) {
-				task.getCheckBox().setSelected(Main.pref.getBoolean("download."+task.getPreferencesSuffix()));
-			}
-		}
+        // adding the download tasks
+        add(new JLabel(tr("Data Sources and Types")), GBC.eol().insets(0,5,0,0));
+        for (DownloadTask task : downloadTasks) {
+            add(task.getCheckBox(), GBC.eol().insets(20,0,0,0));
+            // don't override defaults, if we (initially) don't have any preferences
+            if(Main.pref.hasKey("download."+task.getPreferencesSuffix())) {
+                task.getCheckBox().setSelected(Main.pref.getBoolean("download."+task.getPreferencesSuffix()));
+            }
+        }
 
-		// predefined download selections
-		downloadSelections.add(new BoundingBoxSelection());
-		downloadSelections.add(new TileSelection());
-		downloadSelections.add(new BookmarkSelection());
-		downloadSelections.add(new WorldChooser());
+        // predefined download selections
+        downloadSelections.add(new BoundingBoxSelection());
+        downloadSelections.add(new TileSelection());
+        downloadSelections.add(new BookmarkSelection());
+        downloadSelections.add(new WorldChooser());
 
-		// add selections from plugins
-		for (PluginProxy p : Main.plugins) {
-			p.addDownloadSelection(downloadSelections);
-		}
+        // add selections from plugins
+        for (PluginProxy p : Main.plugins) {
+            p.addDownloadSelection(downloadSelections);
+        }
 
-		// now everybody may add their tab to the tabbed pane
-		// (not done right away to allow plugins to remove one of
-		// the default selectors!)
-		for (DownloadSelection s : downloadSelections) {
-			s.addGui(this);
-		}
+        // now everybody may add their tab to the tabbed pane
+        // (not done right away to allow plugins to remove one of
+        // the default selectors!)
+        for (DownloadSelection s : downloadSelections) {
+            s.addGui(this);
+        }
 
-		if (Main.map != null) {
-			MapView mv = Main.map.mapView;
-			minlon = mv.getLatLon(0, mv.getHeight()).lon();
-			minlat = mv.getLatLon(0, mv.getHeight()).lat();
-			maxlon = mv.getLatLon(mv.getWidth(), 0).lon();
-			maxlat = mv.getLatLon(mv.getWidth(), 0).lat();
-			boundingBoxChanged(null);
-		}
-		else if (Main.pref.hasKey("osm-download.bounds")) {
-			// read the bounding box from the preferences
-			try {
-				String bounds[] = Main.pref.get("osm-download.bounds").split(";");
-				minlat = Double.parseDouble(bounds[0]);
-				minlon = Double.parseDouble(bounds[1]);
-				maxlat = Double.parseDouble(bounds[2]);
-				maxlon = Double.parseDouble(bounds[3]);
-				boundingBoxChanged(null);
-			}
-			catch (Exception e) {
-				e.printStackTrace();
-			}
-		}
+        if (Main.map != null) {
+            MapView mv = Main.map.mapView;
+            minlon = mv.getLatLon(0, mv.getHeight()).lon();
+            minlat = mv.getLatLon(0, mv.getHeight()).lat();
+            maxlon = mv.getLatLon(mv.getWidth(), 0).lon();
+            maxlat = mv.getLatLon(mv.getWidth(), 0).lat();
+            boundingBoxChanged(null);
+        }
+        else if (Main.pref.hasKey("osm-download.bounds")) {
+            // read the bounding box from the preferences
+            try {
+                String bounds[] = Main.pref.get("osm-download.bounds").split(";");
+                minlat = Double.parseDouble(bounds[0]);
+                minlon = Double.parseDouble(bounds[1]);
+                maxlat = Double.parseDouble(bounds[2]);
+                maxlon = Double.parseDouble(bounds[3]);
+                boundingBoxChanged(null);
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
 
-		newLayer = new JCheckBox(tr("Download as new layer"), Main.pref.getBoolean("download.newlayer", false));
-		add(newLayer, GBC.eol().insets(0,5,0,0));
+        newLayer = new JCheckBox(tr("Download as new layer"), Main.pref.getBoolean("download.newlayer", false));
+        add(newLayer, GBC.eol().insets(0,5,0,0));
 
-		add(new JLabel(tr("Download Area")), GBC.eol().insets(0,5,0,0));
-		add(tabpane, GBC.eol().fill());
+        add(new JLabel(tr("Download Area")), GBC.eol().insets(0,5,0,0));
+        add(tabpane, GBC.eol().fill());
 
-		try {
-			tabpane.setSelectedIndex(Integer.parseInt(Main.pref.get("download.tab", "0")));
-		} catch (Exception ex) {
-			Main.pref.put("download.tab", "0");
-		}
+        try {
+            tabpane.setSelectedIndex(Integer.parseInt(Main.pref.get("download.tab", "0")));
+        } catch (Exception ex) {
+            Main.pref.put("download.tab", "0");
+        }
 
-		Font labelFont = sizeCheck.getFont();
-		sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
-		add(sizeCheck, GBC.eop().insets(0,5,5,10));
-	}
+        Font labelFont = sizeCheck.getFont();
+        sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
+        add(sizeCheck, GBC.eop().insets(0,5,5,10));
+    }
 
-	private void updateSizeCheck() {
-		if ((maxlon-minlon)*(maxlat-minlat) > Main.pref.getDouble("osm-server.max-request-area", 0.25)) {
-			sizeCheck.setText(tr("Download area too large; will probably be rejected by server"));
-			sizeCheck.setForeground(Color.red);
-		} else {
-			sizeCheck.setText(tr("Download area ok, size probably acceptable to server"));
-			sizeCheck.setForeground(Color.darkGray);
-		}
-	}
+    private void updateSizeCheck() {
+        if ((maxlon-minlon)*(maxlat-minlat) > Main.pref.getDouble("osm-server.max-request-area", 0.25)) {
+            sizeCheck.setText(tr("Download area too large; will probably be rejected by server"));
+            sizeCheck.setForeground(Color.red);
+        } else {
+            sizeCheck.setText(tr("Download area ok, size probably acceptable to server"));
+            sizeCheck.setForeground(Color.darkGray);
+        }
+    }
 
-	/**
-	 * Distributes a "bounding box changed" from one DownloadSelection
-	 * object to the others, so they may update or clear their input
-	 * fields.
-	 *
-	 * @param eventSource - the DownloadSelection object that fired this notification.
-	 */
-	public void boundingBoxChanged(DownloadSelection eventSource) {
-		for (DownloadSelection s : downloadSelections) {
-			if (s != eventSource) s.boundingBoxChanged(this);
-		}
-		updateSizeCheck();
-	}
+    /**
+     * Distributes a "bounding box changed" from one DownloadSelection
+     * object to the others, so they may update or clear their input
+     * fields.
+     *
+     * @param eventSource - the DownloadSelection object that fired this notification.
+     */
+    public void boundingBoxChanged(DownloadSelection eventSource) {
+        for (DownloadSelection s : downloadSelections) {
+            if (s != eventSource) s.boundingBoxChanged(this);
+        }
+        updateSizeCheck();
+    }
 
-	/*
-	 * Returns currently selected tab.
-	 */
-	public int getSelectedTab() {
-		return tabpane.getSelectedIndex();
-	}
+    /*
+     * Returns currently selected tab.
+     */
+    public int getSelectedTab() {
+        return tabpane.getSelectedIndex();
+    }
 
-	/**
-	 * Closes the download dialog. This is intended to be called by one of
-	 * the various download area selection "plugins".
-	 *
-	 * @param download true to download selected data, false to cancel download
-	 */
-	public void closeDownloadDialog(boolean download) {
-		optionPane.setValue(download ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION);
-	}
+    /**
+     * Closes the download dialog. This is intended to be called by one of
+     * the various download area selection "plugins".
+     *
+     * @param download true to download selected data, false to cancel download
+     */
+    public void closeDownloadDialog(boolean download) {
+        optionPane.setValue(download ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION);
+    }
 
-	/**
-	 * Has to be called after this dialog has been added to a JOptionPane.
-	 * @param optionPane
-	 */
-	public void setOptionPane(JOptionPane optionPane) {
-		this.optionPane = optionPane;
-	}
+    /**
+     * Has to be called after this dialog has been added to a JOptionPane.
+     * @param optionPane
+     */
+    public void setOptionPane(JOptionPane optionPane) {
+        this.optionPane = optionPane;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/DownloadSelection.java	(revision 1169)
@@ -4,14 +4,14 @@
 
 public interface DownloadSelection {
-	/**
-	 * Add the GUI elements to the dialog. 
-	 */
-	void addGui(DownloadDialog gui);
+    /**
+     * Add the GUI elements to the dialog.
+     */
+    void addGui(DownloadDialog gui);
 
-	/** 
-	 * Update or clear display when a selection is made through another
-	 * DownloadSelection object
-	 */
-	void boundingBoxChanged(DownloadDialog gui);
-	
+    /**
+     * Update or clear display when a selection is made through another
+     * DownloadSelection object
+     */
+    void boundingBoxChanged(DownloadDialog gui);
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/download/TileSelection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/TileSelection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/TileSelection.java	(revision 1169)
@@ -19,7 +19,7 @@
 /**
  * Tile selector.
- * 
+ *
  * Provides a tile coordinate input field.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -27,98 +27,98 @@
 public class TileSelection implements DownloadSelection {
 
-	private JTextField tileX0 = new JTextField(7);
-	private JTextField tileY0 = new JTextField(7);
-	private JTextField tileX1 = new JTextField(7);
-	private JTextField tileY1 = new JTextField(7);
-	private JSpinner tileZ = new JSpinner(new SpinnerNumberModel(12, 10, 18, 1));
-	
-	public void addGui(final DownloadDialog gui) {
+    private JTextField tileX0 = new JTextField(7);
+    private JTextField tileY0 = new JTextField(7);
+    private JTextField tileX1 = new JTextField(7);
+    private JTextField tileY1 = new JTextField(7);
+    private JSpinner tileZ = new JSpinner(new SpinnerNumberModel(12, 10, 18, 1));
 
-		JPanel smpanel = new JPanel(new GridBagLayout());
-		smpanel.add(new JLabel(tr("zoom level")), GBC.std().insets(0,0,10,0));
-		smpanel.add(new JLabel(tr("x from")), GBC.std().insets(10,0,5,0));
-		smpanel.add(tileX0, GBC.std());
-		smpanel.add(new JLabel(tr("to")), GBC.std().insets(10,0,5,0));
-		smpanel.add(tileX1, GBC.eol());
-		smpanel.add(tileZ, GBC.std().insets(0,0,10,0));
-		smpanel.add(new JLabel(tr("y from")), GBC.std().insets(10,0,5,0));
-		smpanel.add(tileY0, GBC.std());
-		smpanel.add(new JLabel(tr("to")), GBC.std().insets(10,0,5,0));
-		smpanel.add(tileY1, GBC.eol());
+    public void addGui(final DownloadDialog gui) {
 
-		final FocusListener dialogUpdater = new FocusAdapter() {
-			@Override public void focusLost(FocusEvent e) {
-				try {
-					int zoomlvl = (Integer) tileZ.getValue();
-					int fromx = Integer.parseInt(tileX0.getText());
-					int tox = fromx;
-					if (tileX1.getText().length()>0) {
-						tox = Integer.parseInt(tileX1.getText());
-					}
-					if (tox<fromx) { int i = fromx; fromx=tox; tox=i; }
+        JPanel smpanel = new JPanel(new GridBagLayout());
+        smpanel.add(new JLabel(tr("zoom level")), GBC.std().insets(0,0,10,0));
+        smpanel.add(new JLabel(tr("x from")), GBC.std().insets(10,0,5,0));
+        smpanel.add(tileX0, GBC.std());
+        smpanel.add(new JLabel(tr("to")), GBC.std().insets(10,0,5,0));
+        smpanel.add(tileX1, GBC.eol());
+        smpanel.add(tileZ, GBC.std().insets(0,0,10,0));
+        smpanel.add(new JLabel(tr("y from")), GBC.std().insets(10,0,5,0));
+        smpanel.add(tileY0, GBC.std());
+        smpanel.add(new JLabel(tr("to")), GBC.std().insets(10,0,5,0));
+        smpanel.add(tileY1, GBC.eol());
 
-					int fromy = Integer.parseInt(tileY0.getText());
-					int toy = fromy;
-					if (tileY1.getText().length()>0) {
-						toy = Integer.parseInt(tileY1.getText());
-					}
-					if (toy<fromy) { int i = fromy; fromy=toy; toy=i; }
+        final FocusListener dialogUpdater = new FocusAdapter() {
+            @Override public void focusLost(FocusEvent e) {
+                try {
+                    int zoomlvl = (Integer) tileZ.getValue();
+                    int fromx = Integer.parseInt(tileX0.getText());
+                    int tox = fromx;
+                    if (tileX1.getText().length()>0) {
+                        tox = Integer.parseInt(tileX1.getText());
+                    }
+                    if (tox<fromx) { int i = fromx; fromx=tox; tox=i; }
 
-					gui.minlat = tileYToLat(zoomlvl, toy+1);
-					gui.minlon = tileXToLon(zoomlvl, fromx);
-					gui.maxlat = tileYToLat(zoomlvl, fromy);
-					gui.maxlon = tileXToLon(zoomlvl, tox+1);
-					gui.boundingBoxChanged(TileSelection.this);
-					//repaint();
-				} catch (NumberFormatException x) {
-					// ignore
-				}
-			}
-		};
-		
-		for (JTextField f : new JTextField[] { tileX0, tileX1, tileY0, tileY1 }) {
-			f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
-			f.addFocusListener(dialogUpdater);
-		}
+                    int fromy = Integer.parseInt(tileY0.getText());
+                    int toy = fromy;
+                    if (tileY1.getText().length()>0) {
+                        toy = Integer.parseInt(tileY1.getText());
+                    }
+                    if (toy<fromy) { int i = fromy; fromy=toy; toy=i; }
 
-		gui.tabpane.addTab(tr("Tile Numbers"), smpanel);
-	}
-	
-	/**
-	 * Called when bounding box is changed by one of the other download dialog tabs.
-	 */
-	public void boundingBoxChanged(DownloadDialog gui) {
-		updateBboxFields(gui);
-	}
-	
-	private void updateBboxFields(DownloadDialog gui) {
-		int z = ((Integer) tileZ.getValue()).intValue();
-		tileX0.setText(Integer.toString(lonToTileX(z, gui.minlon)));
-		tileX1.setText(Integer.toString(lonToTileX(z, gui.maxlon-.00001)));
-		tileY0.setText(Integer.toString(latToTileY(z, gui.maxlat-.00001)));
-		tileY1.setText(Integer.toString(latToTileY(z, gui.minlat)));
-	}
-	
-	public static int latToTileY(int zoom, double lat) {
-		if ((zoom < 3) || (zoom > 18)) return -1; 
-		double l = lat / 180 * Math.PI;
-		double pf = Math.log(Math.tan(l) + (1/Math.cos(l)));
-		return (int) ((1<<(zoom-1)) * (Math.PI - pf) / Math.PI);
-	}   
+                    gui.minlat = tileYToLat(zoomlvl, toy+1);
+                    gui.minlon = tileXToLon(zoomlvl, fromx);
+                    gui.maxlat = tileYToLat(zoomlvl, fromy);
+                    gui.maxlon = tileXToLon(zoomlvl, tox+1);
+                    gui.boundingBoxChanged(TileSelection.this);
+                    //repaint();
+                } catch (NumberFormatException x) {
+                    // ignore
+                }
+            }
+        };
 
-	public static int lonToTileX(int zoom, double lon) {
-		if ((zoom < 3) || (zoom > 18)) return -1; 
-		return (int) ((1<<(zoom-3)) * (lon + 180.0) / 45.0);
-	}
+        for (JTextField f : new JTextField[] { tileX0, tileX1, tileY0, tileY1 }) {
+            f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
+            f.addFocusListener(dialogUpdater);
+        }
 
-	public static double tileYToLat(int zoom, int y) {
-		if ((zoom < 3) || (zoom > 18)) return Double.MIN_VALUE;
-		return Math.atan(Math.sinh(Math.PI - (Math.PI*y / (1<<(zoom-1))))) * 180 / Math.PI;
-	}
+        gui.tabpane.addTab(tr("Tile Numbers"), smpanel);
+    }
 
-	public static double tileXToLon(int zoom, int x) {
-		if ((zoom < 3) || (zoom > 18)) return Double.MIN_VALUE;
-		return x * 45.0 / (1<<(zoom-3)) - 180.0;
+    /**
+     * Called when bounding box is changed by one of the other download dialog tabs.
+     */
+    public void boundingBoxChanged(DownloadDialog gui) {
+        updateBboxFields(gui);
+    }
 
-	}
+    private void updateBboxFields(DownloadDialog gui) {
+        int z = ((Integer) tileZ.getValue()).intValue();
+        tileX0.setText(Integer.toString(lonToTileX(z, gui.minlon)));
+        tileX1.setText(Integer.toString(lonToTileX(z, gui.maxlon-.00001)));
+        tileY0.setText(Integer.toString(latToTileY(z, gui.maxlat-.00001)));
+        tileY1.setText(Integer.toString(latToTileY(z, gui.minlat)));
+    }
+
+    public static int latToTileY(int zoom, double lat) {
+        if ((zoom < 3) || (zoom > 18)) return -1;
+        double l = lat / 180 * Math.PI;
+        double pf = Math.log(Math.tan(l) + (1/Math.cos(l)));
+        return (int) ((1<<(zoom-1)) * (Math.PI - pf) / Math.PI);
+    }
+
+    public static int lonToTileX(int zoom, double lon) {
+        if ((zoom < 3) || (zoom > 18)) return -1;
+        return (int) ((1<<(zoom-3)) * (lon + 180.0) / 45.0);
+    }
+
+    public static double tileYToLat(int zoom, int y) {
+        if ((zoom < 3) || (zoom > 18)) return Double.MIN_VALUE;
+        return Math.atan(Math.sinh(Math.PI - (Math.PI*y / (1<<(zoom-1))))) * 180 / Math.PI;
+    }
+
+    public static double tileXToLon(int zoom, int x) {
+        if ((zoom < 3) || (zoom > 18)) return Double.MIN_VALUE;
+        return x * 45.0 / (1<<(zoom-3)) - 180.0;
+
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/download/WorldChooser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/WorldChooser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/download/WorldChooser.java	(revision 1169)
@@ -38,141 +38,141 @@
 public class WorldChooser extends NavigatableComponent implements DownloadSelection {
 
-	/**
-	 * The world as picture.
-	 */
-	private ImageIcon world;
+    /**
+     * The world as picture.
+     */
+    private ImageIcon world;
 
-	/**
-	 * Maximum scale level
-	 */
-	private double scaleMax;
+    /**
+     * Maximum scale level
+     */
+    private double scaleMax;
 
-	/**
-	 * Mark this rectangle (lat/lon values) when painting.
-	 */
-	private EastNorth markerMin, markerMax;
+    /**
+     * Mark this rectangle (lat/lon values) when painting.
+     */
+    private EastNorth markerMin, markerMax;
 
-	private Projection projection;
+    private Projection projection;
 
-	/**
-	 * Create the chooser component.
-	 */
-	public WorldChooser() {
-		URL path = Main.class.getResource("/images/world.jpg");
-		world = new ImageIcon(path);
-		center = new EastNorth(world.getIconWidth()/2, world.getIconHeight()/2);
-		setPreferredSize(new Dimension(400, 200));
+    /**
+     * Create the chooser component.
+     */
+    public WorldChooser() {
+        URL path = Main.class.getResource("/images/world.jpg");
+        world = new ImageIcon(path);
+        center = new EastNorth(world.getIconWidth()/2, world.getIconHeight()/2);
+        setPreferredSize(new Dimension(400, 200));
 
-		projection = new Projection() {
-			public EastNorth latlon2eastNorth(LatLon p) {
-				return new EastNorth(
-						(p.lon()+180) / 360 * world.getIconWidth(),
-						(p.lat()+90) / 180 * world.getIconHeight());
-			}
-			public LatLon eastNorth2latlon(EastNorth p) {
-				return new LatLon(
-						p.north()*180/world.getIconHeight() - 90,
-						p.east()*360/world.getIconWidth() - 180);
-			}
-			@Override public String toString() {
-				return "WorldChooser";
-			}
+        projection = new Projection() {
+            public EastNorth latlon2eastNorth(LatLon p) {
+                return new EastNorth(
+                        (p.lon()+180) / 360 * world.getIconWidth(),
+                        (p.lat()+90) / 180 * world.getIconHeight());
+            }
+            public LatLon eastNorth2latlon(EastNorth p) {
+                return new LatLon(
+                        p.north()*180/world.getIconHeight() - 90,
+                        p.east()*360/world.getIconWidth() - 180);
+            }
+            @Override public String toString() {
+                return "WorldChooser";
+            }
             public String getCacheDirectoryName() {
                 throw new UnsupportedOperationException();
             }
-			public double scaleFactor() {
-	            return 1.0 / world.getIconWidth();
+            public double scaleFactor() {
+                return 1.0 / world.getIconWidth();
             }
 
-		};
+        };
 
-		MapScaler scaler = new MapScaler(this, projection);
-		add(scaler);
-		scaler.setLocation(10,10);
+        MapScaler scaler = new MapScaler(this, projection);
+        add(scaler);
+        scaler.setLocation(10,10);
 
-		setMinimumSize(new Dimension(350, 350/2));
-	}
-
-	public void addGui(final DownloadDialog gui) {
-		JPanel temp = new JPanel();
-		temp.setLayout(new BorderLayout());
-		temp.add(this, BorderLayout.CENTER);
-		temp.add(new JLabel(tr("You can use the mouse or Ctrl+Arrow keys/./ to zoom and pan.")), BorderLayout.SOUTH);
-		gui.tabpane.add(temp, tr("Map"));
-		new MapMover(this, temp);
-		SelectionEnded selListener = new SelectionEnded(){
-			public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
-				markerMin = getEastNorth(r.x, r.y+r.height);
-				markerMax = getEastNorth(r.x+r.width, r.y);
-				LatLon min = getProjection().eastNorth2latlon(markerMin);
-				LatLon max = getProjection().eastNorth2latlon(markerMax);
-				gui.minlat = min.lat();
-				gui.minlon = min.lon();
-				gui.maxlat = max.lat();
-				gui.maxlon = max.lon();
-				gui.boundingBoxChanged(WorldChooser.this);
-				repaint();
-			}
-			public void addPropertyChangeListener(PropertyChangeListener listener) {}
-			public void removePropertyChangeListener(PropertyChangeListener listener) {}
-		};
-		SelectionManager sm = new SelectionManager(selListener, false, this);
-		sm.register(this);
+        setMinimumSize(new Dimension(350, 350/2));
     }
 
-	public void boundingBoxChanged(DownloadDialog gui) {
-		markerMin = getProjection().latlon2eastNorth(new LatLon(gui.minlat, gui.minlon));
-		markerMax = getProjection().latlon2eastNorth(new LatLon(gui.maxlat, gui.maxlon));
-		repaint();
-	}
+    public void addGui(final DownloadDialog gui) {
+        JPanel temp = new JPanel();
+        temp.setLayout(new BorderLayout());
+        temp.add(this, BorderLayout.CENTER);
+        temp.add(new JLabel(tr("You can use the mouse or Ctrl+Arrow keys/./ to zoom and pan.")), BorderLayout.SOUTH);
+        gui.tabpane.add(temp, tr("Map"));
+        new MapMover(this, temp);
+        SelectionEnded selListener = new SelectionEnded(){
+            public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
+                markerMin = getEastNorth(r.x, r.y+r.height);
+                markerMax = getEastNorth(r.x+r.width, r.y);
+                LatLon min = getProjection().eastNorth2latlon(markerMin);
+                LatLon max = getProjection().eastNorth2latlon(markerMax);
+                gui.minlat = min.lat();
+                gui.minlon = min.lon();
+                gui.maxlat = max.lat();
+                gui.maxlon = max.lon();
+                gui.boundingBoxChanged(WorldChooser.this);
+                repaint();
+            }
+            public void addPropertyChangeListener(PropertyChangeListener listener) {}
+            public void removePropertyChangeListener(PropertyChangeListener listener) {}
+        };
+        SelectionManager sm = new SelectionManager(selListener, false, this);
+        sm.register(this);
+    }
 
-	/**
-	 * Set the scale as well as the preferred size.
-	 */
-	@Override public void setPreferredSize(Dimension preferredSize) {
-		super.setPreferredSize(preferredSize);
-		scale = world.getIconWidth()/preferredSize.getWidth();
-		scaleMax = scale;
-	}
+    public void boundingBoxChanged(DownloadDialog gui) {
+        markerMin = getProjection().latlon2eastNorth(new LatLon(gui.minlat, gui.minlon));
+        markerMax = getProjection().latlon2eastNorth(new LatLon(gui.maxlat, gui.maxlon));
+        repaint();
+    }
 
-	/**
-	 * Draw the current selected region.
-	 */
-	@Override public void paint(Graphics g) {
-		EastNorth tl = getEastNorth(0,0);
-		EastNorth br = getEastNorth(getWidth(),getHeight());
-		g.drawImage(world.getImage(),0,0,getWidth(),getHeight(),(int)tl.east(),(int)tl.north(),(int)br.east(),(int)br.north(), null);
+    /**
+     * Set the scale as well as the preferred size.
+     */
+    @Override public void setPreferredSize(Dimension preferredSize) {
+        super.setPreferredSize(preferredSize);
+        scale = world.getIconWidth()/preferredSize.getWidth();
+        scaleMax = scale;
+    }
 
-		// draw marker rect
-		if (markerMin != null && markerMax != null) {
-			Point p1 = getPoint(markerMin);
-			Point p2 = getPoint(markerMax);
-			double x = Math.min(p1.x, p2.x);
-			double y = Math.min(p1.y, p2.y);
-			double w = Math.max(p1.x, p2.x) - x;
-			double h = Math.max(p1.y, p2.y) - y;
-			if (w < 1)
-				w = 1;
-			if (h < 1)
-				h = 1;
-			g.setColor(Color.YELLOW);
-			g.drawRect((int)x, (int)y, (int)w, (int)h);
-		}
-		super.paint(g);
-	}
+    /**
+     * Draw the current selected region.
+     */
+    @Override public void paint(Graphics g) {
+        EastNorth tl = getEastNorth(0,0);
+        EastNorth br = getEastNorth(getWidth(),getHeight());
+        g.drawImage(world.getImage(),0,0,getWidth(),getHeight(),(int)tl.east(),(int)tl.north(),(int)br.east(),(int)br.north(), null);
 
-	@Override public void zoomTo(EastNorth newCenter, double scale) {
-		if (getWidth() != 0 && scale > scaleMax) {
-			scale = scaleMax;
-			newCenter = center;
-		}
-		super.zoomTo(newCenter, scale);
-	}
+        // draw marker rect
+        if (markerMin != null && markerMax != null) {
+            Point p1 = getPoint(markerMin);
+            Point p2 = getPoint(markerMax);
+            double x = Math.min(p1.x, p2.x);
+            double y = Math.min(p1.y, p2.y);
+            double w = Math.max(p1.x, p2.x) - x;
+            double h = Math.max(p1.y, p2.y) - y;
+            if (w < 1)
+                w = 1;
+            if (h < 1)
+                h = 1;
+            g.setColor(Color.YELLOW);
+            g.drawRect((int)x, (int)y, (int)w, (int)h);
+        }
+        super.paint(g);
+    }
 
-	/**
-	 * Always use our image projection mode.
-	 */
-	@Override protected Projection getProjection() {
-		return projection;
-	}
+    @Override public void zoomTo(EastNorth newCenter, double scale) {
+        if (getWidth() != 0 && scale > scaleMax) {
+            scale = scaleMax;
+            newCenter = center;
+        }
+        super.zoomTo(newCenter, scale);
+    }
+
+    /**
+     * Always use our image projection mode.
+     */
+    @Override protected Projection getProjection() {
+        return projection;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/DataChangeListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/DataChangeListener.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/DataChangeListener.java	(revision 1169)
@@ -4,5 +4,5 @@
 public interface DataChangeListener {
 
-	public void dataChanged(OsmDataLayer l);
-	
+    public void dataChanged(OsmDataLayer l);
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java	(revision 1169)
@@ -78,470 +78,470 @@
 public class GeoImageLayer extends Layer {
 
-	private static final class ImageEntry implements Comparable<ImageEntry> {
-		File image;
-		Date time;
-		LatLon coor;
-		EastNorth pos;
-		Icon icon;
-		public int compareTo(ImageEntry image) {
-			return time.compareTo(image.time);
-		}
-	}
-
-	private static final class Loader extends PleaseWaitRunnable {
-		boolean cancelled = false;
-		private GeoImageLayer layer;
-		private final Collection<File> files;
-		private final GpxLayer gpxLayer;
-		public Loader(Collection<File> files, GpxLayer gpxLayer) {
-			super(tr("Images for {0}", gpxLayer.name));
-			this.files = files;
-			this.gpxLayer = gpxLayer;
-		}
-		@Override protected void realRun() throws IOException {
-			Main.pleaseWaitDlg.currentAction.setText(tr("Read GPX..."));
-			LinkedList<TimedPoint> gps = new LinkedList<TimedPoint>();
-
-			// Extract dates and locations from GPX input
-
-			for (GpxTrack trk : gpxLayer.data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint p : segment) {
-					if (!p.attr.containsKey("time"))
-						throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon()));
-					Date d = null;
-					try {
-						d = DateParser.parse((String) p.attr.get("time"));
-					} catch (ParseException e) {
-						throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon()));
-					}
-					gps.add(new TimedPoint(d, p.eastNorth));
-				}
-			}
-			}
-
-			if (gps.isEmpty()) {
-				errorMessage = tr("No images with readable timestamps found.");
-				return;
-			}
-
-			// read the image files
-			ArrayList<ImageEntry> data = new ArrayList<ImageEntry>(files.size());
-			int i = 0;
-			Main.pleaseWaitDlg.progress.setMaximum(files.size());
-			for (File f : files) {
-				if (cancelled)
-					break;
-				Main.pleaseWaitDlg.currentAction.setText(tr("Reading {0}...",f.getName()));
-				Main.pleaseWaitDlg.progress.setValue(i++);
-
-				ImageEntry e = new ImageEntry();
-				try {
-					e.time = ExifReader.readTime(f);
-				} catch (ParseException e1) {
-					continue;
-				}
-				if (e.time == null)
-					continue;
-				e.image = f;
-				e.icon = loadScaledImage(f, 16);
-
-				data.add(e);
-			}
-			layer = new GeoImageLayer(data, gps);
-			layer.calculatePosition();
-		}
-		@Override protected void finish() {
-			if (layer != null)
-				Main.main.addLayer(layer);
-		}
-		@Override protected void cancel() {cancelled = true;}
-	}
-
-	public ArrayList<ImageEntry> data;
-	private LinkedList<TimedPoint> gps = new LinkedList<TimedPoint>();
-
-	/**
-	 * The delta added to all timestamps in files from the camera
-	 * to match to the timestamp from the gps receivers tracklog.
-	 */
-	private long delta = Long.parseLong(Main.pref.get("tagimages.delta", "0"));
-	private long gpstimezone = Long.parseLong(Main.pref.get("tagimages.gpstimezone", "0"))*60*60*1000;
-	private boolean mousePressed = false;
-	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
-	private MouseAdapter mouseAdapter;
-	private int currentImage;
-
-	public static final class GpsTimeIncorrect extends Exception {
-		public GpsTimeIncorrect(String message, Throwable cause) {
-			super(message, cause);
-		}
-		public GpsTimeIncorrect(String message) {
-			super(message);
-		}
-	}
-
-	private static final class TimedPoint implements Comparable<TimedPoint> {
-		Date time;
-		EastNorth pos;
-		public TimedPoint(Date time, EastNorth pos) {
-			this.time = time;
-			this.pos = pos;
-		}
-		public int compareTo(TimedPoint point) {
-			return time.compareTo(point.time);
-		}
-	}
-
-	public static void create(Collection<File> files, GpxLayer gpxLayer) {
-		Loader loader = new Loader(files, gpxLayer);
-		Main.worker.execute(loader);
-	}
-
-	private GeoImageLayer(final ArrayList<ImageEntry> data, LinkedList<TimedPoint> gps) {
-		super(tr("Geotagged Images"));
-		Collections.sort(data);
-		Collections.sort(gps);
-		this.data = data;
-		this.gps = gps;
-		mouseAdapter = new MouseAdapter(){
-			@Override public void mousePressed(MouseEvent e) {
-				if (e.getButton() != MouseEvent.BUTTON1)
-					return;
-				mousePressed  = true;
-				if (visible)
-					Main.map.mapView.repaint();
-			}
-			@Override public void mouseReleased(MouseEvent ev) {
-				if (ev.getButton() != MouseEvent.BUTTON1)
-					return;
-				mousePressed = false;
-				if (!visible)
-					return;
-				for (int i = data.size(); i > 0; --i) {
-					ImageEntry e = data.get(i-1);
-					if (e.pos == null)
-						continue;
-					Point p = Main.map.mapView.getPoint(e.pos);
-					Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());
-					if (r.contains(ev.getPoint())) {
-						showImage(i-1);
-						break;
-					}
-				}
-				Main.map.mapView.repaint();
-			}
-		};
-		Main.map.mapView.addMouseListener(mouseAdapter);
-		Layer.listeners.add(new LayerChangeListener(){
-			public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
-			public void layerAdded(Layer newLayer) {}
-			public void layerRemoved(Layer oldLayer) {
-				Main.map.mapView.removeMouseListener(mouseAdapter);
-			}
-		});
-	}
-
-	private void showImage(int i) {
-		currentImage = i;
-		final JPanel p = new JPanel(new BorderLayout());
-		final ImageEntry e = data.get(currentImage);
-		final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(e.image, 580)));
-		final JViewport vp = scroll.getViewport();
-		p.add(scroll, BorderLayout.CENTER);
-
-		final JToggleButton scale = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit"));
-		final JButton next  = new JButton(ImageProvider.get("dialogs", "next"));
-		final JButton prev = new JButton(ImageProvider.get("dialogs", "previous"));
-		final JToggleButton cent = new JToggleButton(ImageProvider.get("dialogs", "centreview"));
-
-		JPanel p2 = new JPanel();
-		p2.add(prev);
-		p2.add(scale);
-		p2.add(cent);
-		p2.add(next);
-		prev.setEnabled(currentImage>0?true:false);
-		next.setEnabled(currentImage<data.size()-1?true:false);
-		p.add(p2, BorderLayout.SOUTH);
-		final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE);
-		final JDialog dlg = pane.createDialog(Main.parent, e.image+" ("+e.coor.toDisplayString()+")");
-		scale.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent ev) {
-				p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-				if (scale.getModel().isSelected())
-					((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
-				else
-					((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath()));
-				p.setCursor(Cursor.getDefaultCursor());
-			}
-		});
-		scale.setSelected(true);
-		cent.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent ev) {
-				final ImageEntry e = data.get(currentImage);
-				if (cent.getModel().isSelected())
-					Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale());
-			}
-		});
-
-		ActionListener nextprevAction = new ActionListener(){
-			public void actionPerformed(ActionEvent ev) {			    
-				p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-				if (ev.getActionCommand().equals("Next")) {
-					currentImage++; 
-					if(currentImage>=data.size()-1) next.setEnabled(false);
-					prev.setEnabled(true);
-				} else {
-					currentImage--;
-					if(currentImage<=0) prev.setEnabled(false);
-					next.setEnabled(true);
-				}
-
-				final ImageEntry e = data.get(currentImage);
-				if (scale.getModel().isSelected())
-					((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
-				else
-					((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath()));
-				dlg.setTitle(e.image+" ("+e.coor.toDisplayString()+")");
-				if (cent.getModel().isSelected())
-					Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale());
-				p.setCursor(Cursor.getDefaultCursor());
-			}
-		};
-		next.setActionCommand("Next");
-		prev.setActionCommand("Previous");
-		next.setMnemonic(KeyEvent.VK_RIGHT);
-		prev.setMnemonic(KeyEvent.VK_LEFT);
-		scale.setMnemonic(KeyEvent.VK_F);
-		cent.setMnemonic(KeyEvent.VK_C);
-		next.setToolTipText("Show next image");
-		prev.setToolTipText("Show previous image");
-		cent.setToolTipText("Centre image location in main display");
-		scale.setToolTipText("Scale image to fit");
-
-		prev.addActionListener(nextprevAction);
-		next.addActionListener(nextprevAction);
-		cent.setSelected(false);
-
-		dlg.addComponentListener(new ComponentListener() {
-			boolean ignoreEvent = true;
-			public void componentHidden(ComponentEvent e) {}
-			public void componentMoved(ComponentEvent e) {}
-			public void componentResized(ComponentEvent ev) {
-				// we ignore the first resize event, as the picture is scaled already on load: 
-				if (scale.getModel().isSelected() && !ignoreEvent) {
-					((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
-				}
-				ignoreEvent = false;
-            }
-			public void componentShown(ComponentEvent e) {}
-			
-		});
-		dlg.setModal(false);
-		dlg.setVisible(true);
-		dlg.setResizable(true); 
-	}
-
-	@Override public Icon getIcon() {
-		return ImageProvider.get("layer", "tagimages_small");
-	}
-
-	@Override public Object getInfoComponent() {
-		JPanel p = new JPanel(new GridBagLayout());
-		p.add(new JLabel(getToolTipText()), GBC.eop());
-
-		p.add(new JLabel(tr("GPS start: {0}",dateFormat.format(gps.getFirst().time))), GBC.eol());
-		p.add(new JLabel(tr("GPS end: {0}",dateFormat.format(gps.getLast().time))), GBC.eop());
-
-		p.add(new JLabel(tr("current delta: {0}s",(delta/1000.0))), GBC.eol());
-		p.add(new JLabel(tr("timezone difference: ")+(gpstimezone>0?"+":"")+(gpstimezone/1000/60/60)), GBC.eop());
-
-		JList img = new JList(data.toArray());
-		img.setCellRenderer(new DefaultListCellRenderer(){
-			@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-				ImageEntry e = (ImageEntry)value;
-				setIcon(e.icon);
-				setText(e.image.getName()+" ("+dateFormat.format(new Date(e.time.getTime()+(delta+gpstimezone)))+")");
-				if (e.pos == null)
-					setForeground(Color.red);
-				return this;
-			}
-		});
-		img.setVisibleRowCount(5);
-		p.add(new JScrollPane(img), GBC.eop().fill(GBC.BOTH));
-		return p;
-	}
-
-	@Override public String getToolTipText() {
-		int i = 0;
-		for (ImageEntry e : data)
-			if (e.pos != null)
-				i++;
-		return data.size()+" "+trn("image","images",data.size())+". "+tr("{0} within the track.",i);
-	}
-
-	@Override public boolean isMergable(Layer other) {
-		return other instanceof GeoImageLayer;
-	}
-
-	@Override public void mergeFrom(Layer from) {
-		GeoImageLayer l = (GeoImageLayer)from;
-		data.addAll(l.data);
-	}
-
-	@Override public void paint(Graphics g, MapView mv) {
-		boolean clickedFound = false;
-		for (ImageEntry e : data) {
-			if (e.pos != null) {
-				Point p = mv.getPoint(e.pos);
-				Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());
-				e.icon.paintIcon(mv, g, r.x, r.y);
-				Border b = null;
-				Point mousePosition = mv.getMousePosition();
-				if (mousePosition == null)
-					continue; // mouse outside the whole window
-				if (!clickedFound && mousePressed && r.contains(mousePosition)) {
-					b = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
-					clickedFound = true;
-				} else
-					b = BorderFactory.createBevelBorder(BevelBorder.RAISED);
-				Insets inset = b.getBorderInsets(mv);
-				r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2);
-				b.paintBorder(mv, g, r.x, r.y, r.width, r.height);
-			}
-		}
-	}
-
-	@Override public void visitBoundingBox(BoundingXYVisitor v) {
-		for (ImageEntry e : data)
-			v.visit(e.pos);
-	}
-
-	@Override public Component[] getMenuEntries() {
-		JMenuItem sync = new JMenuItem(tr("Sync clock"), ImageProvider.get("clock"));
-		sync.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JFileChooser fc = new JFileChooser(Main.pref.get("tagimages.lastdirectory"));
-				fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
-				fc.setAcceptAllFileFilterUsed(false);
-				fc.setFileFilter(new FileFilter(){
-					@Override public boolean accept(File f) {
-						return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg");
-					}
-					@Override public String getDescription() {
-						return tr("JPEG images (*.jpg)");
-					}
-				});
-				fc.showOpenDialog(Main.parent);
-				File sel = fc.getSelectedFile();
-				if (sel == null)
-					return;
-				Main.pref.put("tagimages.lastdirectory", sel.getPath());
-				sync(sel);
-				Main.map.repaint();
-			}
-		});
-		return new Component[]{
-				new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-				new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-				new JSeparator(),
-				sync,
-				new JSeparator(),
-				new JMenuItem(new RenameLayerAction(null, this)),
-				new JSeparator(),
-				new JMenuItem(new LayerListPopup.InfoAction(this))};
-	}
-
-	private void calculatePosition() {
-		for (ImageEntry e : data) {
-			TimedPoint lastTP = null;
-			for (TimedPoint tp : gps) {
-				Date time = new Date(tp.time.getTime() - (delta+gpstimezone));
-				if (time.after(e.time) && lastTP != null) {
-					double x = (lastTP.pos.east()+tp.pos.east())/2;
-					double y = (lastTP.pos.north()+tp.pos.north())/2;
-					e.pos = new EastNorth(x,y);
-					break;
-				}
-				lastTP = tp;
-			}
-			if (e.pos != null)
-				e.coor = Main.proj.eastNorth2latlon(e.pos);
-		}
-	}
-
-	private void sync(File f) {
-		Date exifDate;
-		try {
-			exifDate = ExifReader.readTime(f);
-		} catch (ParseException e) {
-			JOptionPane.showMessageDialog(Main.parent, tr("The date in file \"{0}\" could not be parsed.", f.getName()));
-			return;
-		}
-		if (exifDate == null) {
-			JOptionPane.showMessageDialog(Main.parent, tr("There is no EXIF time within the file \"{0}\".", f.getName()));
-			return;
-		}
-		JPanel p = new JPanel(new GridBagLayout());
-		p.add(new JLabel(tr("Image")), GBC.eol());
-		p.add(new JLabel(loadScaledImage(f, 300)), GBC.eop());
-		p.add(new JLabel(tr("Enter shown date (mm/dd/yyyy HH:MM:SS)")), GBC.eol());
-		JTextField gpsText = new JTextField(dateFormat.format(new Date(exifDate.getTime()+delta)));
-		p.add(gpsText, GBC.eol().fill(GBC.HORIZONTAL));
-		p.add(new JLabel(tr("GPS unit timezone (difference to photo)")), GBC.eol());
-		String t = Main.pref.get("tagimages.gpstimezone", "0");
-		if (t.charAt(0) != '-')
-			t = "+"+t;
-		JTextField gpsTimezone = new JTextField(t);
-		p.add(gpsTimezone, GBC.eol().fill(GBC.HORIZONTAL));
-
-		while (true) {
-			int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Syncronize Time with GPS Unit"), JOptionPane.OK_CANCEL_OPTION);
-			if (answer != JOptionPane.OK_OPTION || gpsText.getText().equals(""))
-				return;
-			try {
-				delta = DateParser.parse(gpsText.getText()).getTime() - exifDate.getTime();
-				String time = gpsTimezone.getText();
-				if (!time.equals("") && time.charAt(0) == '+')
-					time = time.substring(1);
-				if (time.equals(""))
-					time = "0";
-				gpstimezone = Long.valueOf(time)*60*60*1000;
-				Main.pref.put("tagimages.delta", ""+delta);
-				Main.pref.put("tagimages.gpstimezone", time);
-				calculatePosition();
-				return;
-			} catch (NumberFormatException x) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Time entered could not be parsed."));
-			} catch (ParseException x) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Time entered could not be parsed."));
-			}
-		}
-	}
-
-	private static Icon loadScaledImage(File f, int maxSize) {
-		Image img = new ImageIcon(f.getPath()).getImage();
-		int w = img.getWidth(null);
-		int h = img.getHeight(null);
-		if (w>h) {
-			h = Math.round(maxSize*((float)h/w));
-			w = maxSize;
-		} else {
-			w = Math.round(maxSize*((float)w/h));
-			h = maxSize;
-		}
-		return new ImageIcon(createResizedCopy(img, w, h));
-	}
-	
-	private static BufferedImage createResizedCopy(Image originalImage, 
-			int scaledWidth, int scaledHeight)
-	{
-		BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
-		Graphics2D g = scaledBI.createGraphics();
-
-		g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); 
-		g.dispose();
-		return scaledBI;
-	}
+    private static final class ImageEntry implements Comparable<ImageEntry> {
+        File image;
+        Date time;
+        LatLon coor;
+        EastNorth pos;
+        Icon icon;
+        public int compareTo(ImageEntry image) {
+            return time.compareTo(image.time);
+        }
+    }
+
+    private static final class Loader extends PleaseWaitRunnable {
+        boolean cancelled = false;
+        private GeoImageLayer layer;
+        private final Collection<File> files;
+        private final GpxLayer gpxLayer;
+        public Loader(Collection<File> files, GpxLayer gpxLayer) {
+            super(tr("Images for {0}", gpxLayer.name));
+            this.files = files;
+            this.gpxLayer = gpxLayer;
+        }
+        @Override protected void realRun() throws IOException {
+            Main.pleaseWaitDlg.currentAction.setText(tr("Read GPX..."));
+            LinkedList<TimedPoint> gps = new LinkedList<TimedPoint>();
+
+            // Extract dates and locations from GPX input
+
+            for (GpxTrack trk : gpxLayer.data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint p : segment) {
+                    if (!p.attr.containsKey("time"))
+                        throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon()));
+                    Date d = null;
+                    try {
+                        d = DateParser.parse((String) p.attr.get("time"));
+                    } catch (ParseException e) {
+                        throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon()));
+                    }
+                    gps.add(new TimedPoint(d, p.eastNorth));
+                }
+            }
+            }
+
+            if (gps.isEmpty()) {
+                errorMessage = tr("No images with readable timestamps found.");
+                return;
+            }
+
+            // read the image files
+            ArrayList<ImageEntry> data = new ArrayList<ImageEntry>(files.size());
+            int i = 0;
+            Main.pleaseWaitDlg.progress.setMaximum(files.size());
+            for (File f : files) {
+                if (cancelled)
+                    break;
+                Main.pleaseWaitDlg.currentAction.setText(tr("Reading {0}...",f.getName()));
+                Main.pleaseWaitDlg.progress.setValue(i++);
+
+                ImageEntry e = new ImageEntry();
+                try {
+                    e.time = ExifReader.readTime(f);
+                } catch (ParseException e1) {
+                    continue;
+                }
+                if (e.time == null)
+                    continue;
+                e.image = f;
+                e.icon = loadScaledImage(f, 16);
+
+                data.add(e);
+            }
+            layer = new GeoImageLayer(data, gps);
+            layer.calculatePosition();
+        }
+        @Override protected void finish() {
+            if (layer != null)
+                Main.main.addLayer(layer);
+        }
+        @Override protected void cancel() {cancelled = true;}
+    }
+
+    public ArrayList<ImageEntry> data;
+    private LinkedList<TimedPoint> gps = new LinkedList<TimedPoint>();
+
+    /**
+     * The delta added to all timestamps in files from the camera
+     * to match to the timestamp from the gps receivers tracklog.
+     */
+    private long delta = Long.parseLong(Main.pref.get("tagimages.delta", "0"));
+    private long gpstimezone = Long.parseLong(Main.pref.get("tagimages.gpstimezone", "0"))*60*60*1000;
+    private boolean mousePressed = false;
+    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+    private MouseAdapter mouseAdapter;
+    private int currentImage;
+
+    public static final class GpsTimeIncorrect extends Exception {
+        public GpsTimeIncorrect(String message, Throwable cause) {
+            super(message, cause);
+        }
+        public GpsTimeIncorrect(String message) {
+            super(message);
+        }
+    }
+
+    private static final class TimedPoint implements Comparable<TimedPoint> {
+        Date time;
+        EastNorth pos;
+        public TimedPoint(Date time, EastNorth pos) {
+            this.time = time;
+            this.pos = pos;
+        }
+        public int compareTo(TimedPoint point) {
+            return time.compareTo(point.time);
+        }
+    }
+
+    public static void create(Collection<File> files, GpxLayer gpxLayer) {
+        Loader loader = new Loader(files, gpxLayer);
+        Main.worker.execute(loader);
+    }
+
+    private GeoImageLayer(final ArrayList<ImageEntry> data, LinkedList<TimedPoint> gps) {
+        super(tr("Geotagged Images"));
+        Collections.sort(data);
+        Collections.sort(gps);
+        this.data = data;
+        this.gps = gps;
+        mouseAdapter = new MouseAdapter(){
+            @Override public void mousePressed(MouseEvent e) {
+                if (e.getButton() != MouseEvent.BUTTON1)
+                    return;
+                mousePressed  = true;
+                if (visible)
+                    Main.map.mapView.repaint();
+            }
+            @Override public void mouseReleased(MouseEvent ev) {
+                if (ev.getButton() != MouseEvent.BUTTON1)
+                    return;
+                mousePressed = false;
+                if (!visible)
+                    return;
+                for (int i = data.size(); i > 0; --i) {
+                    ImageEntry e = data.get(i-1);
+                    if (e.pos == null)
+                        continue;
+                    Point p = Main.map.mapView.getPoint(e.pos);
+                    Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());
+                    if (r.contains(ev.getPoint())) {
+                        showImage(i-1);
+                        break;
+                    }
+                }
+                Main.map.mapView.repaint();
+            }
+        };
+        Main.map.mapView.addMouseListener(mouseAdapter);
+        Layer.listeners.add(new LayerChangeListener(){
+            public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
+            public void layerAdded(Layer newLayer) {}
+            public void layerRemoved(Layer oldLayer) {
+                Main.map.mapView.removeMouseListener(mouseAdapter);
+            }
+        });
+    }
+
+    private void showImage(int i) {
+        currentImage = i;
+        final JPanel p = new JPanel(new BorderLayout());
+        final ImageEntry e = data.get(currentImage);
+        final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(e.image, 580)));
+        final JViewport vp = scroll.getViewport();
+        p.add(scroll, BorderLayout.CENTER);
+
+        final JToggleButton scale = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit"));
+        final JButton next  = new JButton(ImageProvider.get("dialogs", "next"));
+        final JButton prev = new JButton(ImageProvider.get("dialogs", "previous"));
+        final JToggleButton cent = new JToggleButton(ImageProvider.get("dialogs", "centreview"));
+
+        JPanel p2 = new JPanel();
+        p2.add(prev);
+        p2.add(scale);
+        p2.add(cent);
+        p2.add(next);
+        prev.setEnabled(currentImage>0?true:false);
+        next.setEnabled(currentImage<data.size()-1?true:false);
+        p.add(p2, BorderLayout.SOUTH);
+        final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE);
+        final JDialog dlg = pane.createDialog(Main.parent, e.image+" ("+e.coor.toDisplayString()+")");
+        scale.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent ev) {
+                p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+                if (scale.getModel().isSelected())
+                    ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
+                else
+                    ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath()));
+                p.setCursor(Cursor.getDefaultCursor());
+            }
+        });
+        scale.setSelected(true);
+        cent.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent ev) {
+                final ImageEntry e = data.get(currentImage);
+                if (cent.getModel().isSelected())
+                    Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale());
+            }
+        });
+
+        ActionListener nextprevAction = new ActionListener(){
+            public void actionPerformed(ActionEvent ev) {
+                p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+                if (ev.getActionCommand().equals("Next")) {
+                    currentImage++;
+                    if(currentImage>=data.size()-1) next.setEnabled(false);
+                    prev.setEnabled(true);
+                } else {
+                    currentImage--;
+                    if(currentImage<=0) prev.setEnabled(false);
+                    next.setEnabled(true);
+                }
+
+                final ImageEntry e = data.get(currentImage);
+                if (scale.getModel().isSelected())
+                    ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
+                else
+                    ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath()));
+                dlg.setTitle(e.image+" ("+e.coor.toDisplayString()+")");
+                if (cent.getModel().isSelected())
+                    Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale());
+                p.setCursor(Cursor.getDefaultCursor());
+            }
+        };
+        next.setActionCommand("Next");
+        prev.setActionCommand("Previous");
+        next.setMnemonic(KeyEvent.VK_RIGHT);
+        prev.setMnemonic(KeyEvent.VK_LEFT);
+        scale.setMnemonic(KeyEvent.VK_F);
+        cent.setMnemonic(KeyEvent.VK_C);
+        next.setToolTipText("Show next image");
+        prev.setToolTipText("Show previous image");
+        cent.setToolTipText("Centre image location in main display");
+        scale.setToolTipText("Scale image to fit");
+
+        prev.addActionListener(nextprevAction);
+        next.addActionListener(nextprevAction);
+        cent.setSelected(false);
+
+        dlg.addComponentListener(new ComponentListener() {
+            boolean ignoreEvent = true;
+            public void componentHidden(ComponentEvent e) {}
+            public void componentMoved(ComponentEvent e) {}
+            public void componentResized(ComponentEvent ev) {
+                // we ignore the first resize event, as the picture is scaled already on load:
+                if (scale.getModel().isSelected() && !ignoreEvent) {
+                    ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight())));
+                }
+                ignoreEvent = false;
+            }
+            public void componentShown(ComponentEvent e) {}
+
+        });
+        dlg.setModal(false);
+        dlg.setVisible(true);
+        dlg.setResizable(true);
+    }
+
+    @Override public Icon getIcon() {
+        return ImageProvider.get("layer", "tagimages_small");
+    }
+
+    @Override public Object getInfoComponent() {
+        JPanel p = new JPanel(new GridBagLayout());
+        p.add(new JLabel(getToolTipText()), GBC.eop());
+
+        p.add(new JLabel(tr("GPS start: {0}",dateFormat.format(gps.getFirst().time))), GBC.eol());
+        p.add(new JLabel(tr("GPS end: {0}",dateFormat.format(gps.getLast().time))), GBC.eop());
+
+        p.add(new JLabel(tr("current delta: {0}s",(delta/1000.0))), GBC.eol());
+        p.add(new JLabel(tr("timezone difference: ")+(gpstimezone>0?"+":"")+(gpstimezone/1000/60/60)), GBC.eop());
+
+        JList img = new JList(data.toArray());
+        img.setCellRenderer(new DefaultListCellRenderer(){
+            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+                ImageEntry e = (ImageEntry)value;
+                setIcon(e.icon);
+                setText(e.image.getName()+" ("+dateFormat.format(new Date(e.time.getTime()+(delta+gpstimezone)))+")");
+                if (e.pos == null)
+                    setForeground(Color.red);
+                return this;
+            }
+        });
+        img.setVisibleRowCount(5);
+        p.add(new JScrollPane(img), GBC.eop().fill(GBC.BOTH));
+        return p;
+    }
+
+    @Override public String getToolTipText() {
+        int i = 0;
+        for (ImageEntry e : data)
+            if (e.pos != null)
+                i++;
+        return data.size()+" "+trn("image","images",data.size())+". "+tr("{0} within the track.",i);
+    }
+
+    @Override public boolean isMergable(Layer other) {
+        return other instanceof GeoImageLayer;
+    }
+
+    @Override public void mergeFrom(Layer from) {
+        GeoImageLayer l = (GeoImageLayer)from;
+        data.addAll(l.data);
+    }
+
+    @Override public void paint(Graphics g, MapView mv) {
+        boolean clickedFound = false;
+        for (ImageEntry e : data) {
+            if (e.pos != null) {
+                Point p = mv.getPoint(e.pos);
+                Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());
+                e.icon.paintIcon(mv, g, r.x, r.y);
+                Border b = null;
+                Point mousePosition = mv.getMousePosition();
+                if (mousePosition == null)
+                    continue; // mouse outside the whole window
+                if (!clickedFound && mousePressed && r.contains(mousePosition)) {
+                    b = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
+                    clickedFound = true;
+                } else
+                    b = BorderFactory.createBevelBorder(BevelBorder.RAISED);
+                Insets inset = b.getBorderInsets(mv);
+                r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2);
+                b.paintBorder(mv, g, r.x, r.y, r.width, r.height);
+            }
+        }
+    }
+
+    @Override public void visitBoundingBox(BoundingXYVisitor v) {
+        for (ImageEntry e : data)
+            v.visit(e.pos);
+    }
+
+    @Override public Component[] getMenuEntries() {
+        JMenuItem sync = new JMenuItem(tr("Sync clock"), ImageProvider.get("clock"));
+        sync.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser fc = new JFileChooser(Main.pref.get("tagimages.lastdirectory"));
+                fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
+                fc.setAcceptAllFileFilterUsed(false);
+                fc.setFileFilter(new FileFilter(){
+                    @Override public boolean accept(File f) {
+                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg");
+                    }
+                    @Override public String getDescription() {
+                        return tr("JPEG images (*.jpg)");
+                    }
+                });
+                fc.showOpenDialog(Main.parent);
+                File sel = fc.getSelectedFile();
+                if (sel == null)
+                    return;
+                Main.pref.put("tagimages.lastdirectory", sel.getPath());
+                sync(sel);
+                Main.map.repaint();
+            }
+        });
+        return new Component[]{
+                new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+                new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+                new JSeparator(),
+                sync,
+                new JSeparator(),
+                new JMenuItem(new RenameLayerAction(null, this)),
+                new JSeparator(),
+                new JMenuItem(new LayerListPopup.InfoAction(this))};
+    }
+
+    private void calculatePosition() {
+        for (ImageEntry e : data) {
+            TimedPoint lastTP = null;
+            for (TimedPoint tp : gps) {
+                Date time = new Date(tp.time.getTime() - (delta+gpstimezone));
+                if (time.after(e.time) && lastTP != null) {
+                    double x = (lastTP.pos.east()+tp.pos.east())/2;
+                    double y = (lastTP.pos.north()+tp.pos.north())/2;
+                    e.pos = new EastNorth(x,y);
+                    break;
+                }
+                lastTP = tp;
+            }
+            if (e.pos != null)
+                e.coor = Main.proj.eastNorth2latlon(e.pos);
+        }
+    }
+
+    private void sync(File f) {
+        Date exifDate;
+        try {
+            exifDate = ExifReader.readTime(f);
+        } catch (ParseException e) {
+            JOptionPane.showMessageDialog(Main.parent, tr("The date in file \"{0}\" could not be parsed.", f.getName()));
+            return;
+        }
+        if (exifDate == null) {
+            JOptionPane.showMessageDialog(Main.parent, tr("There is no EXIF time within the file \"{0}\".", f.getName()));
+            return;
+        }
+        JPanel p = new JPanel(new GridBagLayout());
+        p.add(new JLabel(tr("Image")), GBC.eol());
+        p.add(new JLabel(loadScaledImage(f, 300)), GBC.eop());
+        p.add(new JLabel(tr("Enter shown date (mm/dd/yyyy HH:MM:SS)")), GBC.eol());
+        JTextField gpsText = new JTextField(dateFormat.format(new Date(exifDate.getTime()+delta)));
+        p.add(gpsText, GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(new JLabel(tr("GPS unit timezone (difference to photo)")), GBC.eol());
+        String t = Main.pref.get("tagimages.gpstimezone", "0");
+        if (t.charAt(0) != '-')
+            t = "+"+t;
+        JTextField gpsTimezone = new JTextField(t);
+        p.add(gpsTimezone, GBC.eol().fill(GBC.HORIZONTAL));
+
+        while (true) {
+            int answer = JOptionPane.showConfirmDialog(Main.parent, p, tr("Syncronize Time with GPS Unit"), JOptionPane.OK_CANCEL_OPTION);
+            if (answer != JOptionPane.OK_OPTION || gpsText.getText().equals(""))
+                return;
+            try {
+                delta = DateParser.parse(gpsText.getText()).getTime() - exifDate.getTime();
+                String time = gpsTimezone.getText();
+                if (!time.equals("") && time.charAt(0) == '+')
+                    time = time.substring(1);
+                if (time.equals(""))
+                    time = "0";
+                gpstimezone = Long.valueOf(time)*60*60*1000;
+                Main.pref.put("tagimages.delta", ""+delta);
+                Main.pref.put("tagimages.gpstimezone", time);
+                calculatePosition();
+                return;
+            } catch (NumberFormatException x) {
+                JOptionPane.showMessageDialog(Main.parent, tr("Time entered could not be parsed."));
+            } catch (ParseException x) {
+                JOptionPane.showMessageDialog(Main.parent, tr("Time entered could not be parsed."));
+            }
+        }
+    }
+
+    private static Icon loadScaledImage(File f, int maxSize) {
+        Image img = new ImageIcon(f.getPath()).getImage();
+        int w = img.getWidth(null);
+        int h = img.getHeight(null);
+        if (w>h) {
+            h = Math.round(maxSize*((float)h/w));
+            w = maxSize;
+        } else {
+            w = Math.round(maxSize*((float)w/h));
+            h = maxSize;
+        }
+        return new ImageIcon(createResizedCopy(img, w, h));
+    }
+
+    private static BufferedImage createResizedCopy(Image originalImage,
+            int scaledWidth, int scaledHeight)
+    {
+        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = scaledBI.createGraphics();
+
+        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
+        g.dispose();
+        return scaledBI;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 1169)
@@ -80,676 +80,676 @@
 
 public class GpxLayer extends Layer {
-	public GpxData data;
-	private final GpxLayer me;
-	protected static final double PHI = Math.toRadians(15);
-	private boolean computeCacheInSync;
-	private int computeCacheMaxLineLengthUsed;
-	private Color computeCacheColorUsed;
-	private boolean computeCacheColored;
-
-	public GpxLayer(GpxData d) {
-		super((String) d.attr.get("name"));
-		data = d;
-		me = this;
-		computeCacheInSync = false;
-	}
-
-	public GpxLayer(GpxData d, String name) {
-		this(d);
-		this.name = name;
-	}
-
-	@Override public Icon getIcon() {
-		return ImageProvider.get("layer", "gpx_small");
-	}
-
-	@Override public Object getInfoComponent() {
-		return getToolTipText();
-	}
-
-	@Override public Component[] getMenuEntries() {
-		JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
-		line.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				JRadioButton[] r = new JRadioButton[3];
-				r[0] = new JRadioButton(tr("Use global settings."));
-				r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
-				r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
-				ButtonGroup group = new ButtonGroup();
-				Box panel = Box.createVerticalBox();
-				for (JRadioButton b : r) {
-					group.add(b);
-					panel.add(b);
-				}
-				String propName = "draw.rawgps.lines.layer "+name;
-				if (Main.pref.hasKey(propName))
-					group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
-				else
-					group.setSelected(r[0].getModel(), true);
-				int answer = JOptionPane.showConfirmDialog(Main.parent, panel, tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION);
-				if (answer == JOptionPane.CANCEL_OPTION)
-					return;
-				if (group.getSelection() == r[0].getModel())
-					Main.pref.put(propName, null);
-				else
-					Main.pref.put(propName, group.getSelection() == r[1].getModel());
-				Main.map.repaint();
-			}
-		});
-
-		JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-		color.putClientProperty("help", "Action/LayerCustomizeColor");
-		color.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
-				Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
-				int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
-				JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
-				switch (answer) {
-				case 0:
-					Main.pref.putColor("layer "+name, c.getColor());
-					break;
-				case 1:
-					return;
-				case 2:
-					Main.pref.putColor("layer "+name, null);
-					break;
-				}
-				Main.map.repaint();
-			}
-		});
-
-		JMenuItem markersFromNamedTrackpoints = new JMenuItem(tr("Markers From Named Points"), ImageProvider.get("addmarkers"));
-		markersFromNamedTrackpoints.putClientProperty("help", "Action/MarkersFromNamedPoints");
-		markersFromNamedTrackpoints.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				GpxData namedTrackPoints = new GpxData();
-				for (GpxTrack track : data.tracks)
-					for (Collection<WayPoint> seg : track.trackSegs)
-						for (WayPoint point : seg)
-							if (point.attr.containsKey("name") || point.attr.containsKey("desc"))
-								namedTrackPoints.waypoints.add(point);
-
-				MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile, me);
-				if (ml.data.size() > 0) {
-					Main.main.addLayer(ml);
-				}
-			}
-		});
-
-		JMenuItem importAudio = new JMenuItem(tr("Import Audio"), ImageProvider.get("importaudio"));
-		importAudio.putClientProperty("help", "ImportAudio");
-		importAudio.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				String dir = Main.pref.get("markers.lastaudiodirectory");
-				JFileChooser fc = new JFileChooser(dir);
-				fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
-				fc.setAcceptAllFileFilterUsed(false);
-				fc.setFileFilter(new FileFilter(){
-					@Override public boolean accept(File f) {
-						return f.isDirectory() || f.getName().toLowerCase().endsWith(".wav");
-					}
-					@Override public String getDescription() {
-						return tr("Wave Audio files (*.wav)");
-					}
-				});
-				fc.setMultiSelectionEnabled(true);
-				if(fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) {
-					if (!fc.getCurrentDirectory().getAbsolutePath().equals(dir))
-						Main.pref.put("markers.lastaudiodirectory", fc.getCurrentDirectory().getAbsolutePath());
-
-					// FIXME: properly support multi-selection here.
-					// Calling importAudio several times just creates N maker layers, which
-					// is sub-optimal.
-					File sel[] = fc.getSelectedFiles();
-					if(sel != null)
-						for (int i = 0; i < sel.length; i++)
-							importAudio(sel[i]);
-
-					Main.map.repaint();
-				}
-			}
-		});
-
-		JMenuItem tagimage = new JMenuItem(tr("Import images"), ImageProvider.get("tagimages"));
-		tagimage.putClientProperty("help", "Action/ImportImages");
-		tagimage.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				JFileChooser fc = new JFileChooser(Main.pref.get("tagimages.lastdirectory"));
-				fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
-				fc.setMultiSelectionEnabled(true);
-				fc.setAcceptAllFileFilterUsed(false);
-				fc.setFileFilter(new FileFilter() {
-					@Override public boolean accept(File f) {
-						return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg");
-					}
-					@Override public String getDescription() {
-						return tr("JPEG images (*.jpg)");
-					}
-				});
-				fc.showOpenDialog(Main.parent);
-				File[] sel = fc.getSelectedFiles();
-				if (sel == null || sel.length == 0)
-					return;
-				LinkedList<File> files = new LinkedList<File>();
-				addRecursiveFiles(files, sel);
-				Main.pref.put("tagimages.lastdirectory", fc.getCurrentDirectory().getPath());
-				GeoImageLayer.create(files, GpxLayer.this);
-			}
-
-			private void addRecursiveFiles(LinkedList<File> files, File[] sel) {
-				for (File f : sel) {
-					if (f.isDirectory())
-						addRecursiveFiles(files, f.listFiles());
-					else if (f.getName().toLowerCase().endsWith(".jpg"))
-						files.add(f);
-				}
-			}
-		});
-
-		if (Main.applet)
-			return new Component[] {
-				new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-				new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-				new JSeparator(),
-				color,
-				line,
-				new JMenuItem(new ConvertToDataLayerAction()),
-				new JSeparator(),
-				new JMenuItem(new RenameLayerAction(associatedFile, this)),
-				new JSeparator(),
-				new JMenuItem(new LayerListPopup.InfoAction(this))};
-		return new Component[] {
-			new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-			new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-			new JSeparator(),
-			new JMenuItem(new SaveAction(this)),
-			new JMenuItem(new SaveAsAction(this)),
-			// new JMenuItem(new UploadTraceAction()),
-			color,
-			line,
-			tagimage,
-			importAudio,
-			markersFromNamedTrackpoints,
-			new JMenuItem(new ConvertToDataLayerAction()),
+    public GpxData data;
+    private final GpxLayer me;
+    protected static final double PHI = Math.toRadians(15);
+    private boolean computeCacheInSync;
+    private int computeCacheMaxLineLengthUsed;
+    private Color computeCacheColorUsed;
+    private boolean computeCacheColored;
+
+    public GpxLayer(GpxData d) {
+        super((String) d.attr.get("name"));
+        data = d;
+        me = this;
+        computeCacheInSync = false;
+    }
+
+    public GpxLayer(GpxData d, String name) {
+        this(d);
+        this.name = name;
+    }
+
+    @Override public Icon getIcon() {
+        return ImageProvider.get("layer", "gpx_small");
+    }
+
+    @Override public Object getInfoComponent() {
+        return getToolTipText();
+    }
+
+    @Override public Component[] getMenuEntries() {
+        JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
+        line.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                JRadioButton[] r = new JRadioButton[3];
+                r[0] = new JRadioButton(tr("Use global settings."));
+                r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
+                r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
+                ButtonGroup group = new ButtonGroup();
+                Box panel = Box.createVerticalBox();
+                for (JRadioButton b : r) {
+                    group.add(b);
+                    panel.add(b);
+                }
+                String propName = "draw.rawgps.lines.layer "+name;
+                if (Main.pref.hasKey(propName))
+                    group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
+                else
+                    group.setSelected(r[0].getModel(), true);
+                int answer = JOptionPane.showConfirmDialog(Main.parent, panel, tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION);
+                if (answer == JOptionPane.CANCEL_OPTION)
+                    return;
+                if (group.getSelection() == r[0].getModel())
+                    Main.pref.put(propName, null);
+                else
+                    Main.pref.put(propName, group.getSelection() == r[1].getModel());
+                Main.map.repaint();
+            }
+        });
+
+        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
+        color.putClientProperty("help", "Action/LayerCustomizeColor");
+        color.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
+                Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+                int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
+                JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+                switch (answer) {
+                case 0:
+                    Main.pref.putColor("layer "+name, c.getColor());
+                    break;
+                case 1:
+                    return;
+                case 2:
+                    Main.pref.putColor("layer "+name, null);
+                    break;
+                }
+                Main.map.repaint();
+            }
+        });
+
+        JMenuItem markersFromNamedTrackpoints = new JMenuItem(tr("Markers From Named Points"), ImageProvider.get("addmarkers"));
+        markersFromNamedTrackpoints.putClientProperty("help", "Action/MarkersFromNamedPoints");
+        markersFromNamedTrackpoints.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                GpxData namedTrackPoints = new GpxData();
+                for (GpxTrack track : data.tracks)
+                    for (Collection<WayPoint> seg : track.trackSegs)
+                        for (WayPoint point : seg)
+                            if (point.attr.containsKey("name") || point.attr.containsKey("desc"))
+                                namedTrackPoints.waypoints.add(point);
+
+                MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile, me);
+                if (ml.data.size() > 0) {
+                    Main.main.addLayer(ml);
+                }
+            }
+        });
+
+        JMenuItem importAudio = new JMenuItem(tr("Import Audio"), ImageProvider.get("importaudio"));
+        importAudio.putClientProperty("help", "ImportAudio");
+        importAudio.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                String dir = Main.pref.get("markers.lastaudiodirectory");
+                JFileChooser fc = new JFileChooser(dir);
+                fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
+                fc.setAcceptAllFileFilterUsed(false);
+                fc.setFileFilter(new FileFilter(){
+                    @Override public boolean accept(File f) {
+                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".wav");
+                    }
+                    @Override public String getDescription() {
+                        return tr("Wave Audio files (*.wav)");
+                    }
+                });
+                fc.setMultiSelectionEnabled(true);
+                if(fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) {
+                    if (!fc.getCurrentDirectory().getAbsolutePath().equals(dir))
+                        Main.pref.put("markers.lastaudiodirectory", fc.getCurrentDirectory().getAbsolutePath());
+
+                    // FIXME: properly support multi-selection here.
+                    // Calling importAudio several times just creates N maker layers, which
+                    // is sub-optimal.
+                    File sel[] = fc.getSelectedFiles();
+                    if(sel != null)
+                        for (int i = 0; i < sel.length; i++)
+                            importAudio(sel[i]);
+
+                    Main.map.repaint();
+                }
+            }
+        });
+
+        JMenuItem tagimage = new JMenuItem(tr("Import images"), ImageProvider.get("tagimages"));
+        tagimage.putClientProperty("help", "Action/ImportImages");
+        tagimage.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser fc = new JFileChooser(Main.pref.get("tagimages.lastdirectory"));
+                fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+                fc.setMultiSelectionEnabled(true);
+                fc.setAcceptAllFileFilterUsed(false);
+                fc.setFileFilter(new FileFilter() {
+                    @Override public boolean accept(File f) {
+                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg");
+                    }
+                    @Override public String getDescription() {
+                        return tr("JPEG images (*.jpg)");
+                    }
+                });
+                fc.showOpenDialog(Main.parent);
+                File[] sel = fc.getSelectedFiles();
+                if (sel == null || sel.length == 0)
+                    return;
+                LinkedList<File> files = new LinkedList<File>();
+                addRecursiveFiles(files, sel);
+                Main.pref.put("tagimages.lastdirectory", fc.getCurrentDirectory().getPath());
+                GeoImageLayer.create(files, GpxLayer.this);
+            }
+
+            private void addRecursiveFiles(LinkedList<File> files, File[] sel) {
+                for (File f : sel) {
+                    if (f.isDirectory())
+                        addRecursiveFiles(files, f.listFiles());
+                    else if (f.getName().toLowerCase().endsWith(".jpg"))
+                        files.add(f);
+                }
+            }
+        });
+
+        if (Main.applet)
+            return new Component[] {
+                new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+                new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+                new JSeparator(),
+                color,
+                line,
+                new JMenuItem(new ConvertToDataLayerAction()),
+                new JSeparator(),
+                new JMenuItem(new RenameLayerAction(associatedFile, this)),
+                new JSeparator(),
+                new JMenuItem(new LayerListPopup.InfoAction(this))};
+        return new Component[] {
+            new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+            new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+            new JSeparator(),
+            new JMenuItem(new SaveAction(this)),
+            new JMenuItem(new SaveAsAction(this)),
+            // new JMenuItem(new UploadTraceAction()),
+            color,
+            line,
+            tagimage,
+            importAudio,
+            markersFromNamedTrackpoints,
+            new JMenuItem(new ConvertToDataLayerAction()),
             new JMenuItem(new DownloadAlongTrackAction()),
-			new JSeparator(),
-			new JMenuItem(new RenameLayerAction(associatedFile, this)),
-			new JSeparator(),
-			new JMenuItem(new LayerListPopup.InfoAction(this))};
-	}
-
-	@Override public String getToolTipText() {
-		StringBuilder info = new StringBuilder().append("<html>");
-
-		info.append(trn("{0} track, ", "{0} tracks, ",
-		data.tracks.size(), data.tracks.size())).append(trn("{0} route, ", "{0} routes, ",
-		data.routes.size(), data.routes.size())).append(trn("{0} waypoint", "{0} waypoints",
-		data.waypoints.size(), data.waypoints.size())).append("<br>");
-
-		if (data.attr.containsKey("name"))
-			info.append(tr("Name: {0}", data.attr.get("name"))).append("<br>");
-
-		if (data.attr.containsKey("desc"))
-			info.append(tr("Description: {0}", data.attr.get("desc"))).append("<br>");
-
-		if(data.tracks.size() > 0){
-			boolean first = true;
-			WayPoint earliest = null, latest = null;
-
-			for(GpxTrack trk: data.tracks){
-				for(Collection<WayPoint> seg:trk.trackSegs){
-					for(WayPoint pnt:seg){
-						if(first){
-							latest = earliest = pnt;
-							first = false;
-						}else{
-							if(pnt.compareTo(earliest) < 0){
-								earliest = pnt;
-							}else{
-								latest = pnt;
-							}
-						}
-					}
-				}
-			}
-			if (earliest != null && latest != null) {
-				DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
-				info.append(tr("Timespan: ") + df.format(new Date((long)(earliest.time * 1000))) + " - "
-				+ df.format(new Date((long)(latest.time * 1000))));
-				int diff = (int)(latest.time - earliest.time);
-				info.append(" (" + (diff / 3600) + ":" + ((diff % 3600)/60) + ")");
-				info.append("<br>");
-			}
-		}
-		info.append(tr("Length: ") + new DecimalFormat("#0.00").format(data.length() / 1000) + "km");
-		info.append("<br>");
-
-		return info.append("</html>").toString();
-	}
-
-	@Override public boolean isMergable(Layer other) {
-		return other instanceof GpxLayer;
-	}
-
-	@Override public void mergeFrom(Layer from) {
-		data.mergeFrom(((GpxLayer)from).data);
-		computeCacheInSync = false;
-	}
-
-	private static Color[] colors = new Color[256];
-	static {
-		for (int i = 0; i < colors.length; i++) {
-			colors[i] = Color.getHSBColor(i/300.0f, 1, 1);
-		}
-	}
-
-	// lookup array to draw arrows without doing any math
-	private static int ll0 = 9;
-	private static int sl4 = 5;
-	private static int sl9 = 3;
-	private static int[][] dir = {
-		{+sl4,+ll0,+ll0,+sl4},
-		{-sl9,+ll0,+sl9,+ll0},
-		{-ll0,+sl4,-sl4,+ll0},
-		{-ll0,-sl9,-ll0,+sl9},
-		{-sl4,-ll0,-ll0,-sl4},
-		{+sl9,-ll0,-sl9,-ll0},
-		{+ll0,-sl4,+sl4,-ll0},
-		{+ll0,+sl9,+ll0,-sl9},
-		{+sl4,+ll0,+ll0,+sl4},
-		{-sl9,+ll0,+sl9,+ll0},
-		{-ll0,+sl4,-sl4,+ll0},
-		{-ll0,-sl9,-ll0,+sl9}
-	};
-
-	@Override public void paint(Graphics g, MapView mv) {
-
-		/****************************************************************
-		 ********** STEP 1 - GET CONFIG VALUES **************************
-		 ****************************************************************/
-		// Long startTime = System.currentTimeMillis();
-		Color neutralColor = Main.pref.getColor(marktr("gps point"), "layer "+name, Color.GRAY);
-		boolean forceLines = Main.pref.getBoolean("draw.rawgps.lines.force");                     // also draw lines between points belonging to different segments
-		boolean direction = Main.pref.getBoolean("draw.rawgps.direction");                        // draw direction arrows on the lines
-		int maxLineLength = -1;
-		try {
-			maxLineLength = Integer.parseInt(Main.pref.get("draw.rawgps.max-line-length", "-1"));   // don't draw lines if longer than x meters
-		} catch (java.lang.NumberFormatException e) {
-			Main.pref.put("draw.rawgps.max-line-length", "-1");
-		}
-		boolean lines = Main.pref.getBoolean("draw.rawgps.lines");                                // draw line between points, global setting
-		String linesKey = "draw.rawgps.lines.layer "+name;
-		if (Main.pref.hasKey(linesKey))
-			lines = Main.pref.getBoolean(linesKey);                                                 // draw lines, per-layer setting
-		boolean large = Main.pref.getBoolean("draw.rawgps.large");                                // paint large dots for points
-		boolean colored = Main.pref.getBoolean("draw.rawgps.colors");                             // color the lines
-		boolean alternatedirection = Main.pref.getBoolean("draw.rawgps.alternatedirection");      // paint direction arrow with alternate math. may be faster
-		int delta = 0;
-		try {
-			delta = Integer.parseInt(Main.pref.get("draw.rawgps.min-arrow-distance", "0"));         // don't draw arrows nearer to each other than this
-		} catch (java.lang.NumberFormatException e) {
-			Main.pref.put("draw.rawgps.min-arrow-distance", "0");
-		}
-
-		/****************************************************************
-		 ********** STEP 2a - CHECK CACHE VALIDITY **********************
-		 ****************************************************************/
-		if (computeCacheInSync && ((computeCacheMaxLineLengthUsed != maxLineLength) ||
-								   (!neutralColor.equals(computeCacheColorUsed)) ||
-								   (computeCacheColored != colored))) {
+            new JSeparator(),
+            new JMenuItem(new RenameLayerAction(associatedFile, this)),
+            new JSeparator(),
+            new JMenuItem(new LayerListPopup.InfoAction(this))};
+    }
+
+    @Override public String getToolTipText() {
+        StringBuilder info = new StringBuilder().append("<html>");
+
+        info.append(trn("{0} track, ", "{0} tracks, ",
+        data.tracks.size(), data.tracks.size())).append(trn("{0} route, ", "{0} routes, ",
+        data.routes.size(), data.routes.size())).append(trn("{0} waypoint", "{0} waypoints",
+        data.waypoints.size(), data.waypoints.size())).append("<br>");
+
+        if (data.attr.containsKey("name"))
+            info.append(tr("Name: {0}", data.attr.get("name"))).append("<br>");
+
+        if (data.attr.containsKey("desc"))
+            info.append(tr("Description: {0}", data.attr.get("desc"))).append("<br>");
+
+        if(data.tracks.size() > 0){
+            boolean first = true;
+            WayPoint earliest = null, latest = null;
+
+            for(GpxTrack trk: data.tracks){
+                for(Collection<WayPoint> seg:trk.trackSegs){
+                    for(WayPoint pnt:seg){
+                        if(first){
+                            latest = earliest = pnt;
+                            first = false;
+                        }else{
+                            if(pnt.compareTo(earliest) < 0){
+                                earliest = pnt;
+                            }else{
+                                latest = pnt;
+                            }
+                        }
+                    }
+                }
+            }
+            if (earliest != null && latest != null) {
+                DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
+                info.append(tr("Timespan: ") + df.format(new Date((long)(earliest.time * 1000))) + " - "
+                + df.format(new Date((long)(latest.time * 1000))));
+                int diff = (int)(latest.time - earliest.time);
+                info.append(" (" + (diff / 3600) + ":" + ((diff % 3600)/60) + ")");
+                info.append("<br>");
+            }
+        }
+        info.append(tr("Length: ") + new DecimalFormat("#0.00").format(data.length() / 1000) + "km");
+        info.append("<br>");
+
+        return info.append("</html>").toString();
+    }
+
+    @Override public boolean isMergable(Layer other) {
+        return other instanceof GpxLayer;
+    }
+
+    @Override public void mergeFrom(Layer from) {
+        data.mergeFrom(((GpxLayer)from).data);
+        computeCacheInSync = false;
+    }
+
+    private static Color[] colors = new Color[256];
+    static {
+        for (int i = 0; i < colors.length; i++) {
+            colors[i] = Color.getHSBColor(i/300.0f, 1, 1);
+        }
+    }
+
+    // lookup array to draw arrows without doing any math
+    private static int ll0 = 9;
+    private static int sl4 = 5;
+    private static int sl9 = 3;
+    private static int[][] dir = {
+        {+sl4,+ll0,+ll0,+sl4},
+        {-sl9,+ll0,+sl9,+ll0},
+        {-ll0,+sl4,-sl4,+ll0},
+        {-ll0,-sl9,-ll0,+sl9},
+        {-sl4,-ll0,-ll0,-sl4},
+        {+sl9,-ll0,-sl9,-ll0},
+        {+ll0,-sl4,+sl4,-ll0},
+        {+ll0,+sl9,+ll0,-sl9},
+        {+sl4,+ll0,+ll0,+sl4},
+        {-sl9,+ll0,+sl9,+ll0},
+        {-ll0,+sl4,-sl4,+ll0},
+        {-ll0,-sl9,-ll0,+sl9}
+    };
+
+    @Override public void paint(Graphics g, MapView mv) {
+
+        /****************************************************************
+         ********** STEP 1 - GET CONFIG VALUES **************************
+         ****************************************************************/
+        // Long startTime = System.currentTimeMillis();
+        Color neutralColor = Main.pref.getColor(marktr("gps point"), "layer "+name, Color.GRAY);
+        boolean forceLines = Main.pref.getBoolean("draw.rawgps.lines.force");                     // also draw lines between points belonging to different segments
+        boolean direction = Main.pref.getBoolean("draw.rawgps.direction");                        // draw direction arrows on the lines
+        int maxLineLength = -1;
+        try {
+            maxLineLength = Integer.parseInt(Main.pref.get("draw.rawgps.max-line-length", "-1"));   // don't draw lines if longer than x meters
+        } catch (java.lang.NumberFormatException e) {
+            Main.pref.put("draw.rawgps.max-line-length", "-1");
+        }
+        boolean lines = Main.pref.getBoolean("draw.rawgps.lines");                                // draw line between points, global setting
+        String linesKey = "draw.rawgps.lines.layer "+name;
+        if (Main.pref.hasKey(linesKey))
+            lines = Main.pref.getBoolean(linesKey);                                                 // draw lines, per-layer setting
+        boolean large = Main.pref.getBoolean("draw.rawgps.large");                                // paint large dots for points
+        boolean colored = Main.pref.getBoolean("draw.rawgps.colors");                             // color the lines
+        boolean alternatedirection = Main.pref.getBoolean("draw.rawgps.alternatedirection");      // paint direction arrow with alternate math. may be faster
+        int delta = 0;
+        try {
+            delta = Integer.parseInt(Main.pref.get("draw.rawgps.min-arrow-distance", "0"));         // don't draw arrows nearer to each other than this
+        } catch (java.lang.NumberFormatException e) {
+            Main.pref.put("draw.rawgps.min-arrow-distance", "0");
+        }
+
+        /****************************************************************
+         ********** STEP 2a - CHECK CACHE VALIDITY **********************
+         ****************************************************************/
+        if (computeCacheInSync && ((computeCacheMaxLineLengthUsed != maxLineLength) ||
+                                   (!neutralColor.equals(computeCacheColorUsed)) ||
+                                   (computeCacheColored != colored))) {
 //          System.out.println("(re-)computing gpx line styles, reason: CCIS=" + computeCacheInSync + " CCMLLU=" + (computeCacheMaxLineLengthUsed != maxLineLength) + " CCCU=" +  (!neutralColor.equals(computeCacheColorUsed)) + " CCC=" + (computeCacheColored != colored));
-			computeCacheMaxLineLengthUsed = maxLineLength;
-			computeCacheInSync = false;
-			computeCacheColorUsed = neutralColor;
-			computeCacheColored = colored;
-		}
-
-		/****************************************************************
-		 ********** STEP 2b - RE-COMPUTE CACHE DATA *********************
-		 ****************************************************************/
-		if (!computeCacheInSync) { // don't compute if the cache is good
-			WayPoint oldWp = null;
-			for (GpxTrack trk : data.tracks) {
-				if (!forceLines) { // don't draw lines between segments, unless forced to
-					oldWp = null;
-				}
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon())) {
-							continue;
-						}
-						if (oldWp != null) {
-							double dist = trkPnt.latlon.greatCircleDistance(oldWp.latlon);
-							double dtime = trkPnt.time - oldWp.time;
-							double vel = dist/dtime;
-
-							if (!colored) {
-								trkPnt.speedLineColor = neutralColor;
-							} else if (dtime <= 0 || vel < 0 || vel > 36) { // attn: bad case first
-								trkPnt.speedLineColor = colors[255];
-							} else {
-								trkPnt.speedLineColor = colors[(int) (7*vel)];
-							}
-							if (maxLineLength == -1 || dist <= maxLineLength) {
-								trkPnt.drawLine = true;
-								trkPnt.dir = (int)(Math.atan2(-trkPnt.eastNorth.north()+oldWp.eastNorth.north(), trkPnt.eastNorth.east()-oldWp.eastNorth.east()) / Math.PI * 4 + 3.5); // crude but works
-							} else {
-								trkPnt.drawLine = false;
-							}
-						} else { // make sure we reset outdated data
-							trkPnt.speedLineColor = colors[255];
-							trkPnt.drawLine = false;
-						}
-						oldWp = trkPnt;
-					}
-				}
-			}
-			computeCacheInSync = true;
-		}
-
-		/****************************************************************
-		 ********** STEP 3a - DRAW LINES ********************************
-		 ****************************************************************/
-		if (lines) {
-		Point old = null;
-		for (GpxTrack trk : data.tracks) {
-			for (Collection<WayPoint> segment : trk.trackSegs) {
-				for (WayPoint trkPnt : segment) {
-					if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-						continue;
-					Point screen = mv.getPoint(trkPnt.eastNorth);
-						if (trkPnt.drawLine) {
-							// skip points that are on the same screenposition
-							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) {
-								g.setColor(trkPnt.speedLineColor);
-								g.drawLine(old.x, old.y, screen.x, screen.y);
-							}
-						}
-						old = screen;
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if lines
-
-		/****************************************************************
-		 ********** STEP 3b - DRAW NICE ARROWS **************************
-		 ****************************************************************/
-		if (lines && direction && !alternatedirection) {
-			Point old = null;
-			Point oldA = null; // last arrow painted
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-							continue;
-						if (trkPnt.drawLine) {
-							Point screen = mv.getPoint(trkPnt.eastNorth);
-							// skip points that are on the same screenposition
-							if (old != null && (oldA == null || screen.x < oldA.x-delta || screen.x > oldA.x+delta || screen.y < oldA.y-delta || screen.y > oldA.y+delta)) {
-								g.setColor(trkPnt.speedLineColor);
-								double t = Math.atan2(screen.y-old.y, screen.x-old.x) + Math.PI;
-								g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t-PHI)), (int)(screen.y
-								+ 10*Math.sin(t-PHI)));
-								g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t+PHI)), (int)(screen.y
-								+ 10*Math.sin(t+PHI)));
-								oldA = screen;
-							}
-							old = screen;
-						}
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if lines
-
-		/****************************************************************
-		 ********** STEP 3c - DRAW FAST ARROWS **************************
-		 ****************************************************************/
-		if (lines && direction && alternatedirection) {
-			Point old = null;
-			Point oldA = null; // last arrow painted
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-							continue;
-						if (trkPnt.drawLine) {
-							Point screen = mv.getPoint(trkPnt.eastNorth);
-							// skip points that are on the same screenposition
-							if (old != null && (oldA == null || screen.x < oldA.x-delta || screen.x > oldA.x+delta || screen.y < oldA.y-delta || screen.y > oldA.y+delta)) {
-								g.setColor(trkPnt.speedLineColor);
-								g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y + dir[trkPnt.dir][1]);
-								g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][2], screen.y + dir[trkPnt.dir][3]);
-								oldA = screen;
-							}
-							old = screen;
-						}
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if lines
-
-		/****************************************************************
-		 ********** STEP 3d - DRAW LARGE POINTS *************************
-		 ****************************************************************/
-		if (large) {
-			g.setColor(neutralColor);
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-							continue;
-						Point screen = mv.getPoint(trkPnt.eastNorth);
-							g.fillRect(screen.x-1, screen.y-1, 3, 3);
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if large
-
-		/****************************************************************
-		 ********** STEP 3e - DRAW SMALL POINTS FOR LINES ***************
-		 ****************************************************************/
-		if (!large && lines){
-			g.setColor(neutralColor);
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-							continue;
-						if (!trkPnt.drawLine) {
-							Point screen = mv.getPoint(trkPnt.eastNorth);
-						g.drawRect(screen.x, screen.y, 0, 0);
-					}
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if large
-
-		/****************************************************************
-		 ********** STEP 3f - DRAW SMALL POINTS INSTEAD OF LINES ********
-		 ****************************************************************/
-		if (!large && !lines){
-			g.setColor(neutralColor);
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					for (WayPoint trkPnt : segment) {
-						if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
-							continue;
-						Point screen = mv.getPoint(trkPnt.eastNorth);
-						g.drawRect(screen.x, screen.y, 0, 0);
-					} // end for trkpnt
-				} // end for segment
-			} // end for trk
-		} // end if large
-
-		//Long duration = System.currentTimeMillis() - startTime;
-		//System.out.println(duration);
-	} // end paint
-
-	@Override public void visitBoundingBox(BoundingXYVisitor v) {
-		for (WayPoint p : data.waypoints)
-			v.visit(p.eastNorth);
-
-		for (GpxRoute rte : data.routes) {
-			Collection<WayPoint> r = rte.routePoints;
-			for (WayPoint p : r) {
-				v.visit(p.eastNorth);
-			}
-		}
-
-		for (GpxTrack trk : data.tracks) {
-			for (Collection<WayPoint> seg : trk.trackSegs) {
-				for (WayPoint p : seg) {
-					v.visit(p.eastNorth);
-				}
-			}
-		}
-	}
-
-	public class UploadTraceAction extends AbstractAction {
-		public UploadTraceAction() {
-			super(tr("Upload this trace..."), ImageProvider.get("uploadtrace"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			JPanel msg = new JPanel(new GridBagLayout());
-			msg.add(new JLabel(tr("<html>This functionality has been added only recently. Please<br>"+
-			"use with care and check if it works as expected.</html>")), GBC.eop());
-			ButtonGroup bg = new ButtonGroup();
-			JRadioButton c1 = null;
-			JRadioButton c2 = null;
-
-			//TODO
-			//check whether data comes from server
-			//check whether data changed sind last save/open
-
-			c1 = new JRadioButton(tr("Upload track filtered by JOSM"), true);
-			c2 = new JRadioButton(tr("Upload raw file: "), false);
-			c2.setEnabled(false);
-			c1.setEnabled(false);
-			bg.add(c1);
-			bg.add(c2);
-
-			msg.add(c1, GBC.eol());
-			msg.add(c2, GBC.eop());
-
-
-			JLabel description = new JLabel((String) data.attr.get("desc"));
-			JTextField tags = new JTextField();
-			tags.setText((String) data.attr.get("keywords"));
-			msg.add(new JLabel(tr("Description:")), GBC.std());
-			msg.add(description, GBC.eol().fill(GBC.HORIZONTAL));
-			msg.add(new JLabel(tr("Tags (keywords in GPX):")), GBC.std());
-			msg.add(tags, GBC.eol().fill(GBC.HORIZONTAL));
-			JCheckBox c3 = new JCheckBox("public");
-			msg.add(c3, GBC.eop());
-			msg.add(new JLabel("Please ensure that you don't upload your traces twice."), GBC.eop());
-
-			int answer = JOptionPane.showConfirmDialog(Main.parent, msg, tr("GPX-Upload"), JOptionPane.OK_CANCEL_OPTION);
-			if (answer == JOptionPane.OK_OPTION)
-			{
-				try {
-					String version = Main.pref.get("osm-server.version", "0.5");
-					URL url = new URL(Main.pref.get("osm-server.url") + "/" + version + "/gpx/create");
-
-					// create a boundary string
-					String boundary = MultiPartFormOutputStream.createBoundary();
-					URLConnection urlConn = MultiPartFormOutputStream.createConnection(url);
-					urlConn.setRequestProperty("Accept", "*/*");
-					urlConn.setRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary));
-					// set some other request headers...
-					urlConn.setRequestProperty("Connection", "Keep-Alive");
-					urlConn.setRequestProperty("Cache-Control", "no-cache");
-					// no need to connect cuz getOutputStream() does it
-					MultiPartFormOutputStream out = new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
-					out.writeField("description", description.getText());
-					out.writeField("tags", tags.getText());
-					out.writeField("public", (c3.getSelectedObjects() != null) ? "1" : "0");
-					// upload a file
-					// out.writeFile("gpx_file", "text/xml", associatedFile);
-					// can also write bytes directly
-					// out.writeFile("myFile", "text/plain", "C:\\test.txt",
-					// "This is some file text.".getBytes("ASCII"));
-					File tmp = File.createTempFile("josm", "tmp.gpx");
-					FileOutputStream outs = new FileOutputStream(tmp);
-					new GpxWriter(outs).write(data);
-					outs.close();
-					FileInputStream ins = new FileInputStream(tmp);
-					new GpxWriter(System.out).write(data);
-					out.writeFile("gpx_file", "text/xml", data.storageFile.getName(), ins);
-					out.close();
-					tmp.delete();
-					// read response from server
-					BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
-					String line = "";
-					while((line = in.readLine()) != null) {
-						System.out.println(line);
-					}
-					in.close();
-
-					//TODO check response
-					/*                  int retCode = urlConn.getResponseCode();
-					System.out.println("got return: " + retCode);
-					String retMsg = urlConn.getResponseMessage();
-					urlConn.disconnect();
-					if (retCode != 200) {
-						// Look for a detailed error message from the server
-						if (urlConn.getHeaderField("Error") != null)
-							retMsg += "\n" + urlConn.getHeaderField("Error");
-
-						// Report our error
-						ByteArrayOutputStream o = new ByteArrayOutputStream();
-						System.out.println(new String(o.toByteArray(), "UTF-8").toString());
-						throw new RuntimeException(retCode+" "+retMsg);
-					}
-					 */
-				} catch (UnknownHostException ex) {
-					throw new RuntimeException(tr("Unknown host")+": "+ex.getMessage(), ex);
-				} catch (Exception ex) {
-					//if (cancel)
-					//  return; // assume cancel
-					if (ex instanceof RuntimeException)
-						throw (RuntimeException)ex;
-					throw new RuntimeException(ex.getMessage(), ex);
-				}
-			}
-		}
-	}
-
-	public class ConvertToDataLayerAction extends AbstractAction {
-		public ConvertToDataLayerAction() {
-			super(tr("Convert to data layer"), ImageProvider.get("converttoosm"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			JPanel msg = new JPanel(new GridBagLayout());
-			msg.add(new JLabel(tr("<html>Upload of unprocessed GPS data as map data is considered harmful.<br>If you want to upload traces, look here:")), GBC.eol());
-			msg.add(new UrlLabel(tr("http://www.openstreetmap.org/traces")), GBC.eop());
-			if (!DontShowAgainInfo.show("convert_to_data", msg))
-				return;
-			DataSet ds = new DataSet();
-			for (GpxTrack trk : data.tracks) {
-				for (Collection<WayPoint> segment : trk.trackSegs) {
-					Way w = new Way();
-					for (WayPoint p : segment) {
-						Node n = new Node(p.latlon);
-						String timestr = p.getString("time");
-						if(timestr != null)
-						{
-							timestr = timestr.replace("Z","+00:00");
-							n.timestamp = timestr;
-						}
-						ds.nodes.add(n);
-						w.nodes.add(n);
-					}
-					ds.ways.add(w);
-				}
-			}
-			Main.main.addLayer(new OsmDataLayer(ds, tr("Converted from: {0}", GpxLayer.this.name), null));
-			Main.main.removeLayer(GpxLayer.this);
-		}
-	}
+            computeCacheMaxLineLengthUsed = maxLineLength;
+            computeCacheInSync = false;
+            computeCacheColorUsed = neutralColor;
+            computeCacheColored = colored;
+        }
+
+        /****************************************************************
+         ********** STEP 2b - RE-COMPUTE CACHE DATA *********************
+         ****************************************************************/
+        if (!computeCacheInSync) { // don't compute if the cache is good
+            WayPoint oldWp = null;
+            for (GpxTrack trk : data.tracks) {
+                if (!forceLines) { // don't draw lines between segments, unless forced to
+                    oldWp = null;
+                }
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon())) {
+                            continue;
+                        }
+                        if (oldWp != null) {
+                            double dist = trkPnt.latlon.greatCircleDistance(oldWp.latlon);
+                            double dtime = trkPnt.time - oldWp.time;
+                            double vel = dist/dtime;
+
+                            if (!colored) {
+                                trkPnt.speedLineColor = neutralColor;
+                            } else if (dtime <= 0 || vel < 0 || vel > 36) { // attn: bad case first
+                                trkPnt.speedLineColor = colors[255];
+                            } else {
+                                trkPnt.speedLineColor = colors[(int) (7*vel)];
+                            }
+                            if (maxLineLength == -1 || dist <= maxLineLength) {
+                                trkPnt.drawLine = true;
+                                trkPnt.dir = (int)(Math.atan2(-trkPnt.eastNorth.north()+oldWp.eastNorth.north(), trkPnt.eastNorth.east()-oldWp.eastNorth.east()) / Math.PI * 4 + 3.5); // crude but works
+                            } else {
+                                trkPnt.drawLine = false;
+                            }
+                        } else { // make sure we reset outdated data
+                            trkPnt.speedLineColor = colors[255];
+                            trkPnt.drawLine = false;
+                        }
+                        oldWp = trkPnt;
+                    }
+                }
+            }
+            computeCacheInSync = true;
+        }
+
+        /****************************************************************
+         ********** STEP 3a - DRAW LINES ********************************
+         ****************************************************************/
+        if (lines) {
+        Point old = null;
+        for (GpxTrack trk : data.tracks) {
+            for (Collection<WayPoint> segment : trk.trackSegs) {
+                for (WayPoint trkPnt : segment) {
+                    if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                        continue;
+                    Point screen = mv.getPoint(trkPnt.eastNorth);
+                        if (trkPnt.drawLine) {
+                            // skip points that are on the same screenposition
+                            if (old != null && ((old.x != screen.x) || (old.y != screen.y))) {
+                                g.setColor(trkPnt.speedLineColor);
+                                g.drawLine(old.x, old.y, screen.x, screen.y);
+                            }
+                        }
+                        old = screen;
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if lines
+
+        /****************************************************************
+         ********** STEP 3b - DRAW NICE ARROWS **************************
+         ****************************************************************/
+        if (lines && direction && !alternatedirection) {
+            Point old = null;
+            Point oldA = null; // last arrow painted
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                            continue;
+                        if (trkPnt.drawLine) {
+                            Point screen = mv.getPoint(trkPnt.eastNorth);
+                            // skip points that are on the same screenposition
+                            if (old != null && (oldA == null || screen.x < oldA.x-delta || screen.x > oldA.x+delta || screen.y < oldA.y-delta || screen.y > oldA.y+delta)) {
+                                g.setColor(trkPnt.speedLineColor);
+                                double t = Math.atan2(screen.y-old.y, screen.x-old.x) + Math.PI;
+                                g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t-PHI)), (int)(screen.y
+                                + 10*Math.sin(t-PHI)));
+                                g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t+PHI)), (int)(screen.y
+                                + 10*Math.sin(t+PHI)));
+                                oldA = screen;
+                            }
+                            old = screen;
+                        }
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if lines
+
+        /****************************************************************
+         ********** STEP 3c - DRAW FAST ARROWS **************************
+         ****************************************************************/
+        if (lines && direction && alternatedirection) {
+            Point old = null;
+            Point oldA = null; // last arrow painted
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                            continue;
+                        if (trkPnt.drawLine) {
+                            Point screen = mv.getPoint(trkPnt.eastNorth);
+                            // skip points that are on the same screenposition
+                            if (old != null && (oldA == null || screen.x < oldA.x-delta || screen.x > oldA.x+delta || screen.y < oldA.y-delta || screen.y > oldA.y+delta)) {
+                                g.setColor(trkPnt.speedLineColor);
+                                g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y + dir[trkPnt.dir][1]);
+                                g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][2], screen.y + dir[trkPnt.dir][3]);
+                                oldA = screen;
+                            }
+                            old = screen;
+                        }
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if lines
+
+        /****************************************************************
+         ********** STEP 3d - DRAW LARGE POINTS *************************
+         ****************************************************************/
+        if (large) {
+            g.setColor(neutralColor);
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                            continue;
+                        Point screen = mv.getPoint(trkPnt.eastNorth);
+                            g.fillRect(screen.x-1, screen.y-1, 3, 3);
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if large
+
+        /****************************************************************
+         ********** STEP 3e - DRAW SMALL POINTS FOR LINES ***************
+         ****************************************************************/
+        if (!large && lines){
+            g.setColor(neutralColor);
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                            continue;
+                        if (!trkPnt.drawLine) {
+                            Point screen = mv.getPoint(trkPnt.eastNorth);
+                        g.drawRect(screen.x, screen.y, 0, 0);
+                    }
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if large
+
+        /****************************************************************
+         ********** STEP 3f - DRAW SMALL POINTS INSTEAD OF LINES ********
+         ****************************************************************/
+        if (!large && !lines){
+            g.setColor(neutralColor);
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    for (WayPoint trkPnt : segment) {
+                        if (Double.isNaN(trkPnt.latlon.lat()) || Double.isNaN(trkPnt.latlon.lon()))
+                            continue;
+                        Point screen = mv.getPoint(trkPnt.eastNorth);
+                        g.drawRect(screen.x, screen.y, 0, 0);
+                    } // end for trkpnt
+                } // end for segment
+            } // end for trk
+        } // end if large
+
+        //Long duration = System.currentTimeMillis() - startTime;
+        //System.out.println(duration);
+    } // end paint
+
+    @Override public void visitBoundingBox(BoundingXYVisitor v) {
+        for (WayPoint p : data.waypoints)
+            v.visit(p.eastNorth);
+
+        for (GpxRoute rte : data.routes) {
+            Collection<WayPoint> r = rte.routePoints;
+            for (WayPoint p : r) {
+                v.visit(p.eastNorth);
+            }
+        }
+
+        for (GpxTrack trk : data.tracks) {
+            for (Collection<WayPoint> seg : trk.trackSegs) {
+                for (WayPoint p : seg) {
+                    v.visit(p.eastNorth);
+                }
+            }
+        }
+    }
+
+    public class UploadTraceAction extends AbstractAction {
+        public UploadTraceAction() {
+            super(tr("Upload this trace..."), ImageProvider.get("uploadtrace"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            JPanel msg = new JPanel(new GridBagLayout());
+            msg.add(new JLabel(tr("<html>This functionality has been added only recently. Please<br>"+
+            "use with care and check if it works as expected.</html>")), GBC.eop());
+            ButtonGroup bg = new ButtonGroup();
+            JRadioButton c1 = null;
+            JRadioButton c2 = null;
+
+            //TODO
+            //check whether data comes from server
+            //check whether data changed sind last save/open
+
+            c1 = new JRadioButton(tr("Upload track filtered by JOSM"), true);
+            c2 = new JRadioButton(tr("Upload raw file: "), false);
+            c2.setEnabled(false);
+            c1.setEnabled(false);
+            bg.add(c1);
+            bg.add(c2);
+
+            msg.add(c1, GBC.eol());
+            msg.add(c2, GBC.eop());
+
+
+            JLabel description = new JLabel((String) data.attr.get("desc"));
+            JTextField tags = new JTextField();
+            tags.setText((String) data.attr.get("keywords"));
+            msg.add(new JLabel(tr("Description:")), GBC.std());
+            msg.add(description, GBC.eol().fill(GBC.HORIZONTAL));
+            msg.add(new JLabel(tr("Tags (keywords in GPX):")), GBC.std());
+            msg.add(tags, GBC.eol().fill(GBC.HORIZONTAL));
+            JCheckBox c3 = new JCheckBox("public");
+            msg.add(c3, GBC.eop());
+            msg.add(new JLabel("Please ensure that you don't upload your traces twice."), GBC.eop());
+
+            int answer = JOptionPane.showConfirmDialog(Main.parent, msg, tr("GPX-Upload"), JOptionPane.OK_CANCEL_OPTION);
+            if (answer == JOptionPane.OK_OPTION)
+            {
+                try {
+                    String version = Main.pref.get("osm-server.version", "0.5");
+                    URL url = new URL(Main.pref.get("osm-server.url") + "/" + version + "/gpx/create");
+
+                    // create a boundary string
+                    String boundary = MultiPartFormOutputStream.createBoundary();
+                    URLConnection urlConn = MultiPartFormOutputStream.createConnection(url);
+                    urlConn.setRequestProperty("Accept", "*/*");
+                    urlConn.setRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary));
+                    // set some other request headers...
+                    urlConn.setRequestProperty("Connection", "Keep-Alive");
+                    urlConn.setRequestProperty("Cache-Control", "no-cache");
+                    // no need to connect cuz getOutputStream() does it
+                    MultiPartFormOutputStream out = new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
+                    out.writeField("description", description.getText());
+                    out.writeField("tags", tags.getText());
+                    out.writeField("public", (c3.getSelectedObjects() != null) ? "1" : "0");
+                    // upload a file
+                    // out.writeFile("gpx_file", "text/xml", associatedFile);
+                    // can also write bytes directly
+                    // out.writeFile("myFile", "text/plain", "C:\\test.txt",
+                    // "This is some file text.".getBytes("ASCII"));
+                    File tmp = File.createTempFile("josm", "tmp.gpx");
+                    FileOutputStream outs = new FileOutputStream(tmp);
+                    new GpxWriter(outs).write(data);
+                    outs.close();
+                    FileInputStream ins = new FileInputStream(tmp);
+                    new GpxWriter(System.out).write(data);
+                    out.writeFile("gpx_file", "text/xml", data.storageFile.getName(), ins);
+                    out.close();
+                    tmp.delete();
+                    // read response from server
+                    BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
+                    String line = "";
+                    while((line = in.readLine()) != null) {
+                        System.out.println(line);
+                    }
+                    in.close();
+
+                    //TODO check response
+                    /*                  int retCode = urlConn.getResponseCode();
+                    System.out.println("got return: " + retCode);
+                    String retMsg = urlConn.getResponseMessage();
+                    urlConn.disconnect();
+                    if (retCode != 200) {
+                        // Look for a detailed error message from the server
+                        if (urlConn.getHeaderField("Error") != null)
+                            retMsg += "\n" + urlConn.getHeaderField("Error");
+
+                        // Report our error
+                        ByteArrayOutputStream o = new ByteArrayOutputStream();
+                        System.out.println(new String(o.toByteArray(), "UTF-8").toString());
+                        throw new RuntimeException(retCode+" "+retMsg);
+                    }
+                     */
+                } catch (UnknownHostException ex) {
+                    throw new RuntimeException(tr("Unknown host")+": "+ex.getMessage(), ex);
+                } catch (Exception ex) {
+                    //if (cancel)
+                    //  return; // assume cancel
+                    if (ex instanceof RuntimeException)
+                        throw (RuntimeException)ex;
+                    throw new RuntimeException(ex.getMessage(), ex);
+                }
+            }
+        }
+    }
+
+    public class ConvertToDataLayerAction extends AbstractAction {
+        public ConvertToDataLayerAction() {
+            super(tr("Convert to data layer"), ImageProvider.get("converttoosm"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            JPanel msg = new JPanel(new GridBagLayout());
+            msg.add(new JLabel(tr("<html>Upload of unprocessed GPS data as map data is considered harmful.<br>If you want to upload traces, look here:")), GBC.eol());
+            msg.add(new UrlLabel(tr("http://www.openstreetmap.org/traces")), GBC.eop());
+            if (!DontShowAgainInfo.show("convert_to_data", msg))
+                return;
+            DataSet ds = new DataSet();
+            for (GpxTrack trk : data.tracks) {
+                for (Collection<WayPoint> segment : trk.trackSegs) {
+                    Way w = new Way();
+                    for (WayPoint p : segment) {
+                        Node n = new Node(p.latlon);
+                        String timestr = p.getString("time");
+                        if(timestr != null)
+                        {
+                            timestr = timestr.replace("Z","+00:00");
+                            n.timestamp = timestr;
+                        }
+                        ds.nodes.add(n);
+                        w.nodes.add(n);
+                    }
+                    ds.ways.add(w);
+                }
+            }
+            Main.main.addLayer(new OsmDataLayer(ds, tr("Converted from: {0}", GpxLayer.this.name), null));
+            Main.main.removeLayer(GpxLayer.this);
+        }
+    }
 
     /**
      * Action that issues a series of download requests to the API, following the GPX track.
-     * 
+     *
      * @author fred
      */
@@ -762,15 +762,15 @@
             JList buffer = new JList(new String[] { "50 metres", "500 metres", "5000 metres" });
             JList maxRect = new JList(new String[] { "1 sq km", "5 sq km", "10 sq km", "20 sq km" });
-            
+
             msg.add(new JLabel(tr("Download everything within:")), GBC.eol());
             msg.add(buffer, GBC.eol());
             msg.add(new JLabel(tr("Maximum area per request:")), GBC.eol());
             msg.add(maxRect, GBC.eol());
-            
-            if (JOptionPane.showConfirmDialog(Main.parent, msg, 
-                tr("Download from OSM along this track"), 
+
+            if (JOptionPane.showConfirmDialog(Main.parent, msg,
+                tr("Download from OSM along this track"),
                 JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
                 return;
-            
+
             }
 
@@ -781,5 +781,5 @@
             double latsum = 0;
             int latcnt = 0;
-            
+
             for (GpxTrack trk : data.tracks) {
                 for (Collection<WayPoint> segment : trk.trackSegs) {
@@ -790,5 +790,5 @@
                 }
             }
-            
+
             double avglat = latsum / latcnt;
             double scale = Math.cos(Math.toRadians(avglat));
@@ -797,6 +797,6 @@
              * Compute buffer zone extents and maximum bounding box size. Note how the
              * maximum we ever offer is a bbox area of 0.002, while the API theoretically
-             * supports 0.25, but as soon as you touch any built-up area, that kind of 
-             * bounding box will download forever and then stop because it has more than 
+             * supports 0.25, but as soon as you touch any built-up area, that kind of
+             * bounding box will download forever and then stop because it has more than
              * 50k nodes.
              */
@@ -809,5 +809,5 @@
             }
             buffer_x = buffer_y / scale;
-            
+
             double max_area;
             switch(maxRect.getSelectedIndex()) {
@@ -820,5 +820,5 @@
             Area a = new Area();
             Rectangle2D r = new Rectangle2D.Double();
-            
+
             /*
              * Collect the combined area of all gpx points plus buffer zones around them.
@@ -836,5 +836,5 @@
                 }
             }
-            
+
             /*
              * Area "a" now contains the hull that we would like to download data for.
@@ -858,20 +858,20 @@
              * actually has something in it.
              */
-            
+
             List<Rectangle2D> toDownload = new ArrayList<Rectangle2D>();
-            
+
             addToDownload(a, a.getBounds(), toDownload, max_area);
-            
+
             msg = new JPanel(new GridBagLayout());
-                       
+
             msg.add(new JLabel(tr("<html>This action will require {0} individual<br>download requests. Do you wish<br>to continue?</html>",
                 toDownload.size())), GBC.eol());
-            
-            if (JOptionPane.showConfirmDialog(Main.parent, msg, 
-                tr("Download from OSM along this track"), 
+
+            if (JOptionPane.showConfirmDialog(Main.parent, msg,
+                tr("Download from OSM along this track"),
                 JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
                 return;
             }
-            
+
             // FIXME: DownloadTask's "please wait" dialog should display the number of
             // downloads left, and "cancel" needs to be honoured. An error along the way
@@ -883,5 +883,5 @@
         }
     }
-    
+
     private static void addToDownload(Area a, Rectangle2D r, Collection<Rectangle2D> results, double max_area) {
         Area tmp = new Area(r);
@@ -909,266 +909,266 @@
         }
     }
-    
-	/**
-	 * Makes a new marker layer derived from this GpxLayer containing at least one
-	 * audio marker which the given audio file is associated with.
-	 * Markers are derived from the following
-	 * (a) explict waypoints in the GPX layer, or
-	 * (b) named trackpoints in the GPX layer, or
-	 * (c) (in future) voice recognised markers in the sound recording
-	 * (d) a single marker at the beginning of the track
-	 * @param wavFile : the file to be associated with the markers in the new marker layer
-	 */
-	private void importAudio(File wavFile) {
-		String uri = "file:".concat(wavFile.getAbsolutePath());
-		MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", name), associatedFile, me);
-
-		Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
-		boolean timedMarkersOmitted = false;
-		boolean untimedMarkersOmitted = false;
-		double snapDistance = Main.pref.getDouble("marker.audiofromuntimedwaypoints.distance", 1.0e-3); /* about 25m */
-
-		// determine time of first point in track
-		double firstTime = -1.0;
-		if (data.tracks != null && ! data.tracks.isEmpty()) {
-			for (GpxTrack track : data.tracks) {
-				if (track.trackSegs == null) continue;
-				for (Collection<WayPoint> seg : track.trackSegs) {
-					for (WayPoint w : seg) {
-						firstTime = w.time;
-						break;
-					}
-					if (firstTime >= 0.0) break;
-				}
-				if (firstTime >= 0.0) break;
-			}
-		}
-		if (firstTime < 0.0) {
-			JOptionPane.showMessageDialog(Main.parent, tr("No GPX track available in layer to associate audio with."));
-			return;
-		}
-
-		// (a) try explicit timestamped waypoints - unless suppressed
-		if (Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true) &&
-			data.waypoints != null && ! data.waypoints.isEmpty())
-		{
-			for (WayPoint w : data.waypoints) {
-				if (w.time > firstTime) {
-					waypoints.add(w);
-				} else if (w.time > 0.0) {
-					timedMarkersOmitted = true;
-				}
-			}
-		}
-
-		// (b) try explicit waypoints without timestamps - unless suppressed
-		if (Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true) &&
-			data.waypoints != null && ! data.waypoints.isEmpty())
-		{
-			for (WayPoint w : data.waypoints) {
-				if (waypoints.contains(w)) { continue; }
-				WayPoint wNear = nearestPointOnTrack(w.eastNorth, snapDistance);
-				if (wNear != null) {
-					WayPoint wc = new WayPoint(w.latlon);
-					wc.time = wNear.time;
-					if (w.attr.containsKey("name")) wc.attr.put("name", w.getString("name"));
-					waypoints.add(wc);
-				} else {
-					untimedMarkersOmitted = true;
-				}
-			}
-		}
-
-		// (c) use explicitly named track points, again unless suppressed
-		if ((Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false)) &&
-			data.tracks != null && ! data.tracks.isEmpty())
-		{
-			for (GpxTrack track : data.tracks) {
-				if (track.trackSegs == null) continue;
-				for (Collection<WayPoint> seg : track.trackSegs) {
-					for (WayPoint w : seg) {
-						if (w.attr.containsKey("name") || w.attr.containsKey("desc")) {
-							waypoints.add(w);
-						}
-					}
-				}
-			}
-		}
-
-		// (d) analyse audio for spoken markers here, in due course
-
-		// (e) simply add a single marker at the start of the track
-		if ((Main.pref.getBoolean("marker.audiofromstart") || waypoints.isEmpty()) &&
-			data.tracks != null && ! data.tracks.isEmpty())
-		{
-			boolean gotOne = false;
-			for (GpxTrack track : data.tracks) {
-				if (track.trackSegs == null) continue;
-				for (Collection<WayPoint> seg : track.trackSegs) {
-					for (WayPoint w : seg) {
-						WayPoint wStart = new WayPoint(w.latlon);
-						wStart.attr.put("name", "start");
-						wStart.time = w.time;
-						waypoints.add(wStart);
-						gotOne = true;
-						break;
-					}
-					if (gotOne) break;
-				}
-				if (gotOne) break;
-			}
-		}
-
-		/* we must have got at least one waypoint now */
-
-		Collections.sort((ArrayList<WayPoint>) waypoints, new Comparator<WayPoint>() {
-			public int compare(WayPoint a, WayPoint b) {
-				return a.time <= b.time ? -1 : 1;
-			}
-		});
-
-		firstTime = -1.0; /* this time of the first waypoint, not first trackpoint */
-		for (WayPoint w : waypoints) {
-			if (firstTime < 0.0) firstTime = w.time;
-			double offset = w.time - firstTime;
-			String name;
-			if (w.attr.containsKey("name"))
-				name = w.getString("name");
-			else if (w.attr.containsKey("desc"))
-				name = w.getString("desc");
-			else
-				name = AudioMarker.inventName(offset);
-			AudioMarker am = AudioMarker.create(w.latlon,
-					name, uri, ml, w.time, offset);
-			ml.data.add(am);
-		}
-		Main.main.addLayer(ml);
-
-		if (timedMarkersOmitted) {
-			JOptionPane.showMessageDialog(Main.parent,
-			tr("Some waypoints with timestamps from before the start of the track were omitted."));
-		}
-		if (untimedMarkersOmitted) {
-			JOptionPane.showMessageDialog(Main.parent,
-			tr("Some waypoints which were too far from the track to sensibly estimate their time were omitted."));
-		}
-	}
-
-	/**
-	 * Makes a WayPoint at the projection of point P onto the track providing P is
-	 * less than tolerance away from the track
-
-	 * @param P : the point to determine the projection for
-	 * @param tolerance : must be no further than this from the track
-	 * @return the closest point on the track to P, which may be the
-	 * first or last point if off the end of a segment, or may be null if
-	 * nothing close enough
-	 */
-	public WayPoint nearestPointOnTrack(EastNorth P, double tolerance) {
-		/*
-		 * assume the coordinates of P are xp,yp, and those of a section of track
-		 * between two trackpoints are R=xr,yr and S=xs,ys. Let N be the projected point.
-		 *
-		 * The equation of RS is Ax + By + C = 0 where
-		 * A = ys - yr
-		 * B = xr - xs
-		 * C = - Axr - Byr
-		 *
-		 * Also, note that the distance RS^2 is A^2 + B^2
-		 *
-		 * If RS^2 == 0.0 ignore the degenerate section of track
-		 *
-		 * PN^2 = (Axp + Byp + C)^2 / RS^2
-		 * that is the distance from P to the line
-		 *
-		 * so if PN^2 is less than PNmin^2 (initialized to tolerance) we can reject
-		 * the line; otherwise...
-		 * determine if the projected poijnt lies within the bounds of the line:
-		 * PR^2 - PN^2 <= RS^2 and PS^2 - PN^2 <= RS^2
-		 *
-		 * where PR^2 = (xp - xr)^2 + (yp-yr)^2
-		 * and   PS^2 = (xp - xs)^2 + (yp-ys)^2
-		 *
-		 * If so, calculate N as
-		 * xn = xr + (RN/RS) B
-		 * yn = y1 + (RN/RS) A
-		 *
-		 * where RN = sqrt(PR^2 - PN^2)
-		 */
-
-		double PNminsq = tolerance * tolerance;
-		EastNorth bestEN = null;
-		double bestTime = 0.0;
-		double px = P.east();
-		double py = P.north();
-		double rx = 0.0, ry = 0.0, sx, sy, x, y;
-		if (data.tracks == null) return null;
-		for (GpxTrack track : data.tracks) {
-			if (track.trackSegs == null) continue;
-			for (Collection<WayPoint> seg : track.trackSegs) {
-				WayPoint R = null;
-				for (WayPoint S : seg) {
-					if (R == null) {
-						R = S;
-						rx = R.eastNorth.east();
-						ry = R.eastNorth.north();
-						x = px - rx;
-						y = py - ry;
-						double PRsq = x * x + y * y;
-						if (PRsq < PNminsq) {
-							PNminsq = PRsq;
-							bestEN = R.eastNorth;
-							bestTime = R.time;
-						}
-					} else {
-						sx = S.eastNorth.east();
-						sy = S.eastNorth.north();
-						double A = sy - ry;
-						double B = rx - sx;
-						double C = - A * rx - B * ry;
-						double RSsq = A * A + B * B;
-						if (RSsq == 0.0) continue;
-						double PNsq = A * px + B * py + C;
-						PNsq = PNsq * PNsq / RSsq;
-						if (PNsq < PNminsq) {
-							x = px - rx;
-							y = py - ry;
-							double PRsq = x * x + y * y;
-							x = px - sx;
-							y = py - sy;
-							double PSsq = x * x + y * y;
-							if (PRsq - PNsq <= RSsq && PSsq - PNsq <= RSsq) {
-								double RNoverRS = Math.sqrt((PRsq - PNsq)/RSsq);
-								double nx = rx - RNoverRS * B;
-								double ny = ry + RNoverRS * A;
-								bestEN = new EastNorth(nx, ny);
-								bestTime = R.time + RNoverRS * (S.time - R.time);
-								PNminsq = PNsq;
-							}
-						}
-						R = S;
-						rx = sx;
-						ry = sy;
-					}
-				}
-				if (R != null) {
-					/* if there is only one point in the seg, it will do this twice, but no matter */
-					rx = R.eastNorth.east();
-					ry = R.eastNorth.north();
-					x = px - rx;
-					y = py - ry;
-					double PRsq = x * x + y * y;
-					if (PRsq < PNminsq) {
-						PNminsq = PRsq;
-						bestEN = R.eastNorth;
-						bestTime = R.time;
-					}
-				}
-			}
-		}
-		if (bestEN == null) return null;
-		WayPoint best = new WayPoint(Main.proj.eastNorth2latlon(bestEN));
-		best.time = bestTime;
-		return best;
-	}
+
+    /**
+     * Makes a new marker layer derived from this GpxLayer containing at least one
+     * audio marker which the given audio file is associated with.
+     * Markers are derived from the following
+     * (a) explict waypoints in the GPX layer, or
+     * (b) named trackpoints in the GPX layer, or
+     * (c) (in future) voice recognised markers in the sound recording
+     * (d) a single marker at the beginning of the track
+     * @param wavFile : the file to be associated with the markers in the new marker layer
+     */
+    private void importAudio(File wavFile) {
+        String uri = "file:".concat(wavFile.getAbsolutePath());
+        MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", name), associatedFile, me);
+
+        Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
+        boolean timedMarkersOmitted = false;
+        boolean untimedMarkersOmitted = false;
+        double snapDistance = Main.pref.getDouble("marker.audiofromuntimedwaypoints.distance", 1.0e-3); /* about 25m */
+
+        // determine time of first point in track
+        double firstTime = -1.0;
+        if (data.tracks != null && ! data.tracks.isEmpty()) {
+            for (GpxTrack track : data.tracks) {
+                if (track.trackSegs == null) continue;
+                for (Collection<WayPoint> seg : track.trackSegs) {
+                    for (WayPoint w : seg) {
+                        firstTime = w.time;
+                        break;
+                    }
+                    if (firstTime >= 0.0) break;
+                }
+                if (firstTime >= 0.0) break;
+            }
+        }
+        if (firstTime < 0.0) {
+            JOptionPane.showMessageDialog(Main.parent, tr("No GPX track available in layer to associate audio with."));
+            return;
+        }
+
+        // (a) try explicit timestamped waypoints - unless suppressed
+        if (Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true) &&
+            data.waypoints != null && ! data.waypoints.isEmpty())
+        {
+            for (WayPoint w : data.waypoints) {
+                if (w.time > firstTime) {
+                    waypoints.add(w);
+                } else if (w.time > 0.0) {
+                    timedMarkersOmitted = true;
+                }
+            }
+        }
+
+        // (b) try explicit waypoints without timestamps - unless suppressed
+        if (Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true) &&
+            data.waypoints != null && ! data.waypoints.isEmpty())
+        {
+            for (WayPoint w : data.waypoints) {
+                if (waypoints.contains(w)) { continue; }
+                WayPoint wNear = nearestPointOnTrack(w.eastNorth, snapDistance);
+                if (wNear != null) {
+                    WayPoint wc = new WayPoint(w.latlon);
+                    wc.time = wNear.time;
+                    if (w.attr.containsKey("name")) wc.attr.put("name", w.getString("name"));
+                    waypoints.add(wc);
+                } else {
+                    untimedMarkersOmitted = true;
+                }
+            }
+        }
+
+        // (c) use explicitly named track points, again unless suppressed
+        if ((Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false)) &&
+            data.tracks != null && ! data.tracks.isEmpty())
+        {
+            for (GpxTrack track : data.tracks) {
+                if (track.trackSegs == null) continue;
+                for (Collection<WayPoint> seg : track.trackSegs) {
+                    for (WayPoint w : seg) {
+                        if (w.attr.containsKey("name") || w.attr.containsKey("desc")) {
+                            waypoints.add(w);
+                        }
+                    }
+                }
+            }
+        }
+
+        // (d) analyse audio for spoken markers here, in due course
+
+        // (e) simply add a single marker at the start of the track
+        if ((Main.pref.getBoolean("marker.audiofromstart") || waypoints.isEmpty()) &&
+            data.tracks != null && ! data.tracks.isEmpty())
+        {
+            boolean gotOne = false;
+            for (GpxTrack track : data.tracks) {
+                if (track.trackSegs == null) continue;
+                for (Collection<WayPoint> seg : track.trackSegs) {
+                    for (WayPoint w : seg) {
+                        WayPoint wStart = new WayPoint(w.latlon);
+                        wStart.attr.put("name", "start");
+                        wStart.time = w.time;
+                        waypoints.add(wStart);
+                        gotOne = true;
+                        break;
+                    }
+                    if (gotOne) break;
+                }
+                if (gotOne) break;
+            }
+        }
+
+        /* we must have got at least one waypoint now */
+
+        Collections.sort((ArrayList<WayPoint>) waypoints, new Comparator<WayPoint>() {
+            public int compare(WayPoint a, WayPoint b) {
+                return a.time <= b.time ? -1 : 1;
+            }
+        });
+
+        firstTime = -1.0; /* this time of the first waypoint, not first trackpoint */
+        for (WayPoint w : waypoints) {
+            if (firstTime < 0.0) firstTime = w.time;
+            double offset = w.time - firstTime;
+            String name;
+            if (w.attr.containsKey("name"))
+                name = w.getString("name");
+            else if (w.attr.containsKey("desc"))
+                name = w.getString("desc");
+            else
+                name = AudioMarker.inventName(offset);
+            AudioMarker am = AudioMarker.create(w.latlon,
+                    name, uri, ml, w.time, offset);
+            ml.data.add(am);
+        }
+        Main.main.addLayer(ml);
+
+        if (timedMarkersOmitted) {
+            JOptionPane.showMessageDialog(Main.parent,
+            tr("Some waypoints with timestamps from before the start of the track were omitted."));
+        }
+        if (untimedMarkersOmitted) {
+            JOptionPane.showMessageDialog(Main.parent,
+            tr("Some waypoints which were too far from the track to sensibly estimate their time were omitted."));
+        }
+    }
+
+    /**
+     * Makes a WayPoint at the projection of point P onto the track providing P is
+     * less than tolerance away from the track
+
+     * @param P : the point to determine the projection for
+     * @param tolerance : must be no further than this from the track
+     * @return the closest point on the track to P, which may be the
+     * first or last point if off the end of a segment, or may be null if
+     * nothing close enough
+     */
+    public WayPoint nearestPointOnTrack(EastNorth P, double tolerance) {
+        /*
+         * assume the coordinates of P are xp,yp, and those of a section of track
+         * between two trackpoints are R=xr,yr and S=xs,ys. Let N be the projected point.
+         *
+         * The equation of RS is Ax + By + C = 0 where
+         * A = ys - yr
+         * B = xr - xs
+         * C = - Axr - Byr
+         *
+         * Also, note that the distance RS^2 is A^2 + B^2
+         *
+         * If RS^2 == 0.0 ignore the degenerate section of track
+         *
+         * PN^2 = (Axp + Byp + C)^2 / RS^2
+         * that is the distance from P to the line
+         *
+         * so if PN^2 is less than PNmin^2 (initialized to tolerance) we can reject
+         * the line; otherwise...
+         * determine if the projected poijnt lies within the bounds of the line:
+         * PR^2 - PN^2 <= RS^2 and PS^2 - PN^2 <= RS^2
+         *
+         * where PR^2 = (xp - xr)^2 + (yp-yr)^2
+         * and   PS^2 = (xp - xs)^2 + (yp-ys)^2
+         *
+         * If so, calculate N as
+         * xn = xr + (RN/RS) B
+         * yn = y1 + (RN/RS) A
+         *
+         * where RN = sqrt(PR^2 - PN^2)
+         */
+
+        double PNminsq = tolerance * tolerance;
+        EastNorth bestEN = null;
+        double bestTime = 0.0;
+        double px = P.east();
+        double py = P.north();
+        double rx = 0.0, ry = 0.0, sx, sy, x, y;
+        if (data.tracks == null) return null;
+        for (GpxTrack track : data.tracks) {
+            if (track.trackSegs == null) continue;
+            for (Collection<WayPoint> seg : track.trackSegs) {
+                WayPoint R = null;
+                for (WayPoint S : seg) {
+                    if (R == null) {
+                        R = S;
+                        rx = R.eastNorth.east();
+                        ry = R.eastNorth.north();
+                        x = px - rx;
+                        y = py - ry;
+                        double PRsq = x * x + y * y;
+                        if (PRsq < PNminsq) {
+                            PNminsq = PRsq;
+                            bestEN = R.eastNorth;
+                            bestTime = R.time;
+                        }
+                    } else {
+                        sx = S.eastNorth.east();
+                        sy = S.eastNorth.north();
+                        double A = sy - ry;
+                        double B = rx - sx;
+                        double C = - A * rx - B * ry;
+                        double RSsq = A * A + B * B;
+                        if (RSsq == 0.0) continue;
+                        double PNsq = A * px + B * py + C;
+                        PNsq = PNsq * PNsq / RSsq;
+                        if (PNsq < PNminsq) {
+                            x = px - rx;
+                            y = py - ry;
+                            double PRsq = x * x + y * y;
+                            x = px - sx;
+                            y = py - sy;
+                            double PSsq = x * x + y * y;
+                            if (PRsq - PNsq <= RSsq && PSsq - PNsq <= RSsq) {
+                                double RNoverRS = Math.sqrt((PRsq - PNsq)/RSsq);
+                                double nx = rx - RNoverRS * B;
+                                double ny = ry + RNoverRS * A;
+                                bestEN = new EastNorth(nx, ny);
+                                bestTime = R.time + RNoverRS * (S.time - R.time);
+                                PNminsq = PNsq;
+                            }
+                        }
+                        R = S;
+                        rx = sx;
+                        ry = sy;
+                    }
+                }
+                if (R != null) {
+                    /* if there is only one point in the seg, it will do this twice, but no matter */
+                    rx = R.eastNorth.east();
+                    ry = R.eastNorth.north();
+                    x = px - rx;
+                    y = py - ry;
+                    double PRsq = x * x + y * y;
+                    if (PRsq < PNminsq) {
+                        PNminsq = PRsq;
+                        bestEN = R.eastNorth;
+                        bestTime = R.time;
+                    }
+                }
+            }
+        }
+        if (bestEN == null) return null;
+        WayPoint best = new WayPoint(Main.proj.eastNorth2latlon(bestEN));
+        best.time = bestTime;
+        return best;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 1169)
@@ -17,106 +17,106 @@
 /**
  * A layer encapsulates the gui componente of one dataset and its representation.
- * 
- * Some layers may display data directly importet from OSM server. Other only 
- * display background images. Some can be edited, some not. Some are static and 
+ *
+ * Some layers may display data directly importet from OSM server. Other only
+ * display background images. Some can be edited, some not. Some are static and
  * other changes dynamically (auto-updated).
  *
  * Layers can be visible or not. Most actions the user can do applies only on
  * selected layers. The available actions depend on the selected layers too.
- * 
- * All layers are managed by the MapView. They are displayed in a list to the 
+ *
+ * All layers are managed by the MapView. They are displayed in a list to the
  * right of the screen.
- * 
+ *
  * @author imi
  */
 abstract public class Layer implements Destroyable, MapViewPaintable {
 
-	/**
-	 * Interface to notify listeners of the change of the active layer.
-	 * @author imi
-	 */
-	public interface LayerChangeListener {
-		void activeLayerChange(Layer oldLayer, Layer newLayer);
-		void layerAdded(Layer newLayer);
-		void layerRemoved(Layer oldLayer);
-	}
+    /**
+     * Interface to notify listeners of the change of the active layer.
+     * @author imi
+     */
+    public interface LayerChangeListener {
+        void activeLayerChange(Layer oldLayer, Layer newLayer);
+        void layerAdded(Layer newLayer);
+        void layerRemoved(Layer oldLayer);
+    }
 
-	/**
-	 * The listener of the active layer changes. You may register/deregister yourself
-	 * while an LayerChangeListener - action is executed.
-	 */
-	public static final Collection<LayerChangeListener> listeners = new CopyOnWriteArrayList<LayerChangeListener>();
+    /**
+     * The listener of the active layer changes. You may register/deregister yourself
+     * while an LayerChangeListener - action is executed.
+     */
+    public static final Collection<LayerChangeListener> listeners = new CopyOnWriteArrayList<LayerChangeListener>();
 
-	/**
-	 * The visibility state of the layer.
-	 */
-	public boolean visible = true;
+    /**
+     * The visibility state of the layer.
+     */
+    public boolean visible = true;
 
-	/**
-	 * The layer should be handled as a background layer in automatic handling
-	 */
-	public boolean background = false;
+    /**
+     * The layer should be handled as a background layer in automatic handling
+     */
+    public boolean background = false;
 
-	/**
-	 * The name of this layer.
-	 */
-	public String name;
-	/**
-	 * If a file is associated with this layer, this variable should be set to it.
-	 */
-	public File associatedFile;
+    /**
+     * The name of this layer.
+     */
+    public String name;
+    /**
+     * If a file is associated with this layer, this variable should be set to it.
+     */
+    public File associatedFile;
 
-	/**
-	 * Create the layer and fill in the necessary components.
-	 */
-	public Layer(String name) {
-		this.name = name;
-	}
+    /**
+     * Create the layer and fill in the necessary components.
+     */
+    public Layer(String name) {
+        this.name = name;
+    }
 
-	/**
-	 * Paint the dataset using the engine set.
-	 * @param mv The object that can translate GeoPoints to screen coordinates.
-	 */
-	abstract public void paint(Graphics g, MapView mv);
-	/**
-	 * Return a representative small image for this layer. The image must not 
-	 * be larger than 64 pixel in any dimension.
-	 */
-	abstract public Icon getIcon();
+    /**
+     * Paint the dataset using the engine set.
+     * @param mv The object that can translate GeoPoints to screen coordinates.
+     */
+    abstract public void paint(Graphics g, MapView mv);
+    /**
+     * Return a representative small image for this layer. The image must not
+     * be larger than 64 pixel in any dimension.
+     */
+    abstract public Icon getIcon();
 
-	/**
-	 * @return A small tooltip hint about some statistics for this layer.
-	 */
-	abstract public String getToolTipText();
+    /**
+     * @return A small tooltip hint about some statistics for this layer.
+     */
+    abstract public String getToolTipText();
 
-	/**
-	 * Merges the given layer into this layer. Throws if the layer types are
-	 * incompatible.
-	 * @param from The layer that get merged into this one. After the merge,
-	 * 		the other layer is not usable anymore and passing to one others
-	 * 		mergeFrom should be one of the last things to do with a layer.
-	 */
-	abstract public void mergeFrom(Layer from);
-	
-	/**
-	 * @param other The other layer that is tested to be mergable with this.
-	 * @return Whether the other layer can be merged into this layer.
-	 */
-	abstract public boolean isMergable(Layer other);
+    /**
+     * Merges the given layer into this layer. Throws if the layer types are
+     * incompatible.
+     * @param from The layer that get merged into this one. After the merge,
+     *      the other layer is not usable anymore and passing to one others
+     *      mergeFrom should be one of the last things to do with a layer.
+     */
+    abstract public void mergeFrom(Layer from);
 
-	abstract public void visitBoundingBox(BoundingXYVisitor v);
+    /**
+     * @param other The other layer that is tested to be mergable with this.
+     * @return Whether the other layer can be merged into this layer.
+     */
+    abstract public boolean isMergable(Layer other);
 
-	abstract public Object getInfoComponent();
-	
-	abstract public Component[] getMenuEntries();
-	
-	/**
-	 * Called, when the layer is removed from the mapview and is going to be
-	 * destroyed.
-	 * 
-	 * This is because the Layer constructor can not add itself safely as listener
-	 * to the layerlist dialog, because there may be no such dialog yet (loaded
-	 * via command line parameter).
-	 */
-	public void destroy() {}
+    abstract public void visitBoundingBox(BoundingXYVisitor v);
+
+    abstract public Object getInfoComponent();
+
+    abstract public Component[] getMenuEntries();
+
+    /**
+     * Called, when the layer is removed from the mapview and is going to be
+     * destroyed.
+     *
+     * This is because the Layer constructor can not add itself safely as listener
+     * to the layerlist dialog, because there may be no such dialog yet (loaded
+     * via command line parameter).
+     */
+    public void destroy() {}
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 1169)
@@ -8,9 +8,9 @@
 public interface MapViewPaintable {
 
-	/**
-	 * Paint the dataset using the engine set.
-	 * @param mv The object that can translate GeoPoints to screen coordinates.
-	 */
-	abstract public void paint(Graphics g, MapView mv);
+    /**
+     * Paint the dataset using the engine set.
+     * @param mv The object that can translate GeoPoints to screen coordinates.
+     */
+    abstract public void paint(Graphics g, MapView mv);
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 1169)
@@ -68,5 +68,5 @@
  * A layer holding data from a specific dataset.
  * The data can be fully edited.
- * 
+ *
  * @author imi
  */
@@ -74,5 +74,5 @@
 
     public final static class DataCountVisitor implements Visitor {
-        public final int[] normal = new int[3];        
+        public final int[] normal = new int[3];
         public final int[] deleted = new int[3];
         public final String[] names = {"node", "way", "relation"};
@@ -131,5 +131,5 @@
      */
     private static TexturePaint hatched;
-    
+
     static {
         createHatchTexture();
@@ -178,15 +178,15 @@
         boolean inactive = !active && Main.pref.getBoolean("draw.data.inactive_color", true);
         boolean virtual = !inactive && Main.map.mapView.useVirtualNodes();
-        
-        // draw the hatched area for non-downloaded region. only draw if we're the active 
+
+        // draw the hatched area for non-downloaded region. only draw if we're the active
         // and bounds are defined; don't draw for inactive layers or loaded GPX files etc
         if (active && Main.pref.getBoolean("draw.data.downloaded_area", true) && !data.dataSources.isEmpty()) {
             // initialize area with current viewport
             Rectangle b = Main.map.mapView.getBounds();
-            // on some platforms viewport bounds seem to be offset from the left, 
+            // on some platforms viewport bounds seem to be offset from the left,
             // over-grow it just to be sure
             b.grow(100, 100);
             Area a = new Area(b);
-            
+
             // now succesively subtract downloaded areas
             for (DataSource src : data.dataSources) {
@@ -200,10 +200,10 @@
                 }
             }
-            
+
             // paint remainder
             ((Graphics2D)g).setPaint(hatched);
             ((Graphics2D)g).fill(a);
         }
-    
+
         SimplePaintVisitor painter;
         if (Main.pref.getBoolean("draw.wireframe"))
@@ -234,10 +234,10 @@
 
         // copy the merged layer's data source info
-        for (DataSource src : ((OsmDataLayer)from).data.dataSources) 
+        for (DataSource src : ((OsmDataLayer)from).data.dataSources)
             data.dataSources.add(src);
         fireDataChange();
         // repaint to make sure new data is displayed properly.
         Main.map.mapView.repaint();
-        
+
         if (visitor.conflicts.isEmpty())
             return;
@@ -263,7 +263,7 @@
      * really deleting all deleted objects and reset the modified flags. This is done
      * after a successfull upload.
-     * 
-     * @param processed A list of all objects that were actually uploaded. 
-     *         May be <code>null</code>, which means nothing has been uploaded but 
+     *
+     * @param processed A list of all objects that were actually uploaded.
+     *         May be <code>null</code>, which means nothing has been uploaded but
      *         saved to disk instead. Note that an empty collection for "processed"
      *      means that an upload has been attempted but failed.
@@ -274,5 +274,5 @@
         if (processed != null && processed.isEmpty() && !dataAdded)
             return;
-        
+
         Main.main.undoRedo.clean();
 
@@ -300,5 +300,5 @@
      * Clean the modified flag for the given iterator over a collection if it is in the
      * list of processed entries.
-     * 
+     *
      * @param it The iterator to change the modified and remove the items if deleted.
      * @param processed A list of all objects that have been successfully progressed.
@@ -415,6 +415,6 @@
             }
         }
-        
-        // what is this loop meant to do? it creates waypoints but never 
+
+        // what is this loop meant to do? it creates waypoints but never
         // records them?
         for (Node n : data.nodes) {
Index: trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java	(revision 1169)
@@ -57,322 +57,322 @@
  * A layer holding data from a gps source.
  * The data is read only.
- * 
+ *
  * @author imi
  */
 public class RawGpsLayer extends Layer implements PreferenceChangedListener {
 
-	public class ConvertToDataLayerAction extends AbstractAction {
-		public ConvertToDataLayerAction() {
-			super(tr("Convert to data layer"), ImageProvider.get("converttoosm"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			JPanel msg = new JPanel(new GridBagLayout());
-			msg.add(new JLabel(tr("<html>Upload of unprocessed GPS data as map data is considered harmful.<br>If you want to upload traces, look here:")), GBC.eol());
-			msg.add(new UrlLabel(tr("http://www.openstreetmap.org/traces")), GBC.eop());
-			if (!DontShowAgainInfo.show("convert_to_data", msg))
-				return;
-			DataSet ds = new DataSet();
-			for (Collection<GpsPoint> c : data) {
-				Way w = new Way();
-				for (GpsPoint p : c) {
-					Node n = new Node(p.latlon);
-					ds.nodes.add(n);
-					w.nodes.add(n);
-				}
-				ds.ways.add(w);
-			}
-			Main.main.addLayer(new OsmDataLayer(ds, tr("Converted from: {0}", RawGpsLayer.this.name), null));
-			Main.main.removeLayer(RawGpsLayer.this);
-		}
-	}
-	
-	public class UploadTraceAction extends AbstractAction {
-		public UploadTraceAction() {
-			super(tr("Upload this trace..."), ImageProvider.get("uploadtrace"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			JPanel msg = new JPanel(new GridBagLayout());
-			msg.add(new JLabel(tr("<html>This functionality has been added only recently. Please<br>"+
-					              "use with care and check if it works as expected.</html>")), GBC.eop());
-			ButtonGroup bg = new ButtonGroup();
-			JRadioButton c1 = null;
-			JRadioButton c2 = null;
-			
-			if (associatedFile != null) {
-				c1 = new JRadioButton(tr("Upload track filtered by JOSM"), false);
-				c2 = new JRadioButton(tr("Upload raw file: {0}", associatedFile.getName()), true);
-			}
-			else
-			{
-				c1 = new JRadioButton(tr("Upload track filtered by JOSM"), true);
-				c2 = new JRadioButton(tr("Upload raw file: "), false);
-				c2.setEnabled(false);
-			}
-			c1.setEnabled(false);
-			bg.add(c1);
-			bg.add(c2);
-
-			msg.add(c1, GBC.eol());
-			msg.add(c2, GBC.eop());
-
-			
-			JTextField description = new JTextField();
-			JTextField tags = new JTextField();
-			msg.add(new JLabel(tr("Description:")), GBC.std());
-			msg.add(description, GBC.eol().fill(GBC.HORIZONTAL));
-			msg.add(new JLabel(tr("Tags:")), GBC.std());
-			msg.add(tags, GBC.eol().fill(GBC.HORIZONTAL));
-			JCheckBox c3 = new JCheckBox("public");
-			msg.add(c3, GBC.eop());
-			msg.add(new JLabel("Please ensure that you don't upload your traces twice."), GBC.eop());
-			
-			int answer = JOptionPane.showConfirmDialog(Main.parent, msg, tr("GPX-Upload"), JOptionPane.OK_CANCEL_OPTION);
-			if (answer == JOptionPane.OK_OPTION)
-			{
-				try {
-					String version = Main.pref.get("osm-server.version", "0.5");
-					URL url = new URL(Main.pref.get("osm-server.url") +
-							"/" + version + "/gpx/create");
-
-					// create a boundary string
-					String boundary = MultiPartFormOutputStream.createBoundary();
-					URLConnection urlConn = MultiPartFormOutputStream.createConnection(url);
-					urlConn.setRequestProperty("Accept", "*/*");
-					urlConn.setRequestProperty("Content-Type", 
-						MultiPartFormOutputStream.getContentType(boundary));
-					// set some other request headers...
-					urlConn.setRequestProperty("Connection", "Keep-Alive");
-					urlConn.setRequestProperty("Cache-Control", "no-cache");
-					// no need to connect cuz getOutputStream() does it
-					MultiPartFormOutputStream out = 
-						new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
-					out.writeField("description", description.getText());
-					out.writeField("tags", tags.getText());
-					out.writeField("public", (c3.getSelectedObjects() != null) ? "1" : "0");
-					// upload a file
-					out.writeFile("gpx_file", "text/xml", associatedFile);
-					// can also write bytes directly
-					// out.writeFile("myFile", "text/plain", "C:\\test.txt", 
-					// "This is some file text.".getBytes("ASCII"));
-					out.close();
-					// read response from server
-					BufferedReader in = new BufferedReader(
-						new InputStreamReader(urlConn.getInputStream()));
-					String line = "";
-					while((line = in.readLine()) != null) {
-						 System.out.println(line);
-					}
-					in.close();
-					
-					/*
-					int retCode = activeConnection.getResponseCode();
-					System.out.println("got return: "+retCode);
-					String retMsg = activeConnection.getResponseMessage();
-					activeConnection.disconnect();
-					if (retCode != 200) {
-						// Look for a detailed error message from the server
-						if (activeConnection.getHeaderField("Error") != null)
-							retMsg += "\n" + activeConnection.getHeaderField("Error");
-
-						// Report our error
-						ByteArrayOutputStream o = new ByteArrayOutputStream();
-						System.out.println(new String(o.toByteArray(), "UTF-8").toString());
-						throw new RuntimeException(retCode+" "+retMsg);
-					}
-					*/
-				} catch (UnknownHostException ex) {
-					throw new RuntimeException(tr("Unknown host")+": "+ex.getMessage(), ex);
-				} catch (Exception ex) {
-					//if (cancel)
-					//	return; // assume cancel
-					if (ex instanceof RuntimeException)
-						throw (RuntimeException)ex;
-					throw new RuntimeException(ex.getMessage(), ex);
-				}	
-			}
-		}
-	}
-
-	public static class GpsPoint {
-		public final LatLon latlon;
-		public final EastNorth eastNorth;
-		public final String time;
-		public GpsPoint(LatLon ll, String t) {
-			latlon = ll; 
-			eastNorth = Main.proj.latlon2eastNorth(ll); 
-			time = t;
-		}
-	}
-
-	/**
-	 * A list of ways which containing a list of points.
-	 */
-	public final Collection<Collection<GpsPoint>> data;
-	public final boolean fromServer;
-
-	public RawGpsLayer(boolean fromServer, Collection<Collection<GpsPoint>> data, String name, File associatedFile) {
-		super(name);
-		this.fromServer = fromServer;
-		this.associatedFile = associatedFile;
-		this.data = data;
-		Main.pref.listener.add(this);
-	}
-
-	/**
-	 * Return a static icon.
-	 */
-	@Override public Icon getIcon() {
-		return ImageProvider.get("layer", "rawgps_small");
-	}
-
-	@Override public void paint(Graphics g, MapView mv) {
-		g.setColor(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
-		Point old = null;
-
-		boolean force = Main.pref.getBoolean("draw.rawgps.lines.force");
-		boolean lines = Main.pref.getBoolean("draw.rawgps.lines");
-		String linesKey = "draw.rawgps.lines.layer "+name;
-		if (Main.pref.hasKey(linesKey))
-			lines = Main.pref.getBoolean(linesKey);
-		boolean large = Main.pref.getBoolean("draw.rawgps.large");
-		for (Collection<GpsPoint> c : data) {
-			if (!force)
-				old = null;
-			for (GpsPoint p : c) {
-				Point screen = mv.getPoint(p.eastNorth);
-				if (lines && old != null)
-					g.drawLine(old.x, old.y, screen.x, screen.y);
-				else if (!large)
-					g.drawRect(screen.x, screen.y, 0, 0);
-				if (large)
-					g.fillRect(screen.x-1, screen.y-1, 3, 3);
-				old = screen;
-			}
-		}
-	}
-
-	@Override public String getToolTipText() {
-		int points = 0;
-		for (Collection<GpsPoint> c : data)
-			points += c.size();
-		String tool = data.size()+" "+trn("track", "tracks", data.size())
-		+" "+points+" "+trn("point", "points", points);
-		if (associatedFile != null)
-			tool = "<html>"+tool+"<br>"+associatedFile.getPath()+"</html>";
-		return tool;
-	}
-
-	@Override public void mergeFrom(Layer from) {
-		RawGpsLayer layer = (RawGpsLayer)from;
-		data.addAll(layer.data);
-	}
-
-	@Override public boolean isMergable(Layer other) {
-		return other instanceof RawGpsLayer;
-	}
-
-	@Override public void visitBoundingBox(BoundingXYVisitor v) {
-		for (Collection<GpsPoint> c : data)
-			for (GpsPoint p : c)
-				v.visit(p.eastNorth);
-	}
-
-	@Override public Object getInfoComponent() {
-		StringBuilder b = new StringBuilder();
-		int points = 0;
-		for (Collection<GpsPoint> c : data) {
-			b.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+trn("a track with {0} point","a track with {0} points", c.size(), c.size())+"<br>");
-			points += c.size();
-		}
-		b.append("</html>");
-		return "<html>"+trn("{0} consists of {1} track", "{0} consists of {1} tracks", data.size(), name, data.size())+" ("+trn("{0} point", "{0} points", points, points)+")<br>"+b.toString();
-	}
-
-	@Override public Component[] getMenuEntries() {
-		JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
-		line.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JRadioButton[] r = new JRadioButton[3];
-				r[0] = new JRadioButton(tr("Use global settings."));
-				r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
-				r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
-				ButtonGroup group = new ButtonGroup();
-				Box panel = Box.createVerticalBox();
-				for (JRadioButton b : r) {
-					group.add(b);
-					panel.add(b);
-				}
-				String propName = "draw.rawgps.lines.layer "+name;
-				if (Main.pref.hasKey(propName))
-					group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
-				else
-					group.setSelected(r[0].getModel(), true);
-				int answer = JOptionPane.showConfirmDialog(Main.parent, panel, tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION);
-				if (answer == JOptionPane.CANCEL_OPTION)
-					return;
-				if (group.getSelection() == r[0].getModel())
-					Main.pref.put(propName, null);
-				else
-					Main.pref.put(propName, group.getSelection() == r[1].getModel());
-				Main.map.repaint();
-			}
-		});
-
-		JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-		color.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
-				Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
-				int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
-				JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
-				switch (answer) {
-				case 0:
-					Main.pref.putColor("layer "+name, c.getColor());
-					break;
-				case 1:
-					return;
-				case 2:
-					Main.pref.putColor("layer "+name, null);
-					break;
-				}
-				Main.map.repaint();
-			}
-		});
-
-		if (Main.applet)
-			return new Component[]{
-				new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-				new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-				new JSeparator(),
-				color,
-				line,
-				new JMenuItem(new ConvertToDataLayerAction()),
-				//new JMenuItem(new UploadTraceAction()),
-				new JSeparator(),
-				new JMenuItem(new RenameLayerAction(associatedFile, this)),
-				new JSeparator(),
-				new JMenuItem(new LayerListPopup.InfoAction(this))};
-		return new Component[]{
-				new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-				new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-				new JSeparator(),
-				new JMenuItem(new GpxExportAction(this)),
-				color,
-				line,
-				new JMenuItem(new ConvertToDataLayerAction()),
-				//new JMenuItem(new UploadTraceAction()),
-				new JSeparator(),
-				new JMenuItem(new RenameLayerAction(associatedFile, this)),
-				new JSeparator(),
-				new JMenuItem(new LayerListPopup.InfoAction(this))};
-	}
-
-	public void preferenceChanged(String key, String newValue) {
-		if (Main.map != null && (key.equals("draw.rawgps.lines") || key.equals("draw.rawgps.lines.force")))
-			Main.map.repaint();
-	}
-
-	@Override public void destroy() {
-		Main.pref.listener.remove(RawGpsLayer.this);
+    public class ConvertToDataLayerAction extends AbstractAction {
+        public ConvertToDataLayerAction() {
+            super(tr("Convert to data layer"), ImageProvider.get("converttoosm"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            JPanel msg = new JPanel(new GridBagLayout());
+            msg.add(new JLabel(tr("<html>Upload of unprocessed GPS data as map data is considered harmful.<br>If you want to upload traces, look here:")), GBC.eol());
+            msg.add(new UrlLabel(tr("http://www.openstreetmap.org/traces")), GBC.eop());
+            if (!DontShowAgainInfo.show("convert_to_data", msg))
+                return;
+            DataSet ds = new DataSet();
+            for (Collection<GpsPoint> c : data) {
+                Way w = new Way();
+                for (GpsPoint p : c) {
+                    Node n = new Node(p.latlon);
+                    ds.nodes.add(n);
+                    w.nodes.add(n);
+                }
+                ds.ways.add(w);
+            }
+            Main.main.addLayer(new OsmDataLayer(ds, tr("Converted from: {0}", RawGpsLayer.this.name), null));
+            Main.main.removeLayer(RawGpsLayer.this);
+        }
+    }
+
+    public class UploadTraceAction extends AbstractAction {
+        public UploadTraceAction() {
+            super(tr("Upload this trace..."), ImageProvider.get("uploadtrace"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            JPanel msg = new JPanel(new GridBagLayout());
+            msg.add(new JLabel(tr("<html>This functionality has been added only recently. Please<br>"+
+                                  "use with care and check if it works as expected.</html>")), GBC.eop());
+            ButtonGroup bg = new ButtonGroup();
+            JRadioButton c1 = null;
+            JRadioButton c2 = null;
+
+            if (associatedFile != null) {
+                c1 = new JRadioButton(tr("Upload track filtered by JOSM"), false);
+                c2 = new JRadioButton(tr("Upload raw file: {0}", associatedFile.getName()), true);
+            }
+            else
+            {
+                c1 = new JRadioButton(tr("Upload track filtered by JOSM"), true);
+                c2 = new JRadioButton(tr("Upload raw file: "), false);
+                c2.setEnabled(false);
+            }
+            c1.setEnabled(false);
+            bg.add(c1);
+            bg.add(c2);
+
+            msg.add(c1, GBC.eol());
+            msg.add(c2, GBC.eop());
+
+
+            JTextField description = new JTextField();
+            JTextField tags = new JTextField();
+            msg.add(new JLabel(tr("Description:")), GBC.std());
+            msg.add(description, GBC.eol().fill(GBC.HORIZONTAL));
+            msg.add(new JLabel(tr("Tags:")), GBC.std());
+            msg.add(tags, GBC.eol().fill(GBC.HORIZONTAL));
+            JCheckBox c3 = new JCheckBox("public");
+            msg.add(c3, GBC.eop());
+            msg.add(new JLabel("Please ensure that you don't upload your traces twice."), GBC.eop());
+
+            int answer = JOptionPane.showConfirmDialog(Main.parent, msg, tr("GPX-Upload"), JOptionPane.OK_CANCEL_OPTION);
+            if (answer == JOptionPane.OK_OPTION)
+            {
+                try {
+                    String version = Main.pref.get("osm-server.version", "0.5");
+                    URL url = new URL(Main.pref.get("osm-server.url") +
+                            "/" + version + "/gpx/create");
+
+                    // create a boundary string
+                    String boundary = MultiPartFormOutputStream.createBoundary();
+                    URLConnection urlConn = MultiPartFormOutputStream.createConnection(url);
+                    urlConn.setRequestProperty("Accept", "*/*");
+                    urlConn.setRequestProperty("Content-Type",
+                        MultiPartFormOutputStream.getContentType(boundary));
+                    // set some other request headers...
+                    urlConn.setRequestProperty("Connection", "Keep-Alive");
+                    urlConn.setRequestProperty("Cache-Control", "no-cache");
+                    // no need to connect cuz getOutputStream() does it
+                    MultiPartFormOutputStream out =
+                        new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
+                    out.writeField("description", description.getText());
+                    out.writeField("tags", tags.getText());
+                    out.writeField("public", (c3.getSelectedObjects() != null) ? "1" : "0");
+                    // upload a file
+                    out.writeFile("gpx_file", "text/xml", associatedFile);
+                    // can also write bytes directly
+                    // out.writeFile("myFile", "text/plain", "C:\\test.txt",
+                    // "This is some file text.".getBytes("ASCII"));
+                    out.close();
+                    // read response from server
+                    BufferedReader in = new BufferedReader(
+                        new InputStreamReader(urlConn.getInputStream()));
+                    String line = "";
+                    while((line = in.readLine()) != null) {
+                         System.out.println(line);
+                    }
+                    in.close();
+
+                    /*
+                    int retCode = activeConnection.getResponseCode();
+                    System.out.println("got return: "+retCode);
+                    String retMsg = activeConnection.getResponseMessage();
+                    activeConnection.disconnect();
+                    if (retCode != 200) {
+                        // Look for a detailed error message from the server
+                        if (activeConnection.getHeaderField("Error") != null)
+                            retMsg += "\n" + activeConnection.getHeaderField("Error");
+
+                        // Report our error
+                        ByteArrayOutputStream o = new ByteArrayOutputStream();
+                        System.out.println(new String(o.toByteArray(), "UTF-8").toString());
+                        throw new RuntimeException(retCode+" "+retMsg);
+                    }
+                    */
+                } catch (UnknownHostException ex) {
+                    throw new RuntimeException(tr("Unknown host")+": "+ex.getMessage(), ex);
+                } catch (Exception ex) {
+                    //if (cancel)
+                    //  return; // assume cancel
+                    if (ex instanceof RuntimeException)
+                        throw (RuntimeException)ex;
+                    throw new RuntimeException(ex.getMessage(), ex);
+                }
+            }
+        }
+    }
+
+    public static class GpsPoint {
+        public final LatLon latlon;
+        public final EastNorth eastNorth;
+        public final String time;
+        public GpsPoint(LatLon ll, String t) {
+            latlon = ll;
+            eastNorth = Main.proj.latlon2eastNorth(ll);
+            time = t;
+        }
+    }
+
+    /**
+     * A list of ways which containing a list of points.
+     */
+    public final Collection<Collection<GpsPoint>> data;
+    public final boolean fromServer;
+
+    public RawGpsLayer(boolean fromServer, Collection<Collection<GpsPoint>> data, String name, File associatedFile) {
+        super(name);
+        this.fromServer = fromServer;
+        this.associatedFile = associatedFile;
+        this.data = data;
+        Main.pref.listener.add(this);
+    }
+
+    /**
+     * Return a static icon.
+     */
+    @Override public Icon getIcon() {
+        return ImageProvider.get("layer", "rawgps_small");
+    }
+
+    @Override public void paint(Graphics g, MapView mv) {
+        g.setColor(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
+        Point old = null;
+
+        boolean force = Main.pref.getBoolean("draw.rawgps.lines.force");
+        boolean lines = Main.pref.getBoolean("draw.rawgps.lines");
+        String linesKey = "draw.rawgps.lines.layer "+name;
+        if (Main.pref.hasKey(linesKey))
+            lines = Main.pref.getBoolean(linesKey);
+        boolean large = Main.pref.getBoolean("draw.rawgps.large");
+        for (Collection<GpsPoint> c : data) {
+            if (!force)
+                old = null;
+            for (GpsPoint p : c) {
+                Point screen = mv.getPoint(p.eastNorth);
+                if (lines && old != null)
+                    g.drawLine(old.x, old.y, screen.x, screen.y);
+                else if (!large)
+                    g.drawRect(screen.x, screen.y, 0, 0);
+                if (large)
+                    g.fillRect(screen.x-1, screen.y-1, 3, 3);
+                old = screen;
+            }
+        }
+    }
+
+    @Override public String getToolTipText() {
+        int points = 0;
+        for (Collection<GpsPoint> c : data)
+            points += c.size();
+        String tool = data.size()+" "+trn("track", "tracks", data.size())
+        +" "+points+" "+trn("point", "points", points);
+        if (associatedFile != null)
+            tool = "<html>"+tool+"<br>"+associatedFile.getPath()+"</html>";
+        return tool;
+    }
+
+    @Override public void mergeFrom(Layer from) {
+        RawGpsLayer layer = (RawGpsLayer)from;
+        data.addAll(layer.data);
+    }
+
+    @Override public boolean isMergable(Layer other) {
+        return other instanceof RawGpsLayer;
+    }
+
+    @Override public void visitBoundingBox(BoundingXYVisitor v) {
+        for (Collection<GpsPoint> c : data)
+            for (GpsPoint p : c)
+                v.visit(p.eastNorth);
+    }
+
+    @Override public Object getInfoComponent() {
+        StringBuilder b = new StringBuilder();
+        int points = 0;
+        for (Collection<GpsPoint> c : data) {
+            b.append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+trn("a track with {0} point","a track with {0} points", c.size(), c.size())+"<br>");
+            points += c.size();
+        }
+        b.append("</html>");
+        return "<html>"+trn("{0} consists of {1} track", "{0} consists of {1} tracks", data.size(), name, data.size())+" ("+trn("{0} point", "{0} points", points, points)+")<br>"+b.toString();
+    }
+
+    @Override public Component[] getMenuEntries() {
+        JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
+        line.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JRadioButton[] r = new JRadioButton[3];
+                r[0] = new JRadioButton(tr("Use global settings."));
+                r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
+                r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
+                ButtonGroup group = new ButtonGroup();
+                Box panel = Box.createVerticalBox();
+                for (JRadioButton b : r) {
+                    group.add(b);
+                    panel.add(b);
+                }
+                String propName = "draw.rawgps.lines.layer "+name;
+                if (Main.pref.hasKey(propName))
+                    group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
+                else
+                    group.setSelected(r[0].getModel(), true);
+                int answer = JOptionPane.showConfirmDialog(Main.parent, panel, tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION);
+                if (answer == JOptionPane.CANCEL_OPTION)
+                    return;
+                if (group.getSelection() == r[0].getModel())
+                    Main.pref.put(propName, null);
+                else
+                    Main.pref.put(propName, group.getSelection() == r[1].getModel());
+                Main.map.repaint();
+            }
+        });
+
+        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
+        color.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+name, Color.gray));
+                Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+                int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
+                JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+                switch (answer) {
+                case 0:
+                    Main.pref.putColor("layer "+name, c.getColor());
+                    break;
+                case 1:
+                    return;
+                case 2:
+                    Main.pref.putColor("layer "+name, null);
+                    break;
+                }
+                Main.map.repaint();
+            }
+        });
+
+        if (Main.applet)
+            return new Component[]{
+                new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+                new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+                new JSeparator(),
+                color,
+                line,
+                new JMenuItem(new ConvertToDataLayerAction()),
+                //new JMenuItem(new UploadTraceAction()),
+                new JSeparator(),
+                new JMenuItem(new RenameLayerAction(associatedFile, this)),
+                new JSeparator(),
+                new JMenuItem(new LayerListPopup.InfoAction(this))};
+        return new Component[]{
+                new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+                new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+                new JSeparator(),
+                new JMenuItem(new GpxExportAction(this)),
+                color,
+                line,
+                new JMenuItem(new ConvertToDataLayerAction()),
+                //new JMenuItem(new UploadTraceAction()),
+                new JSeparator(),
+                new JMenuItem(new RenameLayerAction(associatedFile, this)),
+                new JSeparator(),
+                new JMenuItem(new LayerListPopup.InfoAction(this))};
+    }
+
+    public void preferenceChanged(String key, String newValue) {
+        if (Main.map != null && (key.equals("draw.rawgps.lines") || key.equals("draw.rawgps.lines.force")))
+            Main.map.repaint();
+    }
+
+    @Override public void destroy() {
+        Main.pref.listener.remove(RawGpsLayer.this);
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 1169)
@@ -11,5 +11,5 @@
 /**
  * Marker class with audio playback capability.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -17,77 +17,77 @@
 public class AudioMarker extends ButtonMarker {
 
-	private URL audioUrl;	
-	private static AudioMarker recentlyPlayedMarker = null;
-	public  double syncOffset;
-	
-	/**
-	 * Verifies the parameter whether a new AudioMarker can be created and return
-	 * one or return <code>null</code>.
-	 */
-	public static AudioMarker create(LatLon ll, String text, String url, MarkerLayer parentLayer, double time, double offset) {
-		try {
-			return new AudioMarker(ll, text, new URL(url), parentLayer, time, offset);
-		} catch (Exception ex) {
-			return null;
-		}
-	}
+    private URL audioUrl;
+    private static AudioMarker recentlyPlayedMarker = null;
+    public  double syncOffset;
 
-	private AudioMarker(LatLon ll, String text, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
-		super(ll, text, "speech.png", parentLayer, time, offset);
-		this.audioUrl = audioUrl;
-		this.syncOffset = 0.0;
-	}
+    /**
+     * Verifies the parameter whether a new AudioMarker can be created and return
+     * one or return <code>null</code>.
+     */
+    public static AudioMarker create(LatLon ll, String text, String url, MarkerLayer parentLayer, double time, double offset) {
+        try {
+            return new AudioMarker(ll, text, new URL(url), parentLayer, time, offset);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
 
-	@Override public void actionPerformed(ActionEvent ev) {
-		play();
-	}
+    private AudioMarker(LatLon ll, String text, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
+        super(ll, text, "speech.png", parentLayer, time, offset);
+        this.audioUrl = audioUrl;
+        this.syncOffset = 0.0;
+    }
 
-	public static AudioMarker recentlyPlayedMarker() {
-		return recentlyPlayedMarker;
-	}
-	
-	public URL url() {
-		return audioUrl;
-	}
-		
-	/**
-	 * Starts playing the audio associated with the marker offset by the given amount 
-	 * @param after : seconds after marker where playing should start
-	 */
-	public void play(double after) {
-		try {
-			// first enable tracing the audio along the track
-			Main.map.mapView.playHeadMarker.animate();
+    @Override public void actionPerformed(ActionEvent ev) {
+        play();
+    }
 
-			AudioPlayer.play(audioUrl, offset + syncOffset + after);
-			recentlyPlayedMarker = this;
-		} catch (Exception e) {
-			AudioPlayer.audioMalfunction(e);
-		}
-	}
+    public static AudioMarker recentlyPlayedMarker() {
+        return recentlyPlayedMarker;
+    }
 
-	/**
-	 * Starts playing the audio associated with the marker: used in response to pressing
-	 * the marker as well as indirectly 
-	 *
-	 */
-	public void play() { play(0.0); }
+    public URL url() {
+        return audioUrl;
+    }
 
-	public void adjustOffset(double adjustment) {
-		syncOffset = adjustment; // added to offset may turn out negative, but that's ok
-	}
+    /**
+     * Starts playing the audio associated with the marker offset by the given amount
+     * @param after : seconds after marker where playing should start
+     */
+    public void play(double after) {
+        try {
+            // first enable tracing the audio along the track
+            Main.map.mapView.playHeadMarker.animate();
 
-	public double syncOffset() {
-		return syncOffset;
-	}
-	
-	public static String inventName (double offset) {
-		int wholeSeconds = (int)(offset + 0.5);
-		if (wholeSeconds < 60)
-			return Integer.toString(wholeSeconds);
-		else if (wholeSeconds < 3600)
-			return String.format("%d:%02d", wholeSeconds / 60, wholeSeconds % 60);
-		else
-			return String.format("%d:%02d:%02d", wholeSeconds / 3600, (wholeSeconds % 3600)/60, wholeSeconds % 60);
-	}
+            AudioPlayer.play(audioUrl, offset + syncOffset + after);
+            recentlyPlayedMarker = this;
+        } catch (Exception e) {
+            AudioPlayer.audioMalfunction(e);
+        }
+    }
+
+    /**
+     * Starts playing the audio associated with the marker: used in response to pressing
+     * the marker as well as indirectly
+     *
+     */
+    public void play() { play(0.0); }
+
+    public void adjustOffset(double adjustment) {
+        syncOffset = adjustment; // added to offset may turn out negative, but that's ok
+    }
+
+    public double syncOffset() {
+        return syncOffset;
+    }
+
+    public static String inventName (double offset) {
+        int wholeSeconds = (int)(offset + 0.5);
+        if (wholeSeconds < 60)
+            return Integer.toString(wholeSeconds);
+        else if (wholeSeconds < 3600)
+            return String.format("%d:%02d", wholeSeconds / 60, wholeSeconds % 60);
+        else
+            return String.format("%d:%02d:%02d", wholeSeconds / 3600, (wholeSeconds % 3600)/60, wholeSeconds % 60);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java	(revision 1169)
@@ -17,5 +17,5 @@
 /**
  * Marker class with button look-and-feel.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -23,47 +23,47 @@
 public class ButtonMarker extends Marker {
 
-	private Rectangle buttonRectangle;
-	
-	public ButtonMarker(LatLon ll, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
-		super(ll, null, buttonImage, parentLayer, time, offset);
-		buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
-	}
-	
-	public ButtonMarker(LatLon ll, String text, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
-		super(ll, text, buttonImage, parentLayer, time, offset);
-		buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
-	}
-	
-	@Override public boolean containsPoint(Point p) {
-		Point screen = Main.map.mapView.getPoint(eastNorth);
-		buttonRectangle.setLocation(screen.x+4, screen.y+2);
-		return buttonRectangle.contains(p);
-	}
-	
-	@Override public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
-		if (! show.equalsIgnoreCase("show")) {
-			super.paint(g, mv, mousePressed, show);
-			return;
-		}
-		Point screen = mv.getPoint(eastNorth);
-		buttonRectangle.setLocation(screen.x+4, screen.y+2);
-		symbol.paintIcon(mv, g, screen.x+4, screen.y+2);
-		Border b;
-		Point mousePosition = mv.getMousePosition();
-		
-		if (mousePosition != null) {
-			// mouse is inside the window
-			if (mousePressed) {
-				b = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
-			} else {
-				b = BorderFactory.createBevelBorder(BevelBorder.RAISED);
-			}
-			Insets inset = b.getBorderInsets(mv);
-			Rectangle r = new Rectangle(buttonRectangle);
-			r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2);
-			b.paintBorder(mv, g, r.x, r.y, r.width, r.height);
-		}
-		if ((text != null) && (show.equalsIgnoreCase("show")) && Main.pref.getBoolean("marker.buttonlabels", true))
-			g.drawString(text, screen.x+4, screen.y+2);
-	}
+    private Rectangle buttonRectangle;
+
+    public ButtonMarker(LatLon ll, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
+        super(ll, null, buttonImage, parentLayer, time, offset);
+        buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
+    }
+
+    public ButtonMarker(LatLon ll, String text, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
+        super(ll, text, buttonImage, parentLayer, time, offset);
+        buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
+    }
+
+    @Override public boolean containsPoint(Point p) {
+        Point screen = Main.map.mapView.getPoint(eastNorth);
+        buttonRectangle.setLocation(screen.x+4, screen.y+2);
+        return buttonRectangle.contains(p);
+    }
+
+    @Override public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
+        if (! show.equalsIgnoreCase("show")) {
+            super.paint(g, mv, mousePressed, show);
+            return;
+        }
+        Point screen = mv.getPoint(eastNorth);
+        buttonRectangle.setLocation(screen.x+4, screen.y+2);
+        symbol.paintIcon(mv, g, screen.x+4, screen.y+2);
+        Border b;
+        Point mousePosition = mv.getMousePosition();
+
+        if (mousePosition != null) {
+            // mouse is inside the window
+            if (mousePressed) {
+                b = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
+            } else {
+                b = BorderFactory.createBevelBorder(BevelBorder.RAISED);
+            }
+            Insets inset = b.getBorderInsets(mv);
+            Rectangle r = new Rectangle(buttonRectangle);
+            r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2);
+            b.paintBorder(mv, g, r.x, r.y, r.width, r.height);
+        }
+        if ((text != null) && (show.equalsIgnoreCase("show")) && Main.pref.getBoolean("marker.buttonlabels", true))
+            g.drawString(text, screen.x+4, screen.y+2);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java	(revision 1169)
@@ -26,5 +26,5 @@
  * Marker representing an image. Uses a special icon, and when clicked,
  * displays an image view dialog. Re-uses some code from GeoImageLayer.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -32,60 +32,60 @@
 public class ImageMarker extends ButtonMarker {
 
-	public URL imageUrl;
+    public URL imageUrl;
 
-	public static ImageMarker create(LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
-		try {
-			return new ImageMarker(ll, new URL(url), parentLayer, time, offset);
-		} catch (Exception ex) {
-			return null;
-		}
-	}
+    public static ImageMarker create(LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
+        try {
+            return new ImageMarker(ll, new URL(url), parentLayer, time, offset);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
 
-	private ImageMarker(LatLon ll, URL imageUrl, MarkerLayer parentLayer, double time, double offset) {
-		super(ll, "photo.png", parentLayer, time, offset);
-		this.imageUrl = imageUrl;
-	}
+    private ImageMarker(LatLon ll, URL imageUrl, MarkerLayer parentLayer, double time, double offset) {
+        super(ll, "photo.png", parentLayer, time, offset);
+        this.imageUrl = imageUrl;
+    }
 
-	@Override public void actionPerformed(ActionEvent ev) {
-		final JPanel p = new JPanel(new BorderLayout());
-		final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(imageUrl, 580)));
-		final JViewport vp = scroll.getViewport();
-		p.add(scroll, BorderLayout.CENTER);
+    @Override public void actionPerformed(ActionEvent ev) {
+        final JPanel p = new JPanel(new BorderLayout());
+        final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(imageUrl, 580)));
+        final JViewport vp = scroll.getViewport();
+        p.add(scroll, BorderLayout.CENTER);
 
-		final JToggleButton scale = new JToggleButton(ImageProvider.get("misc", "rectangle"));
+        final JToggleButton scale = new JToggleButton(ImageProvider.get("misc", "rectangle"));
 
-		JPanel p2 = new JPanel();
-		p2.add(scale);
-		p.add(p2, BorderLayout.SOUTH);
-		scale.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent ev) {
-				p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-				if (scale.getModel().isSelected())
-					((JLabel)vp.getView()).setIcon(loadScaledImage(imageUrl, Math.max(vp.getWidth(), vp.getHeight())));
-				else
-					((JLabel)vp.getView()).setIcon(new ImageIcon(imageUrl));
-				p.setCursor(Cursor.getDefaultCursor());
-			}
-		});
-		scale.setSelected(true);
-		JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE);
-		JDialog dlg = pane.createDialog(Main.parent, imageUrl.toString());
-		dlg.setModal(false);
-		dlg.setVisible(true);
-	}
+        JPanel p2 = new JPanel();
+        p2.add(scale);
+        p.add(p2, BorderLayout.SOUTH);
+        scale.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent ev) {
+                p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+                if (scale.getModel().isSelected())
+                    ((JLabel)vp.getView()).setIcon(loadScaledImage(imageUrl, Math.max(vp.getWidth(), vp.getHeight())));
+                else
+                    ((JLabel)vp.getView()).setIcon(new ImageIcon(imageUrl));
+                p.setCursor(Cursor.getDefaultCursor());
+            }
+        });
+        scale.setSelected(true);
+        JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE);
+        JDialog dlg = pane.createDialog(Main.parent, imageUrl.toString());
+        dlg.setModal(false);
+        dlg.setVisible(true);
+    }
 
-	private static Icon loadScaledImage(URL u, int maxSize) {
-		Image img = new ImageIcon(u).getImage();
-		int w = img.getWidth(null);
-		int h = img.getHeight(null);
-		if (w>h) {
-			h = Math.round(maxSize*((float)h/w));
-			w = maxSize;
-		} else {
-			w = Math.round(maxSize*((float)w/h));
-			h = maxSize;
-		}
-		return new ImageIcon(img.getScaledInstance(w, h, Image.SCALE_SMOOTH));
-	}
+    private static Icon loadScaledImage(URL u, int maxSize) {
+        Image img = new ImageIcon(u).getImage();
+        int w = img.getWidth(null);
+        int h = img.getHeight(null);
+        if (w>h) {
+            h = Math.round(maxSize*((float)h/w));
+            w = maxSize;
+        } else {
+            w = Math.round(maxSize*((float)w/h));
+            h = maxSize;
+        }
+        return new ImageIcon(img.getScaledInstance(w, h, Image.SCALE_SMOOTH));
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 1169)
@@ -23,24 +23,24 @@
 
 /**
- * Basic marker class. Requires a position, and supports 
+ * Basic marker class. Requires a position, and supports
  * a custom icon and a name.
- * 
+ *
  * This class is also used to create appropriate Marker-type objects
  * when waypoints are imported.
- * 
+ *
  * It hosts a public list object, named makers, containing implementations of
- * the MarkerMaker interface. Whenever a Marker needs to be created, each 
+ * the MarkerMaker interface. Whenever a Marker needs to be created, each
  * object in makers is called with the waypoint parameters (Lat/Lon and tag
  * data), and the first one to return a Marker object wins.
- * 
+ *
  * By default, one the list contains one default "Maker" implementation that
- * will create AudioMarkers for .wav files, ImageMarkers for .png/.jpg/.jpeg 
+ * will create AudioMarkers for .wav files, ImageMarkers for .png/.jpg/.jpeg
  * files, and WebMarkers for everything else. (The creation of a WebMarker will
  * fail if there's no vaild URL in the <link> tag, so it might still make sense
  * to add Makers for such waypoints at the end of the list.)
- * 
+ *
  * The default implementation only looks at the value of the <link> tag inside
  * the <wpt> tag of the GPX file.
- * 
+ *
  * <h2>HowTo implement a new Marker</h2>
  * <ul>
@@ -54,39 +54,39 @@
  *      if you only add a new marker style.</li>
  * </ul>
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  */
 public class Marker implements ActionListener {
 
-	public EastNorth eastNorth;
-	public final String text;
-	public final Icon symbol;
-	public final MarkerLayer parentLayer;
-	public double time; /* avbsolute time of marker since epocj */
-	public double offset; /* time offset in seconds from the gpx point from which it was derived,
-							 may be adjusted later to sync with other data, so not final */
-
-	/**
-	 * Plugins can add their Marker creation stuff at the bottom or top of this list
-	 * (depending on whether they want to override default behaviour or just add new
-	 * stuff).
-	 */
-	public static LinkedList<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();
-
-	// Add one Maker specifying the default behaviour.
-	static {
-		Marker.markerProducers.add(new MarkerProducers() {
-			public Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
-				String uri = null;
-				// cheapest way to check whether "link" object exists and is a non-empty
-				// collection of GpxLink objects...
-				try {
-					for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
-						uri = oneLink.uri;
-						break;
-					}
-				} catch (Exception ex) {}
-
-				// Try a relative file:// url, if the link is not in an URL-compatible form
+    public EastNorth eastNorth;
+    public final String text;
+    public final Icon symbol;
+    public final MarkerLayer parentLayer;
+    public double time; /* avbsolute time of marker since epocj */
+    public double offset; /* time offset in seconds from the gpx point from which it was derived,
+                             may be adjusted later to sync with other data, so not final */
+
+    /**
+     * Plugins can add their Marker creation stuff at the bottom or top of this list
+     * (depending on whether they want to override default behaviour or just add new
+     * stuff).
+     */
+    public static LinkedList<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();
+
+    // Add one Maker specifying the default behaviour.
+    static {
+        Marker.markerProducers.add(new MarkerProducers() {
+            public Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
+                String uri = null;
+                // cheapest way to check whether "link" object exists and is a non-empty
+                // collection of GpxLink objects...
+                try {
+                    for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
+                        uri = oneLink.uri;
+                        break;
+                    }
+                } catch (Exception ex) {}
+
+                // Try a relative file:// url, if the link is not in an URL-compatible form
                 if (relativePath != null && uri != null && !isWellFormedAddress(uri))
                     uri = new File(relativePath.getParentFile(), uri).toURI().toString();
@@ -94,9 +94,9 @@
                 String name_desc = "";
                 if (wpt.attr.containsKey("name")) {
-                	name_desc = wpt.getString("name");
+                    name_desc = wpt.getString("name");
                 } else if (wpt.attr.containsKey("desc")) {
                     name_desc = wpt.getString("desc");
                 }
-                
+
                 if (uri == null)
                     return new Marker(wpt.latlon, name_desc, wpt.getString("symbol"), parentLayer, time, offset);
@@ -104,106 +104,106 @@
                     return AudioMarker.create(wpt.latlon, name_desc, uri, parentLayer, time, offset);
                 else if (uri.endsWith(".png") || uri.endsWith(".jpg") || uri.endsWith(".jpeg") || uri.endsWith(".gif"))
-					return ImageMarker.create(wpt.latlon, uri, parentLayer, time, offset);
-				else
-					return WebMarker.create(wpt.latlon, uri, parentLayer, time, offset);
-			}
-
-			private boolean isWellFormedAddress(String link) {
-				try {
-					new URL(link);
-					return true;
-				} catch (MalformedURLException x) {
-					return false;
-				}
+                    return ImageMarker.create(wpt.latlon, uri, parentLayer, time, offset);
+                else
+                    return WebMarker.create(wpt.latlon, uri, parentLayer, time, offset);
             }
-		});
-	}
-
-	public Marker(LatLon ll, String text, String iconName, MarkerLayer parentLayer, double time, double offset) {
-		eastNorth = Main.proj.latlon2eastNorth(ll); 
-		this.text = text;
-		this.offset = offset;
-		this.time = time;
-		Icon symbol = ImageProvider.getIfAvailable("markers",iconName);
-		if (symbol == null)
-			symbol = ImageProvider.getIfAvailable("symbols",iconName);
-		if (symbol == null)
-			symbol = ImageProvider.getIfAvailable("nodes",iconName);
-		this.symbol = symbol;
-		this.parentLayer = parentLayer;
-	}
-
-	/**
-	 * Checks whether the marker display area contains the given point.
-	 * Markers not interested in mouse clicks may always return false.
-	 * 
-	 * @param p The point to check
-	 * @return <code>true</code> if the marker "hotspot" contains the point.
-	 */
-	public boolean containsPoint(Point p) {
-		return false;
-	}
-
-	/**
-	 * Called when the mouse is clicked in the marker's hotspot. Never
-	 * called for markers which always return false from containsPoint.
-	 * 
-	 * @param ev A dummy ActionEvent
-	 */
-	public void actionPerformed(ActionEvent ev) {
-	}
-
-	/**
-	 * Paints the marker.
-	 * @param g graphics context
-	 * @param mv map view
-	 * @param mousePressed true if the left mouse button is pressed
-	 */
-	public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
-		Point screen = mv.getPoint(eastNorth);
-		if (symbol != null && show.equalsIgnoreCase("show")) {
-			symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
-		} else {
-			g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
-			g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
-		}
-
-		if ((text != null) && (show.equalsIgnoreCase("show")))
-			g.drawString(text, screen.x+4, screen.y+2);
-	}
-
-	/**
-	 * Returns an object of class Marker or one of its subclasses
-	 * created from the parameters given.
-	 *
-	 * @param wpt waypoint data for marker
-	 * @param relativePath An path to use for constructing relative URLs or 
-	 *        <code>null</code> for no relative URLs
-	 * @param offset double in seconds as the time offset of this marker from 
-	 * 		  the GPX file from which it was derived (if any).  
-	 * @return a new Marker object
-	 */
-	public static Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
-		for (MarkerProducers maker : Marker.markerProducers) {
-			Marker marker = maker.createMarker(wpt, relativePath, parentLayer, time, offset);
-			if (marker != null)
-				return marker;
-		}
-		return null;
-	}
-	
-	/**
-	 * Returns an AudioMarker derived from this Marker and the provided uri
-	 * Subclasses of specific marker types override this to return null as they can't
-	 * be turned into AudioMarkers. This includes AudioMarkers themselves, as they 
-	 * already have audio.  
-	 * 
-	 * @param uri uri of wave file
-	 * @return AudioMarker
-	 */
-	
-	public AudioMarker audioMarkerFromMarker(String uri) {
-		AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.parentLayer, this.time, this.offset);
-		return audioMarker;
-	}
+
+            private boolean isWellFormedAddress(String link) {
+                try {
+                    new URL(link);
+                    return true;
+                } catch (MalformedURLException x) {
+                    return false;
+                }
+            }
+        });
+    }
+
+    public Marker(LatLon ll, String text, String iconName, MarkerLayer parentLayer, double time, double offset) {
+        eastNorth = Main.proj.latlon2eastNorth(ll);
+        this.text = text;
+        this.offset = offset;
+        this.time = time;
+        Icon symbol = ImageProvider.getIfAvailable("markers",iconName);
+        if (symbol == null)
+            symbol = ImageProvider.getIfAvailable("symbols",iconName);
+        if (symbol == null)
+            symbol = ImageProvider.getIfAvailable("nodes",iconName);
+        this.symbol = symbol;
+        this.parentLayer = parentLayer;
+    }
+
+    /**
+     * Checks whether the marker display area contains the given point.
+     * Markers not interested in mouse clicks may always return false.
+     *
+     * @param p The point to check
+     * @return <code>true</code> if the marker "hotspot" contains the point.
+     */
+    public boolean containsPoint(Point p) {
+        return false;
+    }
+
+    /**
+     * Called when the mouse is clicked in the marker's hotspot. Never
+     * called for markers which always return false from containsPoint.
+     *
+     * @param ev A dummy ActionEvent
+     */
+    public void actionPerformed(ActionEvent ev) {
+    }
+
+    /**
+     * Paints the marker.
+     * @param g graphics context
+     * @param mv map view
+     * @param mousePressed true if the left mouse button is pressed
+     */
+    public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
+        Point screen = mv.getPoint(eastNorth);
+        if (symbol != null && show.equalsIgnoreCase("show")) {
+            symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
+        } else {
+            g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
+            g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
+        }
+
+        if ((text != null) && (show.equalsIgnoreCase("show")))
+            g.drawString(text, screen.x+4, screen.y+2);
+    }
+
+    /**
+     * Returns an object of class Marker or one of its subclasses
+     * created from the parameters given.
+     *
+     * @param wpt waypoint data for marker
+     * @param relativePath An path to use for constructing relative URLs or
+     *        <code>null</code> for no relative URLs
+     * @param offset double in seconds as the time offset of this marker from
+     *        the GPX file from which it was derived (if any).
+     * @return a new Marker object
+     */
+    public static Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
+        for (MarkerProducers maker : Marker.markerProducers) {
+            Marker marker = maker.createMarker(wpt, relativePath, parentLayer, time, offset);
+            if (marker != null)
+                return marker;
+        }
+        return null;
+    }
+
+    /**
+     * Returns an AudioMarker derived from this Marker and the provided uri
+     * Subclasses of specific marker types override this to return null as they can't
+     * be turned into AudioMarkers. This includes AudioMarkers themselves, as they
+     * already have audio.
+     *
+     * @param uri uri of wave file
+     * @return AudioMarker
+     */
+
+    public AudioMarker audioMarkerFromMarker(String uri) {
+        AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.parentLayer, this.time, this.offset);
+        return audioMarker;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 1169)
@@ -43,362 +43,362 @@
 /**
  * A layer holding markers.
- * 
+ *
  * Markers are GPS points with a name and, optionally, a symbol code attached;
  * marker layers can be created from waypoints when importing raw GPS data,
  * but they may also come from other sources.
- * 
+ *
  * The symbol code is for future use.
- * 
+ *
  * The data is read only.
  */
 public class MarkerLayer extends Layer {
 
-	/**
-	 * A list of markers.
-	 */
-	public final Collection<Marker> data;
-	private boolean mousePressed = false;
-	public GpxLayer fromLayer = null;
-	
-	/*
-	private Icon audioTracerIcon = null;
-	private EastNorth playheadPosition = null;
-	private static Timer timer = null;
-	private static double audioAnimationInterval = 0.0; // seconds
-	private static double playheadTime = -1.0;
-	 */
-	public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer) {
-		
-		super(name);
-		this.associatedFile = associatedFile;
-		this.data = new ArrayList<Marker>();
-		this.fromLayer = fromLayer;
-		double firstTime = -1.0;
-		String lastLinkedFile = "";
-
-		for (WayPoint wpt : indata.waypoints) {
-			/* calculate time differences in waypoints */
-			double time = wpt.time;
-			boolean wpt_has_link = wpt.attr.containsKey("link");
-			if (firstTime < 0 && wpt_has_link) {
-				firstTime = time;
-				for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
-					lastLinkedFile = oneLink.uri;
-					break;
-				}
-			}
-			if (wpt_has_link) {
-				for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
-					if (!oneLink.uri.equals(lastLinkedFile))firstTime = time;
-					lastLinkedFile = oneLink.uri;
-					break;
-				}
-			}
+    /**
+     * A list of markers.
+     */
+    public final Collection<Marker> data;
+    private boolean mousePressed = false;
+    public GpxLayer fromLayer = null;
+
+    /*
+    private Icon audioTracerIcon = null;
+    private EastNorth playheadPosition = null;
+    private static Timer timer = null;
+    private static double audioAnimationInterval = 0.0; // seconds
+    private static double playheadTime = -1.0;
+     */
+    public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer) {
+
+        super(name);
+        this.associatedFile = associatedFile;
+        this.data = new ArrayList<Marker>();
+        this.fromLayer = fromLayer;
+        double firstTime = -1.0;
+        String lastLinkedFile = "";
+
+        for (WayPoint wpt : indata.waypoints) {
+            /* calculate time differences in waypoints */
+            double time = wpt.time;
+            boolean wpt_has_link = wpt.attr.containsKey("link");
+            if (firstTime < 0 && wpt_has_link) {
+                firstTime = time;
+                for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
+                    lastLinkedFile = oneLink.uri;
+                    break;
+                }
+            }
+            if (wpt_has_link) {
+                for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
+                    if (!oneLink.uri.equals(lastLinkedFile))firstTime = time;
+                    lastLinkedFile = oneLink.uri;
+                    break;
+                }
+            }
             Marker m = Marker.createMarker(wpt, indata.storageFile, this, time, time - firstTime);
             if (m != null)
-            	data.add(m);
-		}
-		
-		SwingUtilities.invokeLater(new Runnable(){
-			public void run() {
-				Main.map.mapView.addMouseListener(new MouseAdapter() {
-					@Override public void mousePressed(MouseEvent e) {
-						if (e.getButton() != MouseEvent.BUTTON1)
-							return;
-						boolean mousePressedInButton = false;
-						if (e.getPoint() != null) {
-							for (Marker mkr : data) {
-								if (mkr.containsPoint(e.getPoint())) {
-									mousePressedInButton = true;
-									break;
-								}
-							}
-						}
-						if (! mousePressedInButton)
-							return;
-						mousePressed  = true;
-						if (visible)
-							Main.map.mapView.repaint();
-					}
-					@Override public void mouseReleased(MouseEvent ev) {
-						if (ev.getButton() != MouseEvent.BUTTON1 || ! mousePressed)
-							return;
-						mousePressed = false;
-						if (!visible)
-							return;
-						if (ev.getPoint() != null) {
-							for (Marker mkr : data) {
-								if (mkr.containsPoint(ev.getPoint()))
-									mkr.actionPerformed(new ActionEvent(this, 0, null));
-							}
-						}
-						Main.map.mapView.repaint();
-					}
-				});
-			}
-		});
-	}
-
-	/**
-	 * Return a static icon.
-	 */
-	@Override public Icon getIcon() {
-		return ImageProvider.get("layer", "marker_small");
-	}
-
-	@Override public void paint(Graphics g, MapView mv) {
-		boolean mousePressedTmp = mousePressed;
-		Point mousePos = mv.getMousePosition();
-		String mkrTextShow = Main.pref.get("marker.show "+name, "show");
-
-		g.setColor(Main.pref.getColor(marktr("gps marker"), "layer "+name, Color.gray));
-		
-		for (Marker mkr : data) {
-			if (mousePos != null && mkr.containsPoint(mousePos)) {
-				mkr.paint(g, mv, mousePressedTmp, mkrTextShow);
-				mousePressedTmp = false;
-			} else {
-				mkr.paint(g, mv, false, mkrTextShow);
-			}
-		}
-	}
-
-	@Override public String getToolTipText() {
-		return data.size()+" "+trn("marker", "markers", data.size());
-	}
-
-	@Override public void mergeFrom(Layer from) {
-		MarkerLayer layer = (MarkerLayer)from;
-		data.addAll(layer.data);
-	}
-
-	@Override public boolean isMergable(Layer other) {
-		return other instanceof MarkerLayer;
-	}
-
-	@Override public void visitBoundingBox(BoundingXYVisitor v) {
-		for (Marker mkr : data)
-			v.visit(mkr.eastNorth);
-	}
-
-	@Override public Object getInfoComponent() {
-		return "<html>"+trn("{0} consists of {1} marker", "{0} consists of {1} markers", data.size(), name, data.size()) + "</html>";
-	}
-
-	@Override public Component[] getMenuEntries() {
-		JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-		color.putClientProperty("help", "Action/LayerCustomizeColor");
-		color.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps marker"), "layer "+name, Color.gray));
-				Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
-				int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
-				JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
-				switch (answer) {
-				case 0:
-					Main.pref.putColor("layer "+name, c.getColor());
-					break;
-				case 1:
-					return;
-				case 2:
-					Main.pref.putColor("layer "+name, null);
-					break;
-				}
-				Main.map.repaint();
-			}
-		});
-
-		JMenuItem syncaudio = new JMenuItem(tr("Synchronize Audio"), ImageProvider.get("audio-sync"));
-		syncaudio.putClientProperty("help", "Action/SynchronizeAudio");
-		syncaudio.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (! AudioPlayer.paused()) {
-					JOptionPane.showMessageDialog(Main.parent,tr("You need to pause audio at the moment when you hear your synchronization cue."));
-					return;
-				}
-				AudioMarker recent = AudioMarker.recentlyPlayedMarker();
-				if (synchronizeAudioMarkers(recent)) {
-					JOptionPane.showMessageDialog(Main.parent, tr("Audio synchronized at point {0}.", recent.text));
-				} else {
-					JOptionPane.showMessageDialog(Main.parent,tr("Unable to synchronize in layer being played."));
-				}
-			}
-		});
-
-		JMenuItem moveaudio = new JMenuItem(tr("Make Audio Marker At Play Head"), ImageProvider.get("addmarkers"));
-		moveaudio.putClientProperty("help", "Action/MakeAudioMarkerAtPlayHead");
-		moveaudio.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (! AudioPlayer.paused()) {
-					JOptionPane.showMessageDialog(Main.parent,tr("You need to have paused audio at the point on the track where you want the marker."));
-					return;
-				}
-				PlayHeadMarker playHeadMarker = Main.map.mapView.playHeadMarker;
-				if (playHeadMarker == null)
-					return;
-				addAudioMarker(playHeadMarker.time, playHeadMarker.eastNorth);
-				Main.map.mapView.repaint();
-			}
-		});
-
-		Collection<Component> components = new ArrayList<Component>();
-		components.add(new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)));
-		components.add(new JMenuItem(new LayerListDialog.ShowHideMarkerText(this)));
-		components.add(new JMenuItem(new LayerListDialog.DeleteLayerAction(this)));
-		components.add(new JSeparator());
-		components.add(color);
-		components.add(new JSeparator());
-		components.add(syncaudio);
-		if (Main.pref.getBoolean("marker.traceaudio", true)) {
-			components.add (moveaudio);
-		}		
-		components.add(new JMenuItem(new RenameLayerAction(associatedFile, this)));
-		components.add(new JSeparator());
-		components.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
-		return components.toArray(new Component[0]);
-	}
-
-	public boolean synchronizeAudioMarkers(AudioMarker startMarker) {
-		if (startMarker != null && ! data.contains(startMarker)) {
-			startMarker = null;
-		}
-		if (startMarker == null) {
-			// find the first audioMarker in this layer
-			for (Marker m : data) {
-				if (m instanceof AudioMarker) {
-					startMarker = (AudioMarker) m;
-					break;
-				}
-			}
-		}
-		if (startMarker == null)
-			return false;
-			
-		// apply adjustment to all subsequent audio markers in the layer
-		double adjustment = AudioPlayer.position() - startMarker.offset; // in seconds
-		boolean seenStart = false;
-		URL url = startMarker.url();
-		for (Marker m : data) {
-			if (m == startMarker)
-				seenStart = true;
-			if (seenStart) {
-				AudioMarker ma = (AudioMarker) m; // it must be an AudioMarker
-				if (ma.url().equals(url))
-					ma.adjustOffset(adjustment);
-			}
-		}
-		return true;
-	}
-	
-	public AudioMarker addAudioMarker(double time, EastNorth en) {
-		// find first audio marker to get absolute start time
-		double offset = 0.0;
-		AudioMarker am = null; 
-		for (Marker m : data) {
-			if (m.getClass() == AudioMarker.class) {
-				am = (AudioMarker)m;
-				offset = time - am.time;
-				break;
-			}
-		}
-		if (am == null) {
-			JOptionPane.showMessageDialog(Main.parent,tr("No existing audio markers in this layer to offset from."));
-			return null;
-		}
-
-		// make our new marker
-		AudioMarker newAudioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(en), 
-			AudioMarker.inventName(offset), AudioPlayer.url().toString(), this, time, offset);
-
-		// insert it at the right place in a copy the collection
-		Collection<Marker> newData = new ArrayList<Marker>();
-		am = null;
-		AudioMarker ret = newAudioMarker; // save to have return value
-		for (Marker m : data) {
-			if (m.getClass() == AudioMarker.class) {
-				am = (AudioMarker) m;
-				if (newAudioMarker != null && offset < am.offset) {
-					newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same as predecessor
-					newData.add(newAudioMarker);
-					newAudioMarker = null;
-				}
-			}
-			newData.add(m);
-		}
-
-		if (newAudioMarker != null) {
-			if (am != null)
-				newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same as predecessor
-			newData.add(newAudioMarker); // insert at end
-		}
-
-		// replace the collection
-		data.clear();
-		data.addAll(newData);
-		return ret;
-	}
-	
-	public static void playAudio() {
-		if (Main.map == null || Main.map.mapView == null)
-			return;
-		for (Layer layer : Main.map.mapView.getAllLayers()) {
-			if (layer.getClass() == MarkerLayer.class) {
-				MarkerLayer markerLayer = (MarkerLayer) layer;
-				for (Marker marker : markerLayer.data) {
-					if (marker.getClass() == AudioMarker.class) {
-						((AudioMarker)marker).play();
-						break;
-					}
-				}
-			}
-		}
-	}
-
-	public static void playNextMarker() {
-		playAdjacentMarker(true);
-	}
-	
-	public static void playPreviousMarker() {
-		playAdjacentMarker(false);
-	}
-	
-	private static void playAdjacentMarker(boolean next) {
-		Marker startMarker = AudioMarker.recentlyPlayedMarker();
-		if (startMarker == null) {
-			// message?
-			return;
-		}
-		Marker previousMarker = null;
-		boolean nextTime = false;
-		if (Main.map == null || Main.map.mapView == null)
-			return;
-		for (Layer layer : Main.map.mapView.getAllLayers()) {
-			if (layer.getClass() == MarkerLayer.class) {
-				MarkerLayer markerLayer = (MarkerLayer) layer;
-				for (Marker marker : markerLayer.data) {
-					if (marker == startMarker) {
-						if (next) {
-							nextTime = true;
-						} else {
-							if (previousMarker == null)
-								previousMarker = startMarker; // if no previous one, play the first one again
-							((AudioMarker)previousMarker).play();
-							break;
-						}
-					} else if (nextTime && marker.getClass() == AudioMarker.class) {
-						((AudioMarker)marker).play();
-						return;
-					}
-					if (marker.getClass() == AudioMarker.class)
-						previousMarker = marker;
-				}
-				if (nextTime) {
-					// there was no next marker in that layer, so play the last one again
-					((AudioMarker)startMarker).play();
-					return;
-				}
-			}
-		}
-	}
-	
+                data.add(m);
+        }
+
+        SwingUtilities.invokeLater(new Runnable(){
+            public void run() {
+                Main.map.mapView.addMouseListener(new MouseAdapter() {
+                    @Override public void mousePressed(MouseEvent e) {
+                        if (e.getButton() != MouseEvent.BUTTON1)
+                            return;
+                        boolean mousePressedInButton = false;
+                        if (e.getPoint() != null) {
+                            for (Marker mkr : data) {
+                                if (mkr.containsPoint(e.getPoint())) {
+                                    mousePressedInButton = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (! mousePressedInButton)
+                            return;
+                        mousePressed  = true;
+                        if (visible)
+                            Main.map.mapView.repaint();
+                    }
+                    @Override public void mouseReleased(MouseEvent ev) {
+                        if (ev.getButton() != MouseEvent.BUTTON1 || ! mousePressed)
+                            return;
+                        mousePressed = false;
+                        if (!visible)
+                            return;
+                        if (ev.getPoint() != null) {
+                            for (Marker mkr : data) {
+                                if (mkr.containsPoint(ev.getPoint()))
+                                    mkr.actionPerformed(new ActionEvent(this, 0, null));
+                            }
+                        }
+                        Main.map.mapView.repaint();
+                    }
+                });
+            }
+        });
+    }
+
+    /**
+     * Return a static icon.
+     */
+    @Override public Icon getIcon() {
+        return ImageProvider.get("layer", "marker_small");
+    }
+
+    @Override public void paint(Graphics g, MapView mv) {
+        boolean mousePressedTmp = mousePressed;
+        Point mousePos = mv.getMousePosition();
+        String mkrTextShow = Main.pref.get("marker.show "+name, "show");
+
+        g.setColor(Main.pref.getColor(marktr("gps marker"), "layer "+name, Color.gray));
+
+        for (Marker mkr : data) {
+            if (mousePos != null && mkr.containsPoint(mousePos)) {
+                mkr.paint(g, mv, mousePressedTmp, mkrTextShow);
+                mousePressedTmp = false;
+            } else {
+                mkr.paint(g, mv, false, mkrTextShow);
+            }
+        }
+    }
+
+    @Override public String getToolTipText() {
+        return data.size()+" "+trn("marker", "markers", data.size());
+    }
+
+    @Override public void mergeFrom(Layer from) {
+        MarkerLayer layer = (MarkerLayer)from;
+        data.addAll(layer.data);
+    }
+
+    @Override public boolean isMergable(Layer other) {
+        return other instanceof MarkerLayer;
+    }
+
+    @Override public void visitBoundingBox(BoundingXYVisitor v) {
+        for (Marker mkr : data)
+            v.visit(mkr.eastNorth);
+    }
+
+    @Override public Object getInfoComponent() {
+        return "<html>"+trn("{0} consists of {1} marker", "{0} consists of {1} markers", data.size(), name, data.size()) + "</html>";
+    }
+
+    @Override public Component[] getMenuEntries() {
+        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
+        color.putClientProperty("help", "Action/LayerCustomizeColor");
+        color.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps marker"), "layer "+name, Color.gray));
+                Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+                int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
+                JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+                switch (answer) {
+                case 0:
+                    Main.pref.putColor("layer "+name, c.getColor());
+                    break;
+                case 1:
+                    return;
+                case 2:
+                    Main.pref.putColor("layer "+name, null);
+                    break;
+                }
+                Main.map.repaint();
+            }
+        });
+
+        JMenuItem syncaudio = new JMenuItem(tr("Synchronize Audio"), ImageProvider.get("audio-sync"));
+        syncaudio.putClientProperty("help", "Action/SynchronizeAudio");
+        syncaudio.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (! AudioPlayer.paused()) {
+                    JOptionPane.showMessageDialog(Main.parent,tr("You need to pause audio at the moment when you hear your synchronization cue."));
+                    return;
+                }
+                AudioMarker recent = AudioMarker.recentlyPlayedMarker();
+                if (synchronizeAudioMarkers(recent)) {
+                    JOptionPane.showMessageDialog(Main.parent, tr("Audio synchronized at point {0}.", recent.text));
+                } else {
+                    JOptionPane.showMessageDialog(Main.parent,tr("Unable to synchronize in layer being played."));
+                }
+            }
+        });
+
+        JMenuItem moveaudio = new JMenuItem(tr("Make Audio Marker At Play Head"), ImageProvider.get("addmarkers"));
+        moveaudio.putClientProperty("help", "Action/MakeAudioMarkerAtPlayHead");
+        moveaudio.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (! AudioPlayer.paused()) {
+                    JOptionPane.showMessageDialog(Main.parent,tr("You need to have paused audio at the point on the track where you want the marker."));
+                    return;
+                }
+                PlayHeadMarker playHeadMarker = Main.map.mapView.playHeadMarker;
+                if (playHeadMarker == null)
+                    return;
+                addAudioMarker(playHeadMarker.time, playHeadMarker.eastNorth);
+                Main.map.mapView.repaint();
+            }
+        });
+
+        Collection<Component> components = new ArrayList<Component>();
+        components.add(new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)));
+        components.add(new JMenuItem(new LayerListDialog.ShowHideMarkerText(this)));
+        components.add(new JMenuItem(new LayerListDialog.DeleteLayerAction(this)));
+        components.add(new JSeparator());
+        components.add(color);
+        components.add(new JSeparator());
+        components.add(syncaudio);
+        if (Main.pref.getBoolean("marker.traceaudio", true)) {
+            components.add (moveaudio);
+        }
+        components.add(new JMenuItem(new RenameLayerAction(associatedFile, this)));
+        components.add(new JSeparator());
+        components.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
+        return components.toArray(new Component[0]);
+    }
+
+    public boolean synchronizeAudioMarkers(AudioMarker startMarker) {
+        if (startMarker != null && ! data.contains(startMarker)) {
+            startMarker = null;
+        }
+        if (startMarker == null) {
+            // find the first audioMarker in this layer
+            for (Marker m : data) {
+                if (m instanceof AudioMarker) {
+                    startMarker = (AudioMarker) m;
+                    break;
+                }
+            }
+        }
+        if (startMarker == null)
+            return false;
+
+        // apply adjustment to all subsequent audio markers in the layer
+        double adjustment = AudioPlayer.position() - startMarker.offset; // in seconds
+        boolean seenStart = false;
+        URL url = startMarker.url();
+        for (Marker m : data) {
+            if (m == startMarker)
+                seenStart = true;
+            if (seenStart) {
+                AudioMarker ma = (AudioMarker) m; // it must be an AudioMarker
+                if (ma.url().equals(url))
+                    ma.adjustOffset(adjustment);
+            }
+        }
+        return true;
+    }
+
+    public AudioMarker addAudioMarker(double time, EastNorth en) {
+        // find first audio marker to get absolute start time
+        double offset = 0.0;
+        AudioMarker am = null;
+        for (Marker m : data) {
+            if (m.getClass() == AudioMarker.class) {
+                am = (AudioMarker)m;
+                offset = time - am.time;
+                break;
+            }
+        }
+        if (am == null) {
+            JOptionPane.showMessageDialog(Main.parent,tr("No existing audio markers in this layer to offset from."));
+            return null;
+        }
+
+        // make our new marker
+        AudioMarker newAudioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(en),
+            AudioMarker.inventName(offset), AudioPlayer.url().toString(), this, time, offset);
+
+        // insert it at the right place in a copy the collection
+        Collection<Marker> newData = new ArrayList<Marker>();
+        am = null;
+        AudioMarker ret = newAudioMarker; // save to have return value
+        for (Marker m : data) {
+            if (m.getClass() == AudioMarker.class) {
+                am = (AudioMarker) m;
+                if (newAudioMarker != null && offset < am.offset) {
+                    newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same as predecessor
+                    newData.add(newAudioMarker);
+                    newAudioMarker = null;
+                }
+            }
+            newData.add(m);
+        }
+
+        if (newAudioMarker != null) {
+            if (am != null)
+                newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same as predecessor
+            newData.add(newAudioMarker); // insert at end
+        }
+
+        // replace the collection
+        data.clear();
+        data.addAll(newData);
+        return ret;
+    }
+
+    public static void playAudio() {
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        for (Layer layer : Main.map.mapView.getAllLayers()) {
+            if (layer.getClass() == MarkerLayer.class) {
+                MarkerLayer markerLayer = (MarkerLayer) layer;
+                for (Marker marker : markerLayer.data) {
+                    if (marker.getClass() == AudioMarker.class) {
+                        ((AudioMarker)marker).play();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    public static void playNextMarker() {
+        playAdjacentMarker(true);
+    }
+
+    public static void playPreviousMarker() {
+        playAdjacentMarker(false);
+    }
+
+    private static void playAdjacentMarker(boolean next) {
+        Marker startMarker = AudioMarker.recentlyPlayedMarker();
+        if (startMarker == null) {
+            // message?
+            return;
+        }
+        Marker previousMarker = null;
+        boolean nextTime = false;
+        if (Main.map == null || Main.map.mapView == null)
+            return;
+        for (Layer layer : Main.map.mapView.getAllLayers()) {
+            if (layer.getClass() == MarkerLayer.class) {
+                MarkerLayer markerLayer = (MarkerLayer) layer;
+                for (Marker marker : markerLayer.data) {
+                    if (marker == startMarker) {
+                        if (next) {
+                            nextTime = true;
+                        } else {
+                            if (previousMarker == null)
+                                previousMarker = startMarker; // if no previous one, play the first one again
+                            ((AudioMarker)previousMarker).play();
+                            break;
+                        }
+                    } else if (nextTime && marker.getClass() == AudioMarker.class) {
+                        ((AudioMarker)marker).play();
+                        return;
+                    }
+                    if (marker.getClass() == AudioMarker.class)
+                        previousMarker = marker;
+                }
+                if (nextTime) {
+                    // there was no next marker in that layer, so play the last one again
+                    ((AudioMarker)startMarker).play();
+                    return;
+                }
+            }
+        }
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java	(revision 1169)
@@ -8,20 +8,20 @@
 /**
  * This interface has to be implemented by anyone who wants to create markers.
- * 
- * When reading a gpx file, all implementations of MarkerMaker registered with 
+ *
+ * When reading a gpx file, all implementations of MarkerMaker registered with
  * the Marker are consecutively called until one returns a Marker object.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  */
 public interface MarkerProducers {
-	/**
-	 * Returns a Marker object if this implementation wants to create one for the
-	 * given input data, or <code>null</code> otherwise.
-	 * 
-	 * @param wp waypoint data 
-	 * @param relativePath An path to use for constructing relative URLs or 
-	 *        <code>null</code> for no relative URLs
-	 * @return A Marker object, or <code>null</code>.
-	 */
-	public Marker createMarker(WayPoint wp, File relativePath, MarkerLayer parentLayer, double time, double offset);
+    /**
+     * Returns a Marker object if this implementation wants to create one for the
+     * given input data, or <code>null</code> otherwise.
+     *
+     * @param wp waypoint data
+     * @param relativePath An path to use for constructing relative URLs or
+     *        <code>null</code> for no relative URLs
+     * @return A Marker object, or <code>null</code>.
+     */
+    public Marker createMarker(WayPoint wp, File relativePath, MarkerLayer parentLayer, double time, double offset);
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 1169)
@@ -31,5 +31,5 @@
 /**
  * Singleton marker class to track position of audio.
- * 
+ *
  * @author David Earl<david@frankieandshadow.com>
  *
@@ -37,307 +37,307 @@
 public class PlayHeadMarker extends Marker {
 
-	private Timer timer = null;
-	private double animationInterval = 0.0; // seconds
-	// private Rectangle audioTracer = null;
-	// private Icon audioTracerIcon = null;
-	static private PlayHeadMarker playHead = null;
-	private MapMode oldMode = null;
-	private EastNorth oldEastNorth;
-	private boolean enabled;
-	private boolean wasPlaying = false;
-	private int dropTolerance = 50; /* pixels */
-	
-	public static PlayHeadMarker create() {
-		if (playHead == null) {
-			try {
-				playHead = new PlayHeadMarker();
-			} catch (Exception ex) {
-				return null;
-			}
-		}
-		return playHead;
-	}
-	
-	private PlayHeadMarker() {
-		super(new LatLon(0.0,0.0), "", 
-			  Main.pref.get("marker.audiotracericon", "audio-tracer"), 
-			  null, -1.0, 0.0);
-		enabled = Main.pref.getBoolean("marker.traceaudio", true);
-		if (! enabled) return;
-		try { dropTolerance = Integer.parseInt(Main.pref.get("marker.playHeadDropTolerance", "50")); }
-		catch(NumberFormatException x) { dropTolerance = 50; }
-		Main.map.mapView.addMouseListener(new MouseAdapter() {
-			@Override public void mousePressed(MouseEvent ev) {
-				Point p = ev.getPoint();
-				if (ev.getButton() != MouseEvent.BUTTON1 || p == null)
-					return;
-				if (playHead.containsPoint(p)) {
-					/* when we get a click on the marker, we need to switch mode to avoid
-					 * getting confused with other drag operations (like select) */
-					oldMode = Main.map.mapMode;
-					oldEastNorth = eastNorth;
-					PlayHeadDragMode playHeadDragMode = new PlayHeadDragMode(playHead);
-					Main.map.selectMapMode(playHeadDragMode);
-					playHeadDragMode.mousePressed(ev);
-				}
-			}
-		});
-	}
-
-	@Override public boolean containsPoint(Point p) {
-		Point screen = Main.map.mapView.getPoint(eastNorth);
-		Rectangle r = new Rectangle(screen.x, screen.y, symbol.getIconWidth(), symbol.getIconHeight());
-		return r.contains(p);
-	}
-
-	/**
-	 * called back from drag mode to say when we started dragging for real 
-	 * (at least a short distance)
-	 */
-	public void startDrag() {
-		if (timer != null) 
-			timer.stop();
-		wasPlaying = AudioPlayer.playing();
-		if (wasPlaying) {
-			try { AudioPlayer.pause(); } 
-		    catch (Exception ex) { AudioPlayer.audioMalfunction(ex);}
-		}
-	}
-
-	/**
-	 * reinstate the old map mode after swuitching temporarily to do a play head drag 
-	 */
-	private void endDrag(boolean reset) {
-		if (! wasPlaying || reset) 
-			try { AudioPlayer.pause(); }
-			catch (Exception ex) { AudioPlayer.audioMalfunction(ex);}
-		if (reset)
-			eastNorth = oldEastNorth;
-		Main.map.selectMapMode(oldMode);
-		Main.map.mapView.repaint();
-		timer.start();
-	}
-	
-	/**
-	 * apply the new position resulting from a drag in progress
-	 * @param en the new position in map terms 
-	 */
-	public void drag(EastNorth en) {
-		eastNorth = en;
-		Main.map.mapView.repaint();
-	}
-
-	/**
-	 * Find the closest track point within the pixelTolerance of the screen point pNear 
-	 * @param pNear : the point in screen coordinates near which to find a track point 
-	 * @param pixelTolerance : only accept the point if within this number of pixels of en
-	 * @return the nearest trackpoint or null if nothing nearby
-	 * 
-	 * XXX seems unused, F.R. 2008-03-15
-	private WayPoint getClosestTrackPoint(Point pNear, double pixelTolerance) {
-		WayPoint cw = null;
-		AudioMarker recentlyPlayedMarker = AudioMarker.recentlyPlayedMarker();
-		if (recentlyPlayedMarker != null) {
-			// Find the track point closest to letting go of the play head 
-			double minDistance = pixelTolerance;
-			GpxLayer trackLayer = recentlyPlayedMarker.parentLayer.fromLayer;
-			if (trackLayer.data.tracks == null) 
-				return null;
-			
-			for (GpxTrack track : trackLayer.data.tracks) {
-				if (track.trackSegs == null) 
-					continue;
-
-				for (Collection<WayPoint> trackseg : track.trackSegs) {
-					for (WayPoint w : trackseg) {
-						Point p = Main.map.mapView.getPoint(w.eastNorth);
-						double distance = p.distance(pNear);
-						if (distance <= minDistance) {
-							cw = w;
-							minDistance = distance;
-						}
-					}
-				}
-			}
-		}
-		return cw;
-	}
-	*/
-	
-	/**
-	 * reposition the play head at the point on the track nearest position given,
-	 * providing we are within reasonable distance from the track; otherwise reset to the
-	 * original position.
-	 * @param en the position to start looking from
-	 */
-	public void reposition(EastNorth en) {
-		// eastNorth = en;
-		WayPoint cw = null;
-		AudioMarker recent = AudioMarker.recentlyPlayedMarker();
-		if (recent != null && recent.parentLayer != null && recent.parentLayer.fromLayer != null) {
-			/* work out EastNorth equivalent of 50 (default) pixels tolerance */ 
-			Point p = Main.map.mapView.getPoint(en);
-			EastNorth enPlus25px = Main.map.mapView.getEastNorth(p.x+dropTolerance, p.y);
-			cw = recent.parentLayer.fromLayer.nearestPointOnTrack(en, enPlus25px.east() - en.east());
-		}
-		
-		AudioMarker ca = null; 
-		/* Find the prior audio marker (there should always be one in the 
-		 * layer, even if it is only one at the start of the track) to 
-		 * offset the audio from */ 
-		if (cw != null) {
-			if (recent != null && recent.parentLayer != null) {
-				for (Marker m : recent.parentLayer.data) {
-					if (m instanceof AudioMarker) {
-						AudioMarker a = (AudioMarker) m;
-						if (a.time > cw.time)
-							break;
-						ca = a;
-					}
-				}
-			}
-		}
-
-		if (ca == null) {
-			/* Not close enough to track, or no audio marker found for some other reason */
-			JOptionPane.showMessageDialog(Main.parent, tr("You need to Drag the play head near to the GPX track whose associated sound track you were playing."));
-			endDrag(true);
-		} else {
-			eastNorth = cw.eastNorth;
-			ca.play(cw.time - ca.time);
-			endDrag(false);
-		}
-	}
-
-	/**
-	 * Synchronize the audio at the position where the play head was paused before 
-	 * dragging with the position on the track where it was dropped. 
-	 * If this is quite near an audio marker, we use that 
-	 * marker as the sync. location, otherwise we create a new marker at the 
-	 * trackpoint nearest the end point of the drag point to apply the 
-	 * sync to.
-	 * @param en : the EastNorth end point of the drag
-	 */
-	public void synchronize(EastNorth en) {
-		AudioMarker recent = AudioMarker.recentlyPlayedMarker();
-		if(recent == null)
-			return;
-		/* First, see if we dropped onto an existing audio marker in the layer being played */
-		Point startPoint = Main.map.mapView.getPoint(en);
-		AudioMarker ca = null;
-		if (recent.parentLayer != null) {
-			double closestAudioMarkerDistanceSquared = 1.0E100;
-			for (Marker m : recent.parentLayer.data) {
-				if (m instanceof AudioMarker) {
-					double distanceSquared = m.eastNorth.distanceSq(en);
-					if (distanceSquared < closestAudioMarkerDistanceSquared) {
-						ca = (AudioMarker) m;
-						closestAudioMarkerDistanceSquared = distanceSquared;
-					}
-				}
-			}
-		}
-
-		/* We found the closest marker: did we actually hit it? */
-		if (ca != null && ! ca.containsPoint(startPoint)) ca = null;
-
-		/* If we didn't hit an audio marker, we need to create one at the nearest point on the track */
-		if (ca == null) {
-			/* work out EastNorth equivalent of 50 (default) pixels tolerance */
-			Point p = Main.map.mapView.getPoint(en);
-			EastNorth enPlus25px = Main.map.mapView.getEastNorth(p.x+dropTolerance, p.y);
-			WayPoint cw = recent.parentLayer.fromLayer.nearestPointOnTrack(en, enPlus25px.east() - en.east());
-			if (cw == null) {
-				JOptionPane.showMessageDialog(Main.parent, tr("You need to SHIFT-Drag the play head onto an audio marker or onto the track point where you want to synchronize."));
-				endDrag(true);
-				return;
-			}
-			ca = recent.parentLayer.addAudioMarker(cw.time, cw.eastNorth);
-		}
-
-		/* Actually do the synchronization */
-		if(ca == null)
-		{
-			JOptionPane.showMessageDialog(Main.parent,tr("Unable to create new Audio marker."));
-			endDrag(true);
-		}
-		else if (recent.parentLayer.synchronizeAudioMarkers(ca)) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Audio synchronized at point {0}.", ca.text));
-			eastNorth = ca.eastNorth;
-			endDrag(false);
-		} else {
-			JOptionPane.showMessageDialog(Main.parent,tr("Unable to synchronize in layer being played."));
-			endDrag(true);
-		}
-	}
-	
-	public void paint(Graphics g, MapView mv /*, boolean mousePressed */) {
-		if (time < 0.0) return;
-		Point screen = mv.getPoint(eastNorth);
-		symbol.paintIcon(mv, g, screen.x, screen.y);
-	}
-
-	public void animate() {
-		if (! enabled) return;
-		if (timer == null) {
-			animationInterval = Double.parseDouble(Main.pref.get("marker.audioanimationinterval", "1")); //milliseconds
-			timer = new Timer((int)(animationInterval * 1000.0), new ActionListener() {
-				public void actionPerformed(ActionEvent e) {
-					timerAction();
-				}
-			});
-			timer.setInitialDelay(0);
-		} else {
-			timer.stop();
-		}
-		timer.start();
-	}
-	
-	/**
-	 * callback for moving play head marker according to audio player position 
-	 */
-	public void timerAction() {
-		AudioMarker recentlyPlayedMarker = AudioMarker.recentlyPlayedMarker();
-		if (recentlyPlayedMarker == null)
-			return;
-		double audioTime = recentlyPlayedMarker.time + 
-			AudioPlayer.position() - 
-			recentlyPlayedMarker.offset -
-			recentlyPlayedMarker.syncOffset;
-		if (Math.abs(audioTime - time) < animationInterval)
-			return;
-		if (recentlyPlayedMarker.parentLayer == null) return;
-		GpxLayer trackLayer = recentlyPlayedMarker.parentLayer.fromLayer;
-		if (trackLayer == null)
-			return;
-		/* find the pair of track points for this position (adjusted by the syncOffset)
-		 * and interpolate between them 
-		 */
-		WayPoint w1 = null;
-		WayPoint w2 = null;
-
-		for (GpxTrack track : trackLayer.data.tracks) {
-			for (Collection<WayPoint> trackseg : track.trackSegs) {
-				for (Iterator<WayPoint> it = trackseg.iterator(); it.hasNext();) {
-					WayPoint w = it.next();
-					if (audioTime < w.time) {
-						w2 = w;
-						break;
-					}
-					w1 = w;
-				}
-				if (w2 != null) break;
-			}
-			if (w2 != null) break;
-		}
-		
-		if (w1 == null)
-			return;
-		eastNorth = w2 == null ? 
-			w1.eastNorth : 
-			w1.eastNorth.interpolate(w2.eastNorth, 
-					(audioTime - w1.time)/(w2.time - w1.time));
-		time = audioTime;
-		Main.map.mapView.repaint();
-	}
+    private Timer timer = null;
+    private double animationInterval = 0.0; // seconds
+    // private Rectangle audioTracer = null;
+    // private Icon audioTracerIcon = null;
+    static private PlayHeadMarker playHead = null;
+    private MapMode oldMode = null;
+    private EastNorth oldEastNorth;
+    private boolean enabled;
+    private boolean wasPlaying = false;
+    private int dropTolerance = 50; /* pixels */
+
+    public static PlayHeadMarker create() {
+        if (playHead == null) {
+            try {
+                playHead = new PlayHeadMarker();
+            } catch (Exception ex) {
+                return null;
+            }
+        }
+        return playHead;
+    }
+
+    private PlayHeadMarker() {
+        super(new LatLon(0.0,0.0), "",
+              Main.pref.get("marker.audiotracericon", "audio-tracer"),
+              null, -1.0, 0.0);
+        enabled = Main.pref.getBoolean("marker.traceaudio", true);
+        if (! enabled) return;
+        try { dropTolerance = Integer.parseInt(Main.pref.get("marker.playHeadDropTolerance", "50")); }
+        catch(NumberFormatException x) { dropTolerance = 50; }
+        Main.map.mapView.addMouseListener(new MouseAdapter() {
+            @Override public void mousePressed(MouseEvent ev) {
+                Point p = ev.getPoint();
+                if (ev.getButton() != MouseEvent.BUTTON1 || p == null)
+                    return;
+                if (playHead.containsPoint(p)) {
+                    /* when we get a click on the marker, we need to switch mode to avoid
+                     * getting confused with other drag operations (like select) */
+                    oldMode = Main.map.mapMode;
+                    oldEastNorth = eastNorth;
+                    PlayHeadDragMode playHeadDragMode = new PlayHeadDragMode(playHead);
+                    Main.map.selectMapMode(playHeadDragMode);
+                    playHeadDragMode.mousePressed(ev);
+                }
+            }
+        });
+    }
+
+    @Override public boolean containsPoint(Point p) {
+        Point screen = Main.map.mapView.getPoint(eastNorth);
+        Rectangle r = new Rectangle(screen.x, screen.y, symbol.getIconWidth(), symbol.getIconHeight());
+        return r.contains(p);
+    }
+
+    /**
+     * called back from drag mode to say when we started dragging for real
+     * (at least a short distance)
+     */
+    public void startDrag() {
+        if (timer != null)
+            timer.stop();
+        wasPlaying = AudioPlayer.playing();
+        if (wasPlaying) {
+            try { AudioPlayer.pause(); }
+            catch (Exception ex) { AudioPlayer.audioMalfunction(ex);}
+        }
+    }
+
+    /**
+     * reinstate the old map mode after swuitching temporarily to do a play head drag
+     */
+    private void endDrag(boolean reset) {
+        if (! wasPlaying || reset)
+            try { AudioPlayer.pause(); }
+            catch (Exception ex) { AudioPlayer.audioMalfunction(ex);}
+        if (reset)
+            eastNorth = oldEastNorth;
+        Main.map.selectMapMode(oldMode);
+        Main.map.mapView.repaint();
+        timer.start();
+    }
+
+    /**
+     * apply the new position resulting from a drag in progress
+     * @param en the new position in map terms
+     */
+    public void drag(EastNorth en) {
+        eastNorth = en;
+        Main.map.mapView.repaint();
+    }
+
+    /**
+     * Find the closest track point within the pixelTolerance of the screen point pNear
+     * @param pNear : the point in screen coordinates near which to find a track point
+     * @param pixelTolerance : only accept the point if within this number of pixels of en
+     * @return the nearest trackpoint or null if nothing nearby
+     *
+     * XXX seems unused, F.R. 2008-03-15
+    private WayPoint getClosestTrackPoint(Point pNear, double pixelTolerance) {
+        WayPoint cw = null;
+        AudioMarker recentlyPlayedMarker = AudioMarker.recentlyPlayedMarker();
+        if (recentlyPlayedMarker != null) {
+            // Find the track point closest to letting go of the play head
+            double minDistance = pixelTolerance;
+            GpxLayer trackLayer = recentlyPlayedMarker.parentLayer.fromLayer;
+            if (trackLayer.data.tracks == null)
+                return null;
+
+            for (GpxTrack track : trackLayer.data.tracks) {
+                if (track.trackSegs == null)
+                    continue;
+
+                for (Collection<WayPoint> trackseg : track.trackSegs) {
+                    for (WayPoint w : trackseg) {
+                        Point p = Main.map.mapView.getPoint(w.eastNorth);
+                        double distance = p.distance(pNear);
+                        if (distance <= minDistance) {
+                            cw = w;
+                            minDistance = distance;
+                        }
+                    }
+                }
+            }
+        }
+        return cw;
+    }
+    */
+
+    /**
+     * reposition the play head at the point on the track nearest position given,
+     * providing we are within reasonable distance from the track; otherwise reset to the
+     * original position.
+     * @param en the position to start looking from
+     */
+    public void reposition(EastNorth en) {
+        // eastNorth = en;
+        WayPoint cw = null;
+        AudioMarker recent = AudioMarker.recentlyPlayedMarker();
+        if (recent != null && recent.parentLayer != null && recent.parentLayer.fromLayer != null) {
+            /* work out EastNorth equivalent of 50 (default) pixels tolerance */
+            Point p = Main.map.mapView.getPoint(en);
+            EastNorth enPlus25px = Main.map.mapView.getEastNorth(p.x+dropTolerance, p.y);
+            cw = recent.parentLayer.fromLayer.nearestPointOnTrack(en, enPlus25px.east() - en.east());
+        }
+
+        AudioMarker ca = null;
+        /* Find the prior audio marker (there should always be one in the
+         * layer, even if it is only one at the start of the track) to
+         * offset the audio from */
+        if (cw != null) {
+            if (recent != null && recent.parentLayer != null) {
+                for (Marker m : recent.parentLayer.data) {
+                    if (m instanceof AudioMarker) {
+                        AudioMarker a = (AudioMarker) m;
+                        if (a.time > cw.time)
+                            break;
+                        ca = a;
+                    }
+                }
+            }
+        }
+
+        if (ca == null) {
+            /* Not close enough to track, or no audio marker found for some other reason */
+            JOptionPane.showMessageDialog(Main.parent, tr("You need to Drag the play head near to the GPX track whose associated sound track you were playing."));
+            endDrag(true);
+        } else {
+            eastNorth = cw.eastNorth;
+            ca.play(cw.time - ca.time);
+            endDrag(false);
+        }
+    }
+
+    /**
+     * Synchronize the audio at the position where the play head was paused before
+     * dragging with the position on the track where it was dropped.
+     * If this is quite near an audio marker, we use that
+     * marker as the sync. location, otherwise we create a new marker at the
+     * trackpoint nearest the end point of the drag point to apply the
+     * sync to.
+     * @param en : the EastNorth end point of the drag
+     */
+    public void synchronize(EastNorth en) {
+        AudioMarker recent = AudioMarker.recentlyPlayedMarker();
+        if(recent == null)
+            return;
+        /* First, see if we dropped onto an existing audio marker in the layer being played */
+        Point startPoint = Main.map.mapView.getPoint(en);
+        AudioMarker ca = null;
+        if (recent.parentLayer != null) {
+            double closestAudioMarkerDistanceSquared = 1.0E100;
+            for (Marker m : recent.parentLayer.data) {
+                if (m instanceof AudioMarker) {
+                    double distanceSquared = m.eastNorth.distanceSq(en);
+                    if (distanceSquared < closestAudioMarkerDistanceSquared) {
+                        ca = (AudioMarker) m;
+                        closestAudioMarkerDistanceSquared = distanceSquared;
+                    }
+                }
+            }
+        }
+
+        /* We found the closest marker: did we actually hit it? */
+        if (ca != null && ! ca.containsPoint(startPoint)) ca = null;
+
+        /* If we didn't hit an audio marker, we need to create one at the nearest point on the track */
+        if (ca == null) {
+            /* work out EastNorth equivalent of 50 (default) pixels tolerance */
+            Point p = Main.map.mapView.getPoint(en);
+            EastNorth enPlus25px = Main.map.mapView.getEastNorth(p.x+dropTolerance, p.y);
+            WayPoint cw = recent.parentLayer.fromLayer.nearestPointOnTrack(en, enPlus25px.east() - en.east());
+            if (cw == null) {
+                JOptionPane.showMessageDialog(Main.parent, tr("You need to SHIFT-Drag the play head onto an audio marker or onto the track point where you want to synchronize."));
+                endDrag(true);
+                return;
+            }
+            ca = recent.parentLayer.addAudioMarker(cw.time, cw.eastNorth);
+        }
+
+        /* Actually do the synchronization */
+        if(ca == null)
+        {
+            JOptionPane.showMessageDialog(Main.parent,tr("Unable to create new Audio marker."));
+            endDrag(true);
+        }
+        else if (recent.parentLayer.synchronizeAudioMarkers(ca)) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Audio synchronized at point {0}.", ca.text));
+            eastNorth = ca.eastNorth;
+            endDrag(false);
+        } else {
+            JOptionPane.showMessageDialog(Main.parent,tr("Unable to synchronize in layer being played."));
+            endDrag(true);
+        }
+    }
+
+    public void paint(Graphics g, MapView mv /*, boolean mousePressed */) {
+        if (time < 0.0) return;
+        Point screen = mv.getPoint(eastNorth);
+        symbol.paintIcon(mv, g, screen.x, screen.y);
+    }
+
+    public void animate() {
+        if (! enabled) return;
+        if (timer == null) {
+            animationInterval = Double.parseDouble(Main.pref.get("marker.audioanimationinterval", "1")); //milliseconds
+            timer = new Timer((int)(animationInterval * 1000.0), new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    timerAction();
+                }
+            });
+            timer.setInitialDelay(0);
+        } else {
+            timer.stop();
+        }
+        timer.start();
+    }
+
+    /**
+     * callback for moving play head marker according to audio player position
+     */
+    public void timerAction() {
+        AudioMarker recentlyPlayedMarker = AudioMarker.recentlyPlayedMarker();
+        if (recentlyPlayedMarker == null)
+            return;
+        double audioTime = recentlyPlayedMarker.time +
+            AudioPlayer.position() -
+            recentlyPlayedMarker.offset -
+            recentlyPlayedMarker.syncOffset;
+        if (Math.abs(audioTime - time) < animationInterval)
+            return;
+        if (recentlyPlayedMarker.parentLayer == null) return;
+        GpxLayer trackLayer = recentlyPlayedMarker.parentLayer.fromLayer;
+        if (trackLayer == null)
+            return;
+        /* find the pair of track points for this position (adjusted by the syncOffset)
+         * and interpolate between them
+         */
+        WayPoint w1 = null;
+        WayPoint w2 = null;
+
+        for (GpxTrack track : trackLayer.data.tracks) {
+            for (Collection<WayPoint> trackseg : track.trackSegs) {
+                for (Iterator<WayPoint> it = trackseg.iterator(); it.hasNext();) {
+                    WayPoint w = it.next();
+                    if (audioTime < w.time) {
+                        w2 = w;
+                        break;
+                    }
+                    w1 = w;
+                }
+                if (w2 != null) break;
+            }
+            if (w2 != null) break;
+        }
+
+        if (w1 == null)
+            return;
+        eastNorth = w2 == null ?
+            w1.eastNorth :
+            w1.eastNorth.interpolate(w2.eastNorth,
+                    (audioTime - w1.time)/(w2.time - w1.time));
+        time = audioTime;
+        Main.map.mapView.repaint();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java	(revision 1169)
@@ -15,5 +15,5 @@
 /**
  * Marker class with Web URL activation.
- * 
+ *
  * @author Frederik Ramm <frederik@remote.org>
  *
@@ -21,28 +21,28 @@
 public class WebMarker extends ButtonMarker {
 
-	public URL webUrl;
+    public URL webUrl;
 
-	public static WebMarker create (LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
-		try {
-			return new WebMarker(ll, new URL(url), parentLayer, time, offset);
-		} catch (Exception ex) {
-			return null;
-		}
-	}
+    public static WebMarker create (LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
+        try {
+            return new WebMarker(ll, new URL(url), parentLayer, time, offset);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
 
-	private WebMarker(LatLon ll, URL webUrl, MarkerLayer parentLayer, double time, double offset) {
-		super(ll, "web.png", parentLayer, time, offset);
-		this.webUrl = webUrl;
-	}
+    private WebMarker(LatLon ll, URL webUrl, MarkerLayer parentLayer, double time, double offset) {
+        super(ll, "web.png", parentLayer, time, offset);
+        this.webUrl = webUrl;
+    }
 
-	@Override public void actionPerformed(ActionEvent ev) {
-		String error = OpenBrowser.displayUrl(webUrl.toString());
-		if (error != null) {
-			JOptionPane.showMessageDialog(Main.parent, 
-					"<html><b>" + 
-					tr("There was an error while trying to display the URL for this marker") +
-					"</b><br>" + tr("(URL was: ") + webUrl.toString() + ")" + "<br>" + error, 
-					tr("Error displaying URL"), JOptionPane.ERROR_MESSAGE);
-		}
-	}
+    @Override public void actionPerformed(ActionEvent ev) {
+        String error = OpenBrowser.displayUrl(webUrl.toString());
+        if (error != null) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    "<html><b>" +
+                    tr("There was an error while trying to display the URL for this marker") +
+                    "</b><br>" + tr("(URL was: ") + webUrl.toString() + ")" + "<br>" + error,
+                    tr("Error displaying URL"), JOptionPane.ERROR_MESSAGE);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 1169)
@@ -4,29 +4,29 @@
 public class AreaElemStyle extends ElemStyle
 {
-	public Color color;
-	public LineElemStyle line = null;
+    public Color color;
+    public LineElemStyle line = null;
 
-	public AreaElemStyle (AreaElemStyle a, long maxScale, long minScale) {
-		this.color = a.color;
-		this.priority = a.priority;
-		this.maxScale = maxScale;
-		this.minScale = minScale;
-	}
+    public AreaElemStyle (AreaElemStyle a, long maxScale, long minScale) {
+        this.color = a.color;
+        this.priority = a.priority;
+        this.maxScale = maxScale;
+        this.minScale = minScale;
+    }
 
-	public AreaElemStyle(AreaElemStyle a, LineElemStyle l)
-	{
-		this.color = a.color;
-		this.priority = a.priority;
-		this.maxScale = a.maxScale;
-		this.minScale = a.minScale;
-		this.line = l;
-	}
+    public AreaElemStyle(AreaElemStyle a, LineElemStyle l)
+    {
+        this.color = a.color;
+        this.priority = a.priority;
+        this.maxScale = a.maxScale;
+        this.minScale = a.minScale;
+        this.line = l;
+    }
 
-	public AreaElemStyle() { init(); }
+    public AreaElemStyle() { init(); }
 
-	public void init()
-	{
-		color = null;
-		priority = 0;
-	}
+    public void init()
+    {
+        color = null;
+        priority = 0;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 1169)
@@ -3,9 +3,9 @@
 abstract public class ElemStyle
 {
-	// zoom range to display the feature
-	public long minScale;
-	public long maxScale;
+    // zoom range to display the feature
+    public long minScale;
+    public long maxScale;
 
-	public int priority;
+    public int priority;
 }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyleHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyleHandler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyleHandler.java	(revision 1169)
@@ -11,206 +11,206 @@
 public class ElemStyleHandler extends DefaultHandler
 {
-	boolean inDoc, inRule, inCondition, inElemStyle, inLine, inLineMod, inIcon, inArea, inScaleMax, inScaleMin;
-	boolean hadLine, hadLineMod, hadIcon, hadArea;
-	ElemStyles styles;
-	String styleName;
-	RuleElem rule = new RuleElem();
-
-	class RuleElem {
-		String key;
-		String value;
-		String boolValue;
-		long scaleMax;
-		long scaleMin;
-		LineElemStyle line = new LineElemStyle();
-		LineElemStyle linemod = new LineElemStyle();
-		AreaElemStyle area = new AreaElemStyle();
-		IconElemStyle icon = new IconElemStyle();
-		public void init()
-		{
-			key = value = boolValue = null;
-			scaleMax = 1000000000;
-			scaleMin = 0;
-			line.init();
-			linemod.init();
-			area.init();
-			icon.init();
-		}
-	}
-
-	public ElemStyleHandler(String name) {
-		styleName = name;
-		inDoc=inRule=inCondition=inElemStyle=inLine=inIcon=inArea=false;
-		rule.init();
-		styles = MapPaintStyles.getStyles();
-	}
-
-	Color convertColor(String colString)
-	{
-		int i = colString.indexOf("#");
-		String colorString;
-		if(i < 0) // name only
-			colorString = Main.pref.get("color.mappaint."+styleName+"."+colString);
-		else if(i == 0) // value only
-			colorString = colString;
-		else // value and name
-			colorString = Main.pref.get("color.mappaint."+styleName+"."+colString.substring(0,i), colString.substring(i));
-		return ColorHelper.html2color(colorString);
-	}
-
-	@Override public void startDocument() {
-		inDoc = true;
-	}
-
-	@Override public void endDocument() {
-		inDoc = false;
-	}
-
-	@Override public void startElement(String uri,String name, String qName, Attributes atts) {
-		if (inDoc==true)
-		{
-			if (qName.equals("rule"))
-				inRule=true;
-			else if (qName.equals("scale_max"))
-				inScaleMax = true;
-			else if (qName.equals("scale_min"))
-				inScaleMin = true;
-			else if (qName.equals("condition") && inRule)
-			{
-				inCondition=true;
-				for (int count=0; count<atts.getLength(); count++)
-				{
-					if(atts.getQName(count).equals("k"))
-						rule.key = atts.getValue(count);
-					else if(atts.getQName(count).equals("v"))
-						rule.value = atts.getValue(count);
-					else if(atts.getQName(count).equals("b"))
-						rule.boolValue = atts.getValue(count);
-				}
-			}
-			else if (qName.equals("line"))
-			{
-				hadLine = inLine = true;
-				for (int count=0; count<atts.getLength(); count++)
-				{
-					if(atts.getQName(count).equals("width"))
-						rule.line.width = Integer.parseInt(atts.getValue(count));
-					else if (atts.getQName(count).equals("colour"))
-						rule.line.color=convertColor(atts.getValue(count));
-					else if (atts.getQName(count).equals("realwidth"))
-						rule.line.realWidth=Integer.parseInt(atts.getValue(count));
-					else if (atts.getQName(count).equals("dashed"))
-						rule.line.dashed=Boolean.parseBoolean(atts.getValue(count));
-					else if(atts.getQName(count).equals("priority"))
-						rule.line.priority = Integer.parseInt(atts.getValue(count));
-				}
-			}
-			else if (qName.equals("linemod"))
-			{
-				hadLineMod = inLineMod = true;
-				for (int count=0; count<atts.getLength(); count++)
-				{
-					if(atts.getQName(count).equals("width"))
-					{
-						String val = atts.getValue(count);
-						if(val.startsWith("+"))
-						{
-							rule.linemod.width = Integer.parseInt(val.substring(1));
-							rule.linemod.widthMode = LineElemStyle.WidthMode.OFFSET;
-						}
-						else if(val.startsWith("-"))
-						{
-							rule.linemod.width = Integer.parseInt(val);
-							rule.linemod.widthMode = LineElemStyle.WidthMode.OFFSET;
-						}
-						else if(val.endsWith("%"))
-						{
-							rule.linemod.width = Integer.parseInt(val.substring(0, val.length()-1));
-							rule.linemod.widthMode = LineElemStyle.WidthMode.PERCENT;
-						}
-						else
-							rule.linemod.width = Integer.parseInt(val);
-					}
-					else if (atts.getQName(count).equals("colour"))
-						rule.linemod.color=convertColor(atts.getValue(count));
-					else if (atts.getQName(count).equals("realwidth"))
-						rule.linemod.realWidth=Integer.parseInt(atts.getValue(count));
-					else if (atts.getQName(count).equals("dashed"))
-						rule.linemod.dashed=Boolean.parseBoolean(atts.getValue(count));
-					else if(atts.getQName(count).equals("priority"))
-						rule.linemod.priority = Integer.parseInt(atts.getValue(count));
-					else if(atts.getQName(count).equals("mode"))
-						rule.linemod.over = !atts.getValue(count).equals("under");
-				}
-			}
-			else if (qName.equals("icon"))
-			{
-				hadIcon = inIcon = true;
-				for (int count=0; count<atts.getLength(); count++)
-				{
-					if (atts.getQName(count).equals("src"))
-						rule.icon.icon = MapPaintStyles.getIcon(atts.getValue(count), styleName);
-					else if (atts.getQName(count).equals("annotate"))
-						rule.icon.annotate = Boolean.parseBoolean (atts.getValue(count));
-					else if(atts.getQName(count).equals("priority"))
-						rule.icon.priority = Integer.parseInt(atts.getValue(count));
-				}
-			}
-			else if (qName.equals("area"))
-			{
-				hadArea = inArea = true;
-				for (int count=0; count<atts.getLength(); count++)
-				{
-					if (atts.getQName(count).equals("colour"))
-						rule.area.color=convertColor(atts.getValue(count));
-					else if(atts.getQName(count).equals("priority"))
-						rule.area.priority = Integer.parseInt(atts.getValue(count));
-				}
-			}
-		}
-	}
-
-	@Override public void endElement(String uri,String name, String qName)
-	{
-		if (inRule && qName.equals("rule"))
-		{
-			if(hadLine)
-				styles.add(styleName, rule.key, rule.value, rule.boolValue,
-				new LineElemStyle(rule.line, rule.scaleMax, rule.scaleMin));
-			if(hadLineMod)
-				styles.addModifier(styleName, rule.key, rule.value, rule.boolValue,
-				new LineElemStyle(rule.linemod, rule.scaleMax, rule.scaleMin));
-			if(hadIcon)
-				styles.add(styleName, rule.key, rule.value, rule.boolValue,
-				new IconElemStyle(rule.icon, rule.scaleMax, rule.scaleMin));
-			if(hadArea)
-				styles.add(styleName, rule.key, rule.value, rule.boolValue,
-				new AreaElemStyle(rule.area, rule.scaleMax, rule.scaleMin));
-			inRule = false;
-			hadLine = hadLineMod = hadIcon = hadArea = false;
-			rule.init();
-		}
-		else if (inCondition && qName.equals("condition"))
-			inCondition = false;
-		else if (inLine && qName.equals("line"))
-			inLine = false;
-		else if (inLineMod && qName.equals("linemod"))
-			inLineMod = false;
-		else if (inIcon && qName.equals("icon"))
-			inIcon = false;
-		else if (inArea && qName.equals("area"))
-			inArea = false;
-		else if (qName.equals("scale_max"))
-			inScaleMax = false;
-		else if (qName.equals("scale_min"))
-			inScaleMin = false;
-	}
-
-	@Override public void characters(char ch[], int start, int length)
-	{
-		if (inScaleMax == true)
-			rule.scaleMax = Long.parseLong(new String(ch, start, length));
-		else if (inScaleMin == true)
-			rule.scaleMin = Long.parseLong(new String(ch, start, length));
-	}
+    boolean inDoc, inRule, inCondition, inElemStyle, inLine, inLineMod, inIcon, inArea, inScaleMax, inScaleMin;
+    boolean hadLine, hadLineMod, hadIcon, hadArea;
+    ElemStyles styles;
+    String styleName;
+    RuleElem rule = new RuleElem();
+
+    class RuleElem {
+        String key;
+        String value;
+        String boolValue;
+        long scaleMax;
+        long scaleMin;
+        LineElemStyle line = new LineElemStyle();
+        LineElemStyle linemod = new LineElemStyle();
+        AreaElemStyle area = new AreaElemStyle();
+        IconElemStyle icon = new IconElemStyle();
+        public void init()
+        {
+            key = value = boolValue = null;
+            scaleMax = 1000000000;
+            scaleMin = 0;
+            line.init();
+            linemod.init();
+            area.init();
+            icon.init();
+        }
+    }
+
+    public ElemStyleHandler(String name) {
+        styleName = name;
+        inDoc=inRule=inCondition=inElemStyle=inLine=inIcon=inArea=false;
+        rule.init();
+        styles = MapPaintStyles.getStyles();
+    }
+
+    Color convertColor(String colString)
+    {
+        int i = colString.indexOf("#");
+        String colorString;
+        if(i < 0) // name only
+            colorString = Main.pref.get("color.mappaint."+styleName+"."+colString);
+        else if(i == 0) // value only
+            colorString = colString;
+        else // value and name
+            colorString = Main.pref.get("color.mappaint."+styleName+"."+colString.substring(0,i), colString.substring(i));
+        return ColorHelper.html2color(colorString);
+    }
+
+    @Override public void startDocument() {
+        inDoc = true;
+    }
+
+    @Override public void endDocument() {
+        inDoc = false;
+    }
+
+    @Override public void startElement(String uri,String name, String qName, Attributes atts) {
+        if (inDoc==true)
+        {
+            if (qName.equals("rule"))
+                inRule=true;
+            else if (qName.equals("scale_max"))
+                inScaleMax = true;
+            else if (qName.equals("scale_min"))
+                inScaleMin = true;
+            else if (qName.equals("condition") && inRule)
+            {
+                inCondition=true;
+                for (int count=0; count<atts.getLength(); count++)
+                {
+                    if(atts.getQName(count).equals("k"))
+                        rule.key = atts.getValue(count);
+                    else if(atts.getQName(count).equals("v"))
+                        rule.value = atts.getValue(count);
+                    else if(atts.getQName(count).equals("b"))
+                        rule.boolValue = atts.getValue(count);
+                }
+            }
+            else if (qName.equals("line"))
+            {
+                hadLine = inLine = true;
+                for (int count=0; count<atts.getLength(); count++)
+                {
+                    if(atts.getQName(count).equals("width"))
+                        rule.line.width = Integer.parseInt(atts.getValue(count));
+                    else if (atts.getQName(count).equals("colour"))
+                        rule.line.color=convertColor(atts.getValue(count));
+                    else if (atts.getQName(count).equals("realwidth"))
+                        rule.line.realWidth=Integer.parseInt(atts.getValue(count));
+                    else if (atts.getQName(count).equals("dashed"))
+                        rule.line.dashed=Boolean.parseBoolean(atts.getValue(count));
+                    else if(atts.getQName(count).equals("priority"))
+                        rule.line.priority = Integer.parseInt(atts.getValue(count));
+                }
+            }
+            else if (qName.equals("linemod"))
+            {
+                hadLineMod = inLineMod = true;
+                for (int count=0; count<atts.getLength(); count++)
+                {
+                    if(atts.getQName(count).equals("width"))
+                    {
+                        String val = atts.getValue(count);
+                        if(val.startsWith("+"))
+                        {
+                            rule.linemod.width = Integer.parseInt(val.substring(1));
+                            rule.linemod.widthMode = LineElemStyle.WidthMode.OFFSET;
+                        }
+                        else if(val.startsWith("-"))
+                        {
+                            rule.linemod.width = Integer.parseInt(val);
+                            rule.linemod.widthMode = LineElemStyle.WidthMode.OFFSET;
+                        }
+                        else if(val.endsWith("%"))
+                        {
+                            rule.linemod.width = Integer.parseInt(val.substring(0, val.length()-1));
+                            rule.linemod.widthMode = LineElemStyle.WidthMode.PERCENT;
+                        }
+                        else
+                            rule.linemod.width = Integer.parseInt(val);
+                    }
+                    else if (atts.getQName(count).equals("colour"))
+                        rule.linemod.color=convertColor(atts.getValue(count));
+                    else if (atts.getQName(count).equals("realwidth"))
+                        rule.linemod.realWidth=Integer.parseInt(atts.getValue(count));
+                    else if (atts.getQName(count).equals("dashed"))
+                        rule.linemod.dashed=Boolean.parseBoolean(atts.getValue(count));
+                    else if(atts.getQName(count).equals("priority"))
+                        rule.linemod.priority = Integer.parseInt(atts.getValue(count));
+                    else if(atts.getQName(count).equals("mode"))
+                        rule.linemod.over = !atts.getValue(count).equals("under");
+                }
+            }
+            else if (qName.equals("icon"))
+            {
+                hadIcon = inIcon = true;
+                for (int count=0; count<atts.getLength(); count++)
+                {
+                    if (atts.getQName(count).equals("src"))
+                        rule.icon.icon = MapPaintStyles.getIcon(atts.getValue(count), styleName);
+                    else if (atts.getQName(count).equals("annotate"))
+                        rule.icon.annotate = Boolean.parseBoolean (atts.getValue(count));
+                    else if(atts.getQName(count).equals("priority"))
+                        rule.icon.priority = Integer.parseInt(atts.getValue(count));
+                }
+            }
+            else if (qName.equals("area"))
+            {
+                hadArea = inArea = true;
+                for (int count=0; count<atts.getLength(); count++)
+                {
+                    if (atts.getQName(count).equals("colour"))
+                        rule.area.color=convertColor(atts.getValue(count));
+                    else if(atts.getQName(count).equals("priority"))
+                        rule.area.priority = Integer.parseInt(atts.getValue(count));
+                }
+            }
+        }
+    }
+
+    @Override public void endElement(String uri,String name, String qName)
+    {
+        if (inRule && qName.equals("rule"))
+        {
+            if(hadLine)
+                styles.add(styleName, rule.key, rule.value, rule.boolValue,
+                new LineElemStyle(rule.line, rule.scaleMax, rule.scaleMin));
+            if(hadLineMod)
+                styles.addModifier(styleName, rule.key, rule.value, rule.boolValue,
+                new LineElemStyle(rule.linemod, rule.scaleMax, rule.scaleMin));
+            if(hadIcon)
+                styles.add(styleName, rule.key, rule.value, rule.boolValue,
+                new IconElemStyle(rule.icon, rule.scaleMax, rule.scaleMin));
+            if(hadArea)
+                styles.add(styleName, rule.key, rule.value, rule.boolValue,
+                new AreaElemStyle(rule.area, rule.scaleMax, rule.scaleMin));
+            inRule = false;
+            hadLine = hadLineMod = hadIcon = hadArea = false;
+            rule.init();
+        }
+        else if (inCondition && qName.equals("condition"))
+            inCondition = false;
+        else if (inLine && qName.equals("line"))
+            inLine = false;
+        else if (inLineMod && qName.equals("linemod"))
+            inLineMod = false;
+        else if (inIcon && qName.equals("icon"))
+            inIcon = false;
+        else if (inArea && qName.equals("area"))
+            inArea = false;
+        else if (qName.equals("scale_max"))
+            inScaleMax = false;
+        else if (qName.equals("scale_min"))
+            inScaleMin = false;
+    }
+
+    @Override public void characters(char ch[], int start, int length)
+    {
+        if (inScaleMax == true)
+            rule.scaleMax = Long.parseLong(new String(ch, start, length));
+        else if (inScaleMin == true)
+            rule.scaleMin = Long.parseLong(new String(ch, start, length));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 1169)
@@ -14,185 +14,185 @@
 public class ElemStyles
 {
-	private class StyleSet {
-		HashMap<String, IconElemStyle> icons;
-		HashMap<String, LineElemStyle> lines;
-		HashMap<String, AreaElemStyle> areas;
-		HashMap<String, LineElemStyle> modifiers;
-		public StyleSet()
-		{
-			icons = new HashMap<String, IconElemStyle>();
-			lines = new HashMap<String, LineElemStyle>();
-			modifiers = new HashMap<String, LineElemStyle>();
-			areas = new HashMap<String, AreaElemStyle>();
-		}
-	}
-	HashMap<String, StyleSet> styleSet;
+    private class StyleSet {
+        HashMap<String, IconElemStyle> icons;
+        HashMap<String, LineElemStyle> lines;
+        HashMap<String, AreaElemStyle> areas;
+        HashMap<String, LineElemStyle> modifiers;
+        public StyleSet()
+        {
+            icons = new HashMap<String, IconElemStyle>();
+            lines = new HashMap<String, LineElemStyle>();
+            modifiers = new HashMap<String, LineElemStyle>();
+            areas = new HashMap<String, AreaElemStyle>();
+        }
+    }
+    HashMap<String, StyleSet> styleSet;
 
-	public ElemStyles()
-	{
-		styleSet = new HashMap<String, StyleSet>();
-	}
+    public ElemStyles()
+    {
+        styleSet = new HashMap<String, StyleSet>();
+    }
 
-	private String getKey(String k, String v, String b)
-	{
-		if(v != null)
-			return "n" + k + "=" + v;
-		else if(b != null)
-			return "b" + k  + "=" + OsmUtils.getNamedOsmBoolean(b);
-		else
-			return "x" + k;
-	}
+    private String getKey(String k, String v, String b)
+    {
+        if(v != null)
+            return "n" + k + "=" + v;
+        else if(b != null)
+            return "b" + k  + "=" + OsmUtils.getNamedOsmBoolean(b);
+        else
+            return "x" + k;
+    }
 
-	public void add(String name, String k, String v, String b, LineElemStyle style)
-	{
-		getStyleSet(name, true).lines.put(getKey(k,v,b), style);
-	}
+    public void add(String name, String k, String v, String b, LineElemStyle style)
+    {
+        getStyleSet(name, true).lines.put(getKey(k,v,b), style);
+    }
 
-	public void addModifier(String name, String k, String v, String b, LineElemStyle style)
-	{
-		getStyleSet(name, true).modifiers.put(getKey(k,v,b), style);
-	}
+    public void addModifier(String name, String k, String v, String b, LineElemStyle style)
+    {
+        getStyleSet(name, true).modifiers.put(getKey(k,v,b), style);
+    }
 
-	public void add(String name, String k, String v, String b, AreaElemStyle style)
-	{
-		getStyleSet(name, true).areas.put(getKey(k,v,b), style);
-	}
+    public void add(String name, String k, String v, String b, AreaElemStyle style)
+    {
+        getStyleSet(name, true).areas.put(getKey(k,v,b), style);
+    }
 
-	public void add(String name, String k, String v, String b, IconElemStyle style)
-	{
-		getStyleSet(name, true).icons.put(getKey(k,v,b), style);
-	}
+    public void add(String name, String k, String v, String b, IconElemStyle style)
+    {
+        getStyleSet(name, true).icons.put(getKey(k,v,b), style);
+    }
 
-	private StyleSet getStyleSet(String name, boolean create)
-	{
-		if(name == null)
-			name = Main.pref.get("mappaint.style", "standard");
-		StyleSet s = styleSet.get(name);
-		if(create && s == null)
-		{
-			s = new StyleSet();
-			styleSet.put(name, s);
-		}
-		return s;
-	}
+    private StyleSet getStyleSet(String name, boolean create)
+    {
+        if(name == null)
+            name = Main.pref.get("mappaint.style", "standard");
+        StyleSet s = styleSet.get(name);
+        if(create && s == null)
+        {
+            s = new StyleSet();
+            styleSet.put(name, s);
+        }
+        return s;
+    }
 
-	public IconElemStyle get(Node n)
-	{
-		StyleSet ss = getStyleSet(null, false);
-		IconElemStyle ret = null;
-		if(ss != null && n.keys != null)
-		{
-			Iterator<String> iterator = n.keys.keySet().iterator();
-			while(iterator.hasNext())
-			{
-				String key = iterator.next();
-				String val = n.keys.get(key);
-				IconElemStyle style;
-				if((style = ss.icons.get("n" + key + "=" + val)) != null)
-				{
-					if(ret == null || style.priority > ret.priority)
-						ret = style;
-				}
-				if((style = ss.icons.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val))) != null)
-				{
-					if(ret == null || style.priority > ret.priority)
-						ret = style;
-				}
-				if((style = ss.icons.get("x" + key)) != null)
-				{
-					if(ret == null || style.priority > ret.priority)
-						ret = style;
-				}
-			}
-		}
-		return ret;
-	}
+    public IconElemStyle get(Node n)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        IconElemStyle ret = null;
+        if(ss != null && n.keys != null)
+        {
+            Iterator<String> iterator = n.keys.keySet().iterator();
+            while(iterator.hasNext())
+            {
+                String key = iterator.next();
+                String val = n.keys.get(key);
+                IconElemStyle style;
+                if((style = ss.icons.get("n" + key + "=" + val)) != null)
+                {
+                    if(ret == null || style.priority > ret.priority)
+                        ret = style;
+                }
+                if((style = ss.icons.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val))) != null)
+                {
+                    if(ret == null || style.priority > ret.priority)
+                        ret = style;
+                }
+                if((style = ss.icons.get("x" + key)) != null)
+                {
+                    if(ret == null || style.priority > ret.priority)
+                        ret = style;
+                }
+            }
+        }
+        return ret;
+    }
 
-	public ElemStyle get(Way w)
-	{
-		StyleSet ss = getStyleSet(null, false);
-		if(ss == null || w.keys == null)
-			return null;
-		AreaElemStyle retArea = null;
-		LineElemStyle retLine = null;
-		String linestring = null;
-		HashMap<String, LineElemStyle> over = new HashMap<String, LineElemStyle>();
-		Iterator<String> iterator = w.keys.keySet().iterator();
-		while(iterator.hasNext())
-		{
-			String key = iterator.next();
-			String val = w.keys.get(key);
-			AreaElemStyle styleArea;
-			LineElemStyle styleLine;
-			String idx = "n" + key + "=" + val;
-			if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
-				retArea = styleArea;
-			if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
-			{
-				retLine = styleLine;
-				linestring = idx;
-			}
-			if((styleLine = ss.modifiers.get(idx)) != null)
-				over.put(idx, styleLine);
-			idx = "b" + key + "=" + OsmUtils.getNamedOsmBoolean(val);
-			if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
-				retArea = styleArea;
-			if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
-			{
-				retLine = styleLine;
-				linestring = idx;
-			}
-			if((styleLine = ss.modifiers.get(idx)) != null)
-				over.put(idx, styleLine);
-			idx = "x" + key;
-			if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
-				retArea = styleArea;
-			if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
-			{
-				retLine = styleLine;
-				linestring = idx;
-			}
-			if((styleLine = ss.modifiers.get(idx)) != null)
-				over.put(idx, styleLine);
-		}
-		over.remove(linestring);
-		if(over.size() != 0 && retLine != null)
-		{
-			List<LineElemStyle> s = new LinkedList<LineElemStyle>(over.values());
-			Collections.sort(s);
-			retLine = new LineElemStyle(retLine, s);
-		}
-		if(retArea != null)
-		{
-			if(retLine != null)
-				return new AreaElemStyle(retArea, retLine);
-			else
-				return retArea;
-		}
-		return retLine;
-	}
+    public ElemStyle get(Way w)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        if(ss == null || w.keys == null)
+            return null;
+        AreaElemStyle retArea = null;
+        LineElemStyle retLine = null;
+        String linestring = null;
+        HashMap<String, LineElemStyle> over = new HashMap<String, LineElemStyle>();
+        Iterator<String> iterator = w.keys.keySet().iterator();
+        while(iterator.hasNext())
+        {
+            String key = iterator.next();
+            String val = w.keys.get(key);
+            AreaElemStyle styleArea;
+            LineElemStyle styleLine;
+            String idx = "n" + key + "=" + val;
+            if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
+                retArea = styleArea;
+            if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
+            {
+                retLine = styleLine;
+                linestring = idx;
+            }
+            if((styleLine = ss.modifiers.get(idx)) != null)
+                over.put(idx, styleLine);
+            idx = "b" + key + "=" + OsmUtils.getNamedOsmBoolean(val);
+            if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
+                retArea = styleArea;
+            if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
+            {
+                retLine = styleLine;
+                linestring = idx;
+            }
+            if((styleLine = ss.modifiers.get(idx)) != null)
+                over.put(idx, styleLine);
+            idx = "x" + key;
+            if((styleArea = ss.areas.get(idx)) != null && (retArea == null || styleArea.priority > retArea.priority))
+                retArea = styleArea;
+            if((styleLine = ss.lines.get(idx)) != null && (retLine == null || styleLine.priority > retLine.priority))
+            {
+                retLine = styleLine;
+                linestring = idx;
+            }
+            if((styleLine = ss.modifiers.get(idx)) != null)
+                over.put(idx, styleLine);
+        }
+        over.remove(linestring);
+        if(over.size() != 0 && retLine != null)
+        {
+            List<LineElemStyle> s = new LinkedList<LineElemStyle>(over.values());
+            Collections.sort(s);
+            retLine = new LineElemStyle(retLine, s);
+        }
+        if(retArea != null)
+        {
+            if(retLine != null)
+                return new AreaElemStyle(retArea, retLine);
+            else
+                return retArea;
+        }
+        return retLine;
+    }
 
-	public boolean isArea(Way w)
-	{
-		StyleSet ss = getStyleSet(null, false);
-		if(ss != null && w.keys != null)
-		{
-			Iterator<String> iterator = w.keys.keySet().iterator();
-			while(iterator.hasNext())
-			{
-				String key = iterator.next();
-				String val = w.keys.get(key);
-				if(ss.areas.containsKey("n" + key + "=" + val)
-				|| ss.areas.containsKey("n" + key + "=" + OsmUtils.getNamedOsmBoolean(val))
-				|| ss.areas.containsKey("x" + key))
-					return true;
-			}
-		}
-		return false;
-	}
-	public boolean hasAreas()
-	{
-		StyleSet ss = getStyleSet(null, false);
-		return ss != null && ss.areas.size() > 0;
-	}
+    public boolean isArea(Way w)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        if(ss != null && w.keys != null)
+        {
+            Iterator<String> iterator = w.keys.keySet().iterator();
+            while(iterator.hasNext())
+            {
+                String key = iterator.next();
+                String val = w.keys.get(key);
+                if(ss.areas.containsKey("n" + key + "=" + val)
+                || ss.areas.containsKey("n" + key + "=" + OsmUtils.getNamedOsmBoolean(val))
+                || ss.areas.containsKey("x" + key))
+                    return true;
+            }
+        }
+        return false;
+    }
+    public boolean hasAreas()
+    {
+        StyleSet ss = getStyleSet(null, false);
+        return ss != null && ss.areas.size() > 0;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java	(revision 1169)
@@ -4,21 +4,21 @@
 public class IconElemStyle extends ElemStyle
 {
-	public ImageIcon icon;
-	public boolean annotate;
+    public ImageIcon icon;
+    public boolean annotate;
 
-	public IconElemStyle (IconElemStyle i, long maxScale, long minScale) {
-		this.icon = i.icon;
-		this.annotate = i.annotate;
-		this.priority = i.priority;
-		this.maxScale = maxScale;
-		this.minScale = minScale;
-	}
-	public IconElemStyle() { init(); }
+    public IconElemStyle (IconElemStyle i, long maxScale, long minScale) {
+        this.icon = i.icon;
+        this.annotate = i.annotate;
+        this.priority = i.priority;
+        this.maxScale = maxScale;
+        this.minScale = minScale;
+    }
+    public IconElemStyle() { init(); }
 
-	public void init()
-	{
-		icon = null;
-		priority = 0;
-		annotate = true;
-	}
+    public void init()
+    {
+        icon = null;
+        priority = 0;
+        annotate = true;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 1169)
@@ -6,83 +6,83 @@
 public class LineElemStyle extends ElemStyle implements Comparable<LineElemStyle>
 {
-	public int width;
-	public int realWidth; //the real width of this line in meter
-	public Color color;
-	public boolean dashed;
+    public int width;
+    public int realWidth; //the real width of this line in meter
+    public Color color;
+    public boolean dashed;
 
-	public boolean over;
-	public enum WidthMode { ABSOLUTE, PERCENT, OFFSET }
-	public WidthMode widthMode;
+    public boolean over;
+    public enum WidthMode { ABSOLUTE, PERCENT, OFFSET }
+    public WidthMode widthMode;
 
-	public Collection<LineElemStyle> overlays;
+    public Collection<LineElemStyle> overlays;
 
-	public LineElemStyle(LineElemStyle s, long maxScale, long minScale) {
-		this.width = s.width;
-		this.realWidth = s.realWidth;
-		this.color = s.color;
-		this.dashed = s.dashed;
-		this.over = s.over;
-		this.widthMode = s.widthMode;
+    public LineElemStyle(LineElemStyle s, long maxScale, long minScale) {
+        this.width = s.width;
+        this.realWidth = s.realWidth;
+        this.color = s.color;
+        this.dashed = s.dashed;
+        this.over = s.over;
+        this.widthMode = s.widthMode;
 
-		this.priority = s.priority;
-		this.maxScale = maxScale;
-		this.minScale = minScale;
-	}
+        this.priority = s.priority;
+        this.maxScale = maxScale;
+        this.minScale = minScale;
+    }
 
-	public LineElemStyle(LineElemStyle s, Collection<LineElemStyle> overlays) {
-		this.width = s.width;
-		this.realWidth = s.realWidth;
-		this.color = s.color;
-		this.dashed = s.dashed;
-		this.over = s.over;
-		this.widthMode = s.widthMode;
+    public LineElemStyle(LineElemStyle s, Collection<LineElemStyle> overlays) {
+        this.width = s.width;
+        this.realWidth = s.realWidth;
+        this.color = s.color;
+        this.dashed = s.dashed;
+        this.over = s.over;
+        this.widthMode = s.widthMode;
 
-		this.priority = s.priority;
-		this.maxScale = s.maxScale;
-		this.minScale = s.minScale;
+        this.priority = s.priority;
+        this.maxScale = s.maxScale;
+        this.minScale = s.minScale;
 
-		this.overlays = overlays;
-	}
+        this.overlays = overlays;
+    }
 
-	public LineElemStyle() { init(); }
+    public LineElemStyle() { init(); }
 
-	public void init()
-	{
-		width = 1;
-		realWidth = 0;
-		dashed = false;
-		priority = 0;
-		color = null;
-		over = true; // only used for line modifications
-		widthMode = WidthMode.ABSOLUTE;
-		overlays = null;
-	}
+    public void init()
+    {
+        width = 1;
+        realWidth = 0;
+        dashed = false;
+        priority = 0;
+        color = null;
+        over = true; // only used for line modifications
+        widthMode = WidthMode.ABSOLUTE;
+        overlays = null;
+    }
 
-	// get width for overlays
-	public int getWidth(int ref)
-	{
-		int res;
-		if(widthMode == WidthMode.ABSOLUTE)
-			res = width;
-		else if(widthMode == WidthMode.OFFSET)
-			res = ref + width;
-		else
-		{
-			if(width < 0)
-				res = 0;
-			else
-				res = ref*width/100;
-		}
-		return res <= 0 ? 1 : res;
-	}
+    // get width for overlays
+    public int getWidth(int ref)
+    {
+        int res;
+        if(widthMode == WidthMode.ABSOLUTE)
+            res = width;
+        else if(widthMode == WidthMode.OFFSET)
+            res = ref + width;
+        else
+        {
+            if(width < 0)
+                res = 0;
+            else
+                res = ref*width/100;
+        }
+        return res <= 0 ? 1 : res;
+    }
 
-	public int compareTo(LineElemStyle s)
-	{
-		if(s.priority != priority)
-			return s.priority > priority ? 1 : -1;
-		if(!over && s.over)
-			return -1;
-		// we have no idea how to order other objects :-)
-		return 0;
-	}
+    public int compareTo(LineElemStyle s)
+    {
+        if(s.priority != priority)
+            return s.priority > priority ? 1 : -1;
+        if(!over && s.over)
+            return -1;
+        // we have no idea how to order other objects :-)
+        return 0;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 1169)
@@ -16,69 +16,69 @@
 public class MapPaintStyles {
 
-	private static ElemStyles styles = new ElemStyles();
-	private static String iconDirs;
-	
-	public static ElemStyles getStyles()
-	{
-		return styles;
-	}
+    private static ElemStyles styles = new ElemStyles();
+    private static String iconDirs;
 
-	public static ImageIcon getIcon(String name, String styleName)
-	{
-		List<String> dirs = new LinkedList<String>();
-		for(String fileset : iconDirs.split(";"))
-		{
-			String[] a;
-			if(fileset.indexOf("=") >= 0)
-				a = fileset.split("=", 2);
-			else
-				a = new String[] {"", fileset};
+    public static ElemStyles getStyles()
+    {
+        return styles;
+    }
 
-			/* non-prefixed path is generic path, always take it */
-			if(a[0].length() == 0 || styleName.equals(a[0]))
-				dirs.add(a[1]);
-		}
-		ImageIcon i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, name);		
-		if(i == null)
-		{
-			System.out.println("Mappaint-Style \""+styleName+"\" icon \"" + name + "\" not found.");
-			i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, "misc/no_icon.png");
-		}
-		return i;
-	}
+    public static ImageIcon getIcon(String name, String styleName)
+    {
+        List<String> dirs = new LinkedList<String>();
+        for(String fileset : iconDirs.split(";"))
+        {
+            String[] a;
+            if(fileset.indexOf("=") >= 0)
+                a = fileset.split("=", 2);
+            else
+                a = new String[] {"", fileset};
 
-	public static void readFromPreferences() {
-		/* don't prefix icon path, as it should be generic */
-		String internalicon = "resource://images/styles/standard/;resource://images/styles/";
-		String internalfile = "standard=resource://styles/standard/elemstyles.xml";
+            /* non-prefixed path is generic path, always take it */
+            if(a[0].length() == 0 || styleName.equals(a[0]))
+                dirs.add(a[1]);
+        }
+        ImageIcon i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, name);
+        if(i == null)
+        {
+            System.out.println("Mappaint-Style \""+styleName+"\" icon \"" + name + "\" not found.");
+            i = ImageProvider.getIfAvailable(dirs, "mappaint."+styleName, null, "misc/no_icon.png");
+        }
+        return i;
+    }
 
-		iconDirs = Main.pref.get("mappaint.iconpaths");
-		iconDirs = iconDirs == null || iconDirs.length() == 0 ? internalicon : iconDirs + ";" + internalicon;
+    public static void readFromPreferences() {
+        /* don't prefix icon path, as it should be generic */
+        String internalicon = "resource://images/styles/standard/;resource://images/styles/";
+        String internalfile = "standard=resource://styles/standard/elemstyles.xml";
 
-		String file = Main.pref.get("mappaint.sources");
-		file = file == null || file.length() == 0 ? internalfile : internalfile + ";" + file;
+        iconDirs = Main.pref.get("mappaint.iconpaths");
+        iconDirs = iconDirs == null || iconDirs.length() == 0 ? internalicon : iconDirs + ";" + internalicon;
 
-		for(String fileset : file.split(";"))
-		{
-			try
-			{
-				String[] a;
-				if(fileset.indexOf("=") >= 0)
-					a = fileset.split("=", 2);
-				else
-					a = new String[] {"standard", fileset};
-				XMLReader xmlReader = XMLReaderFactory.createXMLReader();
-				ElemStyleHandler handler = new ElemStyleHandler(a[0]);
-				xmlReader.setContentHandler(handler);
-				xmlReader.setErrorHandler(handler);
-				xmlReader.parse(new InputSource(new MirroredInputStream(a[1])));
-			}
-			catch (Exception e)
-			{
-				System.out.println("Mappaint-Style problems: \"" + fileset + "\"");
-			}
-		} 
-		iconDirs = null;
-	}
+        String file = Main.pref.get("mappaint.sources");
+        file = file == null || file.length() == 0 ? internalfile : internalfile + ";" + file;
+
+        for(String fileset : file.split(";"))
+        {
+            try
+            {
+                String[] a;
+                if(fileset.indexOf("=") >= 0)
+                    a = fileset.split("=", 2);
+                else
+                    a = new String[] {"standard", fileset};
+                XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+                ElemStyleHandler handler = new ElemStyleHandler(a[0]);
+                xmlReader.setContentHandler(handler);
+                xmlReader.setErrorHandler(handler);
+                xmlReader.parse(new InputSource(new MirroredInputStream(a[1])));
+            }
+            catch (Exception e)
+            {
+                System.out.println("Mappaint-Style problems: \"" + fileset + "\"");
+            }
+        }
+        iconDirs = null;
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AdvancedPreference.java	(revision 1169)
@@ -31,132 +31,132 @@
 public class AdvancedPreference implements PreferenceSetting {
 
-	private Map<String,String> orig;
-	private Map<String,String> defaults;
-	private DefaultTableModel model;
+    private Map<String,String> orig;
+    private Map<String,String> defaults;
+    private DefaultTableModel model;
 
-	public void addGui(final PreferenceDialog gui) {
-		JPanel p = gui.createPreferenceTab("advanced", tr("Advanced Preferences"), 
-		        tr("Setting Preference entries directly. Use with caution!"), false);
+    public void addGui(final PreferenceDialog gui) {
+        JPanel p = gui.createPreferenceTab("advanced", tr("Advanced Preferences"),
+                tr("Setting Preference entries directly. Use with caution!"), false);
 
-		model = new DefaultTableModel(new String[]{tr("Key"), tr("Value")},0) {
-			@Override public boolean isCellEditable(int row, int column) {
-				return column != 0;
-			}
-		};
-		DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(){
-			public Component getTableCellRendererComponent(JTable table, Object value,
-				boolean isSelected, boolean hasFocus, int row, int column)
-			{
-				JLabel label=new JLabel();
-				String s = defaults.get(value);
-				if(s != null)
-				{
-					if(s.equals(model.getValueAt(row, 1)))
-						label.setToolTipText(tr("Current value is default."));
-					else
-						label.setToolTipText(tr("Default value is ''{0}''.", s));
-				}
-				else
-					label.setToolTipText(tr("Default value currently unknown (setting has not been used yet)."));
-				label.setText((String)value);
-				return label;
-			}
-		};
-		final JTable list = new JTable(model);
-		list.getColumn(tr("Key")).setCellRenderer(renderer);
-		JScrollPane scroll = new JScrollPane(list);
-		p.add(scroll, GBC.eol().fill(GBC.BOTH));
-		scroll.setPreferredSize(new Dimension(400,200));
+        model = new DefaultTableModel(new String[]{tr("Key"), tr("Value")},0) {
+            @Override public boolean isCellEditable(int row, int column) {
+                return column != 0;
+            }
+        };
+        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(){
+            public Component getTableCellRendererComponent(JTable table, Object value,
+                boolean isSelected, boolean hasFocus, int row, int column)
+            {
+                JLabel label=new JLabel();
+                String s = defaults.get(value);
+                if(s != null)
+                {
+                    if(s.equals(model.getValueAt(row, 1)))
+                        label.setToolTipText(tr("Current value is default."));
+                    else
+                        label.setToolTipText(tr("Default value is ''{0}''.", s));
+                }
+                else
+                    label.setToolTipText(tr("Default value currently unknown (setting has not been used yet)."));
+                label.setText((String)value);
+                return label;
+            }
+        };
+        final JTable list = new JTable(model);
+        list.getColumn(tr("Key")).setCellRenderer(renderer);
+        JScrollPane scroll = new JScrollPane(list);
+        p.add(scroll, GBC.eol().fill(GBC.BOTH));
+        scroll.setPreferredSize(new Dimension(400,200));
 
-		orig = Main.pref.getAllPrefix("");
-		defaults = Main.pref.getDefaults();
-		orig.remove("osm-server.password");
-		defaults.remove("osm-server.password");
-		TreeSet<String> ts = new TreeSet<String>(orig.keySet());
-		for (String s : defaults.keySet())
-		{
-			if(!ts.contains(s))
-				ts.add(s);
-		}
+        orig = Main.pref.getAllPrefix("");
+        defaults = Main.pref.getDefaults();
+        orig.remove("osm-server.password");
+        defaults.remove("osm-server.password");
+        TreeSet<String> ts = new TreeSet<String>(orig.keySet());
+        for (String s : defaults.keySet())
+        {
+            if(!ts.contains(s))
+                ts.add(s);
+        }
 
-		for (String s : ts)
-		{
-			String val = Main.pref.get(s);
-			if(val == null) val = "";
-			model.addRow(new String[]{s, val});
-		}
+        for (String s : ts)
+        {
+            String val = Main.pref.get(s);
+            if(val == null) val = "";
+            model.addRow(new String[]{s, val});
+        }
 
-		JButton add = new JButton(tr("Add"));
-		p.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-		p.add(add, GBC.std().insets(0,5,0,0));
-		add.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				JPanel p = new JPanel(new GridBagLayout());
-				p.add(new JLabel(tr("Key")), GBC.std().insets(0,0,5,0));
-				JTextField key = new JTextField(10);
-				JTextField value = new JTextField(10);
-				p.add(key, GBC.eop().insets(5,0,0,0).fill(GBC.HORIZONTAL));
-				p.add(new JLabel(tr("Value")), GBC.std().insets(0,0,5,0));
-				p.add(value, GBC.eol().insets(5,0,0,0).fill(GBC.HORIZONTAL));
-				int answer = JOptionPane.showConfirmDialog(gui, p, tr("Enter a new key/value pair"), JOptionPane.OK_CANCEL_OPTION);
-				if (answer == JOptionPane.OK_OPTION)
-					model.addRow(new String[]{key.getText(), value.getText()});
-			}
-		});
+        JButton add = new JButton(tr("Add"));
+        p.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(add, GBC.std().insets(0,5,0,0));
+        add.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JPanel p = new JPanel(new GridBagLayout());
+                p.add(new JLabel(tr("Key")), GBC.std().insets(0,0,5,0));
+                JTextField key = new JTextField(10);
+                JTextField value = new JTextField(10);
+                p.add(key, GBC.eop().insets(5,0,0,0).fill(GBC.HORIZONTAL));
+                p.add(new JLabel(tr("Value")), GBC.std().insets(0,0,5,0));
+                p.add(value, GBC.eol().insets(5,0,0,0).fill(GBC.HORIZONTAL));
+                int answer = JOptionPane.showConfirmDialog(gui, p, tr("Enter a new key/value pair"), JOptionPane.OK_CANCEL_OPTION);
+                if (answer == JOptionPane.OK_OPTION)
+                    model.addRow(new String[]{key.getText(), value.getText()});
+            }
+        });
 
-		JButton edit = new JButton(tr("Edit"));
-		p.add(edit, GBC.std().insets(5,5,5,0));
-		edit.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				edit(gui, list);
-			}
-		});
+        JButton edit = new JButton(tr("Edit"));
+        p.add(edit, GBC.std().insets(5,5,5,0));
+        edit.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                edit(gui, list);
+            }
+        });
 
-		JButton delete = new JButton(tr("Delete"));
-		p.add(delete, GBC.std().insets(0,5,0,0));
-		delete.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (list.getSelectedRowCount() == 0) {
-					JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
-					return;
-				}
-				for(int row: list.getSelectedRows())
-					model.setValueAt("", row, 1);
-			}
-		});
+        JButton delete = new JButton(tr("Delete"));
+        p.add(delete, GBC.std().insets(0,5,0,0));
+        delete.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (list.getSelectedRowCount() == 0) {
+                    JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
+                    return;
+                }
+                for(int row: list.getSelectedRows())
+                    model.setValueAt("", row, 1);
+            }
+        });
 
-		list.addMouseListener(new MouseAdapter(){
-			@Override public void mouseClicked(MouseEvent e) {
-				if (e.getClickCount() == 2)
-					edit(gui, list);
-			}
-		});
-	}
+        list.addMouseListener(new MouseAdapter(){
+            @Override public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2)
+                    edit(gui, list);
+            }
+        });
+    }
 
-	public void ok() {
-		for (int i = 0; i < model.getRowCount(); ++i) {
-			String value = model.getValueAt(i,1).toString();
-			if(value.length() != 0)
-			{
-				String key = model.getValueAt(i,0).toString();
-				String origValue = orig.get(key);
-				if (origValue == null || !origValue.equals(value))
-					Main.pref.put(key, value);
-				orig.remove(key); // processed.
-			}
-		}
-		for (Entry<String, String> e : orig.entrySet())
-			Main.pref.put(e.getKey(), null);
-	}
+    public void ok() {
+        for (int i = 0; i < model.getRowCount(); ++i) {
+            String value = model.getValueAt(i,1).toString();
+            if(value.length() != 0)
+            {
+                String key = model.getValueAt(i,0).toString();
+                String origValue = orig.get(key);
+                if (origValue == null || !origValue.equals(value))
+                    Main.pref.put(key, value);
+                orig.remove(key); // processed.
+            }
+        }
+        for (Entry<String, String> e : orig.entrySet())
+            Main.pref.put(e.getKey(), null);
+    }
 
 
-	private void edit(final PreferenceDialog gui, final JTable list) {
-		if (list.getSelectedRowCount() != 1) {
-			JOptionPane.showMessageDialog(gui, tr("Please select the row to edit."));
-			return;
-		}
-		String v = JOptionPane.showInputDialog(tr("New value for {0}", model.getValueAt(list.getSelectedRow(), 0)), model.getValueAt(list.getSelectedRow(), 1));
-		if (v != null)
-			model.setValueAt(v, list.getSelectedRow(), 1);
-	}
+    private void edit(final PreferenceDialog gui, final JTable list) {
+        if (list.getSelectedRowCount() != 1) {
+            JOptionPane.showMessageDialog(gui, tr("Please select the row to edit."));
+            return;
+        }
+        String v = JOptionPane.showInputDialog(tr("New value for {0}", model.getValueAt(list.getSelectedRow(), 0)), model.getValueAt(list.getSelectedRow(), 1));
+        if (v != null)
+            model.setValueAt(v, list.getSelectedRow(), 1);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 1169)
@@ -27,148 +27,148 @@
 
 public class AudioPreference implements PreferenceSetting {
-	private JCheckBox audioMenuVisible = new JCheckBox(tr("Display the Audio menu."));
-	private JCheckBox markerButtonLabels = new JCheckBox(tr("Label audio (and image and web) markers."));
-	private JCheckBox markerAudioTraceVisible = new JCheckBox(tr("Display live audio trace."));
-	private JCheckBox makeAutoMarkers = new JCheckBox(tr("Create non-audio markers when reading GPX."));
+    private JCheckBox audioMenuVisible = new JCheckBox(tr("Display the Audio menu."));
+    private JCheckBox markerButtonLabels = new JCheckBox(tr("Label audio (and image and web) markers."));
+    private JCheckBox markerAudioTraceVisible = new JCheckBox(tr("Display live audio trace."));
+    private JCheckBox makeAutoMarkers = new JCheckBox(tr("Create non-audio markers when reading GPX."));
 
-	// various methods of making markers on import audio
-	private JCheckBox audioMarkersFromExplicitWaypoints = new JCheckBox(tr("Explicit waypoints with valid timestamps."));
-	private JCheckBox audioMarkersFromUntimedWaypoints = new JCheckBox(tr("Explicit waypoints with time estimated from track position."));
-	private JCheckBox audioMarkersFromNamedTrackpoints = new JCheckBox(tr("Named trackpoints."));
-	private JCheckBox audioMarkersFromStart = new JCheckBox(tr("Start of track (will always do this if no other markers available)."));
+    // various methods of making markers on import audio
+    private JCheckBox audioMarkersFromExplicitWaypoints = new JCheckBox(tr("Explicit waypoints with valid timestamps."));
+    private JCheckBox audioMarkersFromUntimedWaypoints = new JCheckBox(tr("Explicit waypoints with time estimated from track position."));
+    private JCheckBox audioMarkersFromNamedTrackpoints = new JCheckBox(tr("Named trackpoints."));
+    private JCheckBox audioMarkersFromStart = new JCheckBox(tr("Start of track (will always do this if no other markers available)."));
 
-	private JTextField audioLeadIn = new JTextField(8);
-	private JTextField audioForwardBackAmount = new JTextField(8);
-	private JTextField audioFastForwardMultiplier = new JTextField(8);
-	private JTextField audioCalibration = new JTextField(8);
+    private JTextField audioLeadIn = new JTextField(8);
+    private JTextField audioForwardBackAmount = new JTextField(8);
+    private JTextField audioFastForwardMultiplier = new JTextField(8);
+    private JTextField audioCalibration = new JTextField(8);
 
-	public void addGui(PreferenceDialog gui) {
-		// audioMenuVisible
-		audioMenuVisible.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!audioMenuVisible.isSelected())
-					audioMenuVisible.setSelected(false);
-				audioMenuVisible.setEnabled(audioMenuVisible.isSelected());
-			}
-		});
-		audioMenuVisible.setSelected(! Main.pref.getBoolean("audio.menuinvisible"));
-		audioMenuVisible.setToolTipText(tr("Show or hide the audio menu entry on the main menu bar."));
-		gui.audio.add(audioMenuVisible, GBC.eol().insets(0,0,0,0));
+    public void addGui(PreferenceDialog gui) {
+        // audioMenuVisible
+        audioMenuVisible.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!audioMenuVisible.isSelected())
+                    audioMenuVisible.setSelected(false);
+                audioMenuVisible.setEnabled(audioMenuVisible.isSelected());
+            }
+        });
+        audioMenuVisible.setSelected(! Main.pref.getBoolean("audio.menuinvisible"));
+        audioMenuVisible.setToolTipText(tr("Show or hide the audio menu entry on the main menu bar."));
+        gui.audio.add(audioMenuVisible, GBC.eol().insets(0,0,0,0));
 
-		// audioTraceVisible
-		markerAudioTraceVisible.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!markerAudioTraceVisible.isSelected())
-					markerAudioTraceVisible.setSelected(false);
-			}
-		});
-		markerAudioTraceVisible.setSelected(Main.pref.getBoolean("marker.traceaudio", true));
-		markerAudioTraceVisible.setToolTipText(tr("Display a moving icon representing the point on the synchronized track where the audio currently playing was recorded."));
-		gui.audio.add(markerAudioTraceVisible, GBC.eol().insets(0,0,0,0));
-		
-		// buttonLabels
-		markerButtonLabels.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!markerButtonLabels.isSelected())
-					markerButtonLabels.setSelected(false);
-			}
-		});
-		markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels"));
-		markerButtonLabels.setToolTipText(tr("Put text labels against audio (and image and web) markers as well as their button icons."));
-		gui.audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
-		
-		// makeAutoMarkers
-		makeAutoMarkers.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!makeAutoMarkers.isSelected())
-					makeAutoMarkers.setSelected(false);
-			}
-		});
-		makeAutoMarkers.setSelected(Main.pref.getBoolean("marker.makeautomarkers", true));
-		makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
-		gui.audio.add(makeAutoMarkers, GBC.eol().insets(0,0,0,0));
-		
-		gui.audio.add(new JLabel(tr("When importing audio, make markers from...")), GBC.eol());
+        // audioTraceVisible
+        markerAudioTraceVisible.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!markerAudioTraceVisible.isSelected())
+                    markerAudioTraceVisible.setSelected(false);
+            }
+        });
+        markerAudioTraceVisible.setSelected(Main.pref.getBoolean("marker.traceaudio", true));
+        markerAudioTraceVisible.setToolTipText(tr("Display a moving icon representing the point on the synchronized track where the audio currently playing was recorded."));
+        gui.audio.add(markerAudioTraceVisible, GBC.eol().insets(0,0,0,0));
 
-		// audioMarkersFromExplicitWaypoints
-		audioMarkersFromExplicitWaypoints.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!audioMarkersFromExplicitWaypoints.isSelected())
-					audioMarkersFromExplicitWaypoints.setSelected(false);
-			}
-		});
-		audioMarkersFromExplicitWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true));
-		audioMarkersFromExplicitWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
-		gui.audio.add(audioMarkersFromExplicitWaypoints, GBC.eol().insets(10,0,0,0));
-		
-		// audioMarkersFromUntimedWaypoints
-		audioMarkersFromUntimedWaypoints.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!audioMarkersFromUntimedWaypoints.isSelected())
-					audioMarkersFromUntimedWaypoints.setSelected(false);
-			}
-		});
-		audioMarkersFromUntimedWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true));
-		audioMarkersFromUntimedWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
-		gui.audio.add(audioMarkersFromUntimedWaypoints, GBC.eol().insets(10,0,0,0));
-		
-		// audioMarkersFromNamedTrackpoints
-		audioMarkersFromNamedTrackpoints.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!audioMarkersFromNamedTrackpoints.isSelected())
-					audioMarkersFromNamedTrackpoints.setSelected(false);
-			}
-		});
-		audioMarkersFromNamedTrackpoints.setSelected(Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false));
-		audioMarkersFromNamedTrackpoints.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
-		gui.audio.add(audioMarkersFromNamedTrackpoints, GBC.eol().insets(10,0,0,0));
-		
-		// audioMarkersFromStart
-		audioMarkersFromStart.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (!audioMarkersFromStart.isSelected())
-					audioMarkersFromStart.setSelected(false);
-			}
-		});
-		audioMarkersFromStart.setSelected(Main.pref.getBoolean("marker.audiofromstart"));
-		audioMarkersFromStart.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
-		gui.audio.add(audioMarkersFromStart, GBC.eol().insets(10,0,0,0));
-		
-		audioForwardBackAmount.setText(Main.pref.get("audio.forwardbackamount", "10.0"));
-		audioForwardBackAmount.setToolTipText(tr("The number of seconds to jump forward or back when the relevant button is pressed"));
-		gui.audio.add(new JLabel(tr("Forward/back time (seconds)")), GBC.std());
-		gui.audio.add(audioForwardBackAmount, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        // buttonLabels
+        markerButtonLabels.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!markerButtonLabels.isSelected())
+                    markerButtonLabels.setSelected(false);
+            }
+        });
+        markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels"));
+        markerButtonLabels.setToolTipText(tr("Put text labels against audio (and image and web) markers as well as their button icons."));
+        gui.audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
 
-		audioFastForwardMultiplier.setText(Main.pref.get("audio.fastfwdmultiplier", "1.3"));
-		audioFastForwardMultiplier.setToolTipText(tr("The amount by which the speed is multiplied for fast forwarding"));
-		gui.audio.add(new JLabel(tr("Fast forward multiplier")), GBC.std());
-		gui.audio.add(audioFastForwardMultiplier, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        // makeAutoMarkers
+        makeAutoMarkers.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!makeAutoMarkers.isSelected())
+                    makeAutoMarkers.setSelected(false);
+            }
+        });
+        makeAutoMarkers.setSelected(Main.pref.getBoolean("marker.makeautomarkers", true));
+        makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
+        gui.audio.add(makeAutoMarkers, GBC.eol().insets(0,0,0,0));
 
-		audioLeadIn.setText(Main.pref.get("audio.leadin", "1"));
-		audioLeadIn.setToolTipText(tr("Playback starts this number of seconds before (or after, if negative) the audio track position requested"));
-		gui.audio.add(new JLabel(tr("Lead-in time (seconds)")), GBC.std());
-		gui.audio.add(audioLeadIn, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.audio.add(new JLabel(tr("When importing audio, make markers from...")), GBC.eol());
 
-		audioCalibration.setText(Main.pref.get("audio.calibration", "1.0"));
-		audioCalibration.setToolTipText(tr("The ratio of voice recorder elapsed time to true elapsed time"));
-		gui.audio.add(new JLabel(tr("Voice recorder calibration")), GBC.std());
-		gui.audio.add(audioCalibration, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        // audioMarkersFromExplicitWaypoints
+        audioMarkersFromExplicitWaypoints.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!audioMarkersFromExplicitWaypoints.isSelected())
+                    audioMarkersFromExplicitWaypoints.setSelected(false);
+            }
+        });
+        audioMarkersFromExplicitWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true));
+        audioMarkersFromExplicitWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
+        gui.audio.add(audioMarkersFromExplicitWaypoints, GBC.eol().insets(10,0,0,0));
 
-		gui.audio.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
-	}
+        // audioMarkersFromUntimedWaypoints
+        audioMarkersFromUntimedWaypoints.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!audioMarkersFromUntimedWaypoints.isSelected())
+                    audioMarkersFromUntimedWaypoints.setSelected(false);
+            }
+        });
+        audioMarkersFromUntimedWaypoints.setSelected(Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true));
+        audioMarkersFromUntimedWaypoints.setToolTipText(tr("When importing audio, apply it to any waypoints in the GPX layer."));
+        gui.audio.add(audioMarkersFromUntimedWaypoints, GBC.eol().insets(10,0,0,0));
 
-	public void ok() {
-		Main.pref.put("audio.menuinvisible", ! audioMenuVisible.isSelected());
-		Main.pref.put("marker.traceaudio", markerAudioTraceVisible.isSelected());
-		Main.pref.put("marker.buttonlabels", markerButtonLabels.isSelected());
-		Main.pref.put("marker.makeautomarkers", makeAutoMarkers.isSelected());
-		Main.pref.put("marker.audiofromexplicitwaypoints", audioMarkersFromExplicitWaypoints.isSelected());
-		Main.pref.put("marker.audiofromuntimedwaypoints", audioMarkersFromUntimedWaypoints.isSelected());
-		Main.pref.put("marker.audiofromnamedtrackpoints", audioMarkersFromNamedTrackpoints.isSelected());
-		Main.pref.put("marker.audiofromstart", audioMarkersFromStart.isSelected());
-		Main.pref.put("audio.forwardbackamount", audioForwardBackAmount.getText());		
-		Main.pref.put("audio.fastfwdmultiplier", audioFastForwardMultiplier.getText());		
-		Main.pref.put("audio.leadin", audioLeadIn.getText());		
-		Main.pref.put("audio.calibration", audioCalibration.getText());		
+        // audioMarkersFromNamedTrackpoints
+        audioMarkersFromNamedTrackpoints.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!audioMarkersFromNamedTrackpoints.isSelected())
+                    audioMarkersFromNamedTrackpoints.setSelected(false);
+            }
+        });
+        audioMarkersFromNamedTrackpoints.setSelected(Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false));
+        audioMarkersFromNamedTrackpoints.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
+        gui.audio.add(audioMarkersFromNamedTrackpoints, GBC.eol().insets(10,0,0,0));
+
+        // audioMarkersFromStart
+        audioMarkersFromStart.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (!audioMarkersFromStart.isSelected())
+                    audioMarkersFromStart.setSelected(false);
+            }
+        });
+        audioMarkersFromStart.setSelected(Main.pref.getBoolean("marker.audiofromstart"));
+        audioMarkersFromStart.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
+        gui.audio.add(audioMarkersFromStart, GBC.eol().insets(10,0,0,0));
+
+        audioForwardBackAmount.setText(Main.pref.get("audio.forwardbackamount", "10.0"));
+        audioForwardBackAmount.setToolTipText(tr("The number of seconds to jump forward or back when the relevant button is pressed"));
+        gui.audio.add(new JLabel(tr("Forward/back time (seconds)")), GBC.std());
+        gui.audio.add(audioForwardBackAmount, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        audioFastForwardMultiplier.setText(Main.pref.get("audio.fastfwdmultiplier", "1.3"));
+        audioFastForwardMultiplier.setToolTipText(tr("The amount by which the speed is multiplied for fast forwarding"));
+        gui.audio.add(new JLabel(tr("Fast forward multiplier")), GBC.std());
+        gui.audio.add(audioFastForwardMultiplier, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        audioLeadIn.setText(Main.pref.get("audio.leadin", "1"));
+        audioLeadIn.setToolTipText(tr("Playback starts this number of seconds before (or after, if negative) the audio track position requested"));
+        gui.audio.add(new JLabel(tr("Lead-in time (seconds)")), GBC.std());
+        gui.audio.add(audioLeadIn, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        audioCalibration.setText(Main.pref.get("audio.calibration", "1.0"));
+        audioCalibration.setToolTipText(tr("The ratio of voice recorder elapsed time to true elapsed time"));
+        gui.audio.add(new JLabel(tr("Voice recorder calibration")), GBC.std());
+        gui.audio.add(audioCalibration, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+        gui.audio.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+    }
+
+    public void ok() {
+        Main.pref.put("audio.menuinvisible", ! audioMenuVisible.isSelected());
+        Main.pref.put("marker.traceaudio", markerAudioTraceVisible.isSelected());
+        Main.pref.put("marker.buttonlabels", markerButtonLabels.isSelected());
+        Main.pref.put("marker.makeautomarkers", makeAutoMarkers.isSelected());
+        Main.pref.put("marker.audiofromexplicitwaypoints", audioMarkersFromExplicitWaypoints.isSelected());
+        Main.pref.put("marker.audiofromuntimedwaypoints", audioMarkersFromUntimedWaypoints.isSelected());
+        Main.pref.put("marker.audiofromnamedtrackpoints", audioMarkersFromNamedTrackpoints.isSelected());
+        Main.pref.put("marker.audiofromstart", audioMarkersFromStart.isSelected());
+        Main.pref.put("audio.forwardbackamount", audioForwardBackAmount.getText());
+        Main.pref.put("audio.fastfwdmultiplier", audioFastForwardMultiplier.getText());
+        Main.pref.put("audio.leadin", audioLeadIn.getText());
+        Main.pref.put("audio.calibration", audioCalibration.getText());
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ColorPreference.java	(revision 1169)
@@ -40,145 +40,145 @@
 public class ColorPreference implements PreferenceSetting {
 
-	private DefaultTableModel tableModel;
-	private JTable colors;
+    private DefaultTableModel tableModel;
+    private JTable colors;
 
-	/**
-	 * Set the colors to be shown in the preference table. This method creates a table model if
-	 * none exists and overwrites all existing values.
-	 * @param colorMap the map holding the colors 
-	 * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>), 
-	 * value = html representation of the color.
-	 */
-	public void setColorModel(Map<String, String> colorMap) {
-		if(tableModel == null) {
-			tableModel = new DefaultTableModel();
-			tableModel.addColumn(tr("Color"));
-			tableModel.addColumn(tr("Name"));
-		}
-		
-		// clear old model:
-		while(tableModel.getRowCount() > 0) {
-			tableModel.removeRow(0);
-		}
-		// fill model with colors:
-		List<String> colorKeyList = new ArrayList<String>();
-		for(String key : colorMap.keySet()) {
-			colorKeyList.add(key);
-		}
-		Collections.sort(colorKeyList);
-		for (String key : colorKeyList) {
-			Vector<Object> row = new Vector<Object>(2);
-			row.add(key);
-			row.add(ColorHelper.html2color(colorMap.get(key)));
-			tableModel.addRow(row);
-		}
-		if(this.colors != null) {
-			this.colors.repaint();
-		}		
-	}
-	
-	/**
-	 * Returns a map with the colors in the table (key = color name without prefix, value = html color code).
-	 * @return a map holding the colors.
-	 */
-	public Map<String, String> getColorModel() {
-		String key;
-		String value;
-		Map<String, String> colorMap = new HashMap<String, String>();
-		for(int row = 0; row < tableModel.getRowCount(); ++row) {
-			key = (String)tableModel.getValueAt(row, 0);
-			value = ColorHelper.color2html((Color)tableModel.getValueAt(row, 1));
-			colorMap.put(key, value);
-		}
-		return colorMap;
-	}
-	
-	public void addGui(final PreferenceDialog gui) {
-		// initial fill with colors from preferences:
-		Map<String,String> prefColorMap = new TreeMap<String, String>(Main.pref.getAllPrefix("color."));
-		fixColorPrefixes(prefColorMap);
-		Map<String,String> colorMap = new TreeMap<String, String>();
-		for(String key : prefColorMap.keySet()) {
-			colorMap.put(key.substring("color.".length()), prefColorMap.get(key));
-		}
-		setColorModel(colorMap);
-		
-		colors = new JTable(tableModel) {
-			@Override public boolean isCellEditable(int row, int column) {
-				return false;
-			}
-		};
-		colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		final TableCellRenderer oldColorsRenderer = colors.getDefaultRenderer(Object.class);
-		colors.setDefaultRenderer(Object.class, new TableCellRenderer(){
-			public Component getTableCellRendererComponent(JTable t, Object o, boolean selected, boolean focus, int row, int column) {
-				if (column == 1) {
-					JLabel l = new JLabel(ColorHelper.color2html((Color)o));
-					l.setBackground((Color)o);
-					l.setOpaque(true);
-					return l;
-				}
-				return oldColorsRenderer.getTableCellRendererComponent(t,tr(o.toString()),selected,focus,row,column);
-			}
-		});
-		colors.getColumnModel().getColumn(1).setWidth(100);
+    /**
+     * Set the colors to be shown in the preference table. This method creates a table model if
+     * none exists and overwrites all existing values.
+     * @param colorMap the map holding the colors
+     * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>),
+     * value = html representation of the color.
+     */
+    public void setColorModel(Map<String, String> colorMap) {
+        if(tableModel == null) {
+            tableModel = new DefaultTableModel();
+            tableModel.addColumn(tr("Color"));
+            tableModel.addColumn(tr("Name"));
+        }
 
-		JButton colorEdit = new JButton(tr("Choose"));
-		colorEdit.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (colors.getSelectedRowCount() == 0) {
-					JOptionPane.showMessageDialog(gui, tr("Please select a color."));
-					return;
-				}
-				int sel = colors.getSelectedRow();
-				JColorChooser chooser = new JColorChooser((Color)colors.getValueAt(sel, 1));
-				int answer = JOptionPane.showConfirmDialog(gui, chooser, tr("Choose a color for {0}", colors.getValueAt(sel, 0)), JOptionPane.OK_CANCEL_OPTION);
-				if (answer == JOptionPane.OK_OPTION)
-					colors.setValueAt(chooser.getColor(), sel, 1);
-			}
-		});
-		colors.setToolTipText(tr("Colors used by different objects in JOSM."));
-		colors.setPreferredScrollableViewportSize(new Dimension(100,112));
-
-		JPanel panel = new JPanel(new GridBagLayout());
-		panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-		JScrollPane scrollpane = new JScrollPane(colors);
-		scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-		panel.add(scrollpane, GBC.eol().fill(GBC.BOTH));
-		panel.add(colorEdit, GBC.eol().anchor(GBC.EAST));
-		gui.displaycontent.addTab(tr("Colors"), panel);
+        // clear old model:
+        while(tableModel.getRowCount() > 0) {
+            tableModel.removeRow(0);
+        }
+        // fill model with colors:
+        List<String> colorKeyList = new ArrayList<String>();
+        for(String key : colorMap.keySet()) {
+            colorKeyList.add(key);
+        }
+        Collections.sort(colorKeyList);
+        for (String key : colorKeyList) {
+            Vector<Object> row = new Vector<Object>(2);
+            row.add(key);
+            row.add(ColorHelper.html2color(colorMap.get(key)));
+            tableModel.addRow(row);
+        }
+        if(this.colors != null) {
+            this.colors.repaint();
+        }
     }
 
-	/**
-	 * Add all missing color entries.
-	 */
-	private void fixColorPrefixes(Map<String, String> prefColorMap) {
-		String[] cp = {
-			marktr("background"), ColorHelper.color2html(Color.black),
-			marktr("node"), ColorHelper.color2html(Color.red),
-			marktr("way"), ColorHelper.color2html(SimplePaintVisitor.darkblue),
-			marktr("incomplete way"), ColorHelper.color2html(SimplePaintVisitor.darkerblue),
-			marktr("relation"), ColorHelper.color2html(SimplePaintVisitor.teal),
-			marktr("selected"), ColorHelper.color2html(Color.white),
-			marktr("gps marker"), ColorHelper.color2html(Color.gray),
-			marktr("gps point"), ColorHelper.color2html(Color.gray),
-			marktr("conflict"), ColorHelper.color2html(Color.gray),
-			marktr("scale"), ColorHelper.color2html(Color.white),
-			marktr("inactive"), ColorHelper.color2html(Color.darkGray),
-		};
-		for (int i = 0; i < cp.length/2; ++i)
-		{
-			if (!Main.pref.hasKey("color."+cp[i*2]))
-				Main.pref.put("color."+cp[i*2], cp[i*2+1]);
-			Main.pref.putDefault("color."+cp[i*2], cp[i*2+1]);
-		}
+    /**
+     * Returns a map with the colors in the table (key = color name without prefix, value = html color code).
+     * @return a map holding the colors.
+     */
+    public Map<String, String> getColorModel() {
+        String key;
+        String value;
+        Map<String, String> colorMap = new HashMap<String, String>();
+        for(int row = 0; row < tableModel.getRowCount(); ++row) {
+            key = (String)tableModel.getValueAt(row, 0);
+            value = ColorHelper.color2html((Color)tableModel.getValueAt(row, 1));
+            colorMap.put(key, value);
+        }
+        return colorMap;
     }
 
-	public void ok() {
-		for (int i = 0; i < colors.getRowCount(); ++i) {
-			String name = (String)colors.getValueAt(i, 0);
-			Color col = (Color)colors.getValueAt(i, 1);
-			Main.pref.put("color." + name, ColorHelper.color2html(col));
-		}
+    public void addGui(final PreferenceDialog gui) {
+        // initial fill with colors from preferences:
+        Map<String,String> prefColorMap = new TreeMap<String, String>(Main.pref.getAllPrefix("color."));
+        fixColorPrefixes(prefColorMap);
+        Map<String,String> colorMap = new TreeMap<String, String>();
+        for(String key : prefColorMap.keySet()) {
+            colorMap.put(key.substring("color.".length()), prefColorMap.get(key));
+        }
+        setColorModel(colorMap);
+
+        colors = new JTable(tableModel) {
+            @Override public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        };
+        colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        final TableCellRenderer oldColorsRenderer = colors.getDefaultRenderer(Object.class);
+        colors.setDefaultRenderer(Object.class, new TableCellRenderer(){
+            public Component getTableCellRendererComponent(JTable t, Object o, boolean selected, boolean focus, int row, int column) {
+                if (column == 1) {
+                    JLabel l = new JLabel(ColorHelper.color2html((Color)o));
+                    l.setBackground((Color)o);
+                    l.setOpaque(true);
+                    return l;
+                }
+                return oldColorsRenderer.getTableCellRendererComponent(t,tr(o.toString()),selected,focus,row,column);
+            }
+        });
+        colors.getColumnModel().getColumn(1).setWidth(100);
+
+        JButton colorEdit = new JButton(tr("Choose"));
+        colorEdit.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                if (colors.getSelectedRowCount() == 0) {
+                    JOptionPane.showMessageDialog(gui, tr("Please select a color."));
+                    return;
+                }
+                int sel = colors.getSelectedRow();
+                JColorChooser chooser = new JColorChooser((Color)colors.getValueAt(sel, 1));
+                int answer = JOptionPane.showConfirmDialog(gui, chooser, tr("Choose a color for {0}", colors.getValueAt(sel, 0)), JOptionPane.OK_CANCEL_OPTION);
+                if (answer == JOptionPane.OK_OPTION)
+                    colors.setValueAt(chooser.getColor(), sel, 1);
+            }
+        });
+        colors.setToolTipText(tr("Colors used by different objects in JOSM."));
+        colors.setPreferredScrollableViewportSize(new Dimension(100,112));
+
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        JScrollPane scrollpane = new JScrollPane(colors);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        panel.add(scrollpane, GBC.eol().fill(GBC.BOTH));
+        panel.add(colorEdit, GBC.eol().anchor(GBC.EAST));
+        gui.displaycontent.addTab(tr("Colors"), panel);
+    }
+
+    /**
+     * Add all missing color entries.
+     */
+    private void fixColorPrefixes(Map<String, String> prefColorMap) {
+        String[] cp = {
+            marktr("background"), ColorHelper.color2html(Color.black),
+            marktr("node"), ColorHelper.color2html(Color.red),
+            marktr("way"), ColorHelper.color2html(SimplePaintVisitor.darkblue),
+            marktr("incomplete way"), ColorHelper.color2html(SimplePaintVisitor.darkerblue),
+            marktr("relation"), ColorHelper.color2html(SimplePaintVisitor.teal),
+            marktr("selected"), ColorHelper.color2html(Color.white),
+            marktr("gps marker"), ColorHelper.color2html(Color.gray),
+            marktr("gps point"), ColorHelper.color2html(Color.gray),
+            marktr("conflict"), ColorHelper.color2html(Color.gray),
+            marktr("scale"), ColorHelper.color2html(Color.white),
+            marktr("inactive"), ColorHelper.color2html(Color.darkGray),
+        };
+        for (int i = 0; i < cp.length/2; ++i)
+        {
+            if (!Main.pref.hasKey("color."+cp[i*2]))
+                Main.pref.put("color."+cp[i*2], cp[i*2+1]);
+            Main.pref.putDefault("color."+cp[i*2], cp[i*2+1]);
+        }
+    }
+
+    public void ok() {
+        for (int i = 0; i < colors.getRowCount(); ++i) {
+            String name = (String)colors.getValueAt(i, 0);
+            Color col = (Color)colors.getValueAt(i, 1);
+            Main.pref.put("color." + name, ColorHelper.color2html(col));
+        }
         org.openstreetmap.josm.gui.layer.OsmDataLayer.createHatchTexture();
     }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/DrawingPreference.java	(revision 1169)
@@ -22,28 +22,28 @@
 public class DrawingPreference implements PreferenceSetting {
 
-	private JCheckBox drawRawGpsLines = new JCheckBox(tr("Draw lines between raw gps points."));
-	private JTextField drawRawGpsMaxLineLength = new JTextField(8);
-	private JCheckBox forceRawGpsLines = new JCheckBox(tr("Force lines if no segments imported."));
-	private JCheckBox largeGpsPoints = new JCheckBox(tr("Draw large GPS points."));
-	private JCheckBox colorTracks = new JCheckBox(tr("Color tracks by velocity."));
-	private JCheckBox directionHint = new JCheckBox(tr("Draw Direction Arrows"));
-	private JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows"));
-	private JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)"));
-	private JTextField drawGpsArrowsMinDist = new JTextField(8);
-	private JCheckBox interestingDirections = new JCheckBox(tr("Only interesting direction hints (e.g. with oneway tag)."));
-	private JCheckBox segmentOrderNumber = new JCheckBox(tr("Draw segment order numbers"));
-	private JCheckBox sourceBounds = new JCheckBox(tr("Draw boundaries of downloaded data"));
-	private JCheckBox virtualNodes = new JCheckBox(tr("Draw virtual nodes in select mode"));
-	private JCheckBox inactive = new JCheckBox(tr("Draw inactive layers in other color"));
-	private JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
+    private JCheckBox drawRawGpsLines = new JCheckBox(tr("Draw lines between raw gps points."));
+    private JTextField drawRawGpsMaxLineLength = new JTextField(8);
+    private JCheckBox forceRawGpsLines = new JCheckBox(tr("Force lines if no segments imported."));
+    private JCheckBox largeGpsPoints = new JCheckBox(tr("Draw large GPS points."));
+    private JCheckBox colorTracks = new JCheckBox(tr("Color tracks by velocity."));
+    private JCheckBox directionHint = new JCheckBox(tr("Draw Direction Arrows"));
+    private JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows"));
+    private JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)"));
+    private JTextField drawGpsArrowsMinDist = new JTextField(8);
+    private JCheckBox interestingDirections = new JCheckBox(tr("Only interesting direction hints (e.g. with oneway tag)."));
+    private JCheckBox segmentOrderNumber = new JCheckBox(tr("Draw segment order numbers"));
+    private JCheckBox sourceBounds = new JCheckBox(tr("Draw boundaries of downloaded data"));
+    private JCheckBox virtualNodes = new JCheckBox(tr("Draw virtual nodes in select mode"));
+    private JCheckBox inactive = new JCheckBox(tr("Draw inactive layers in other color"));
+    private JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
 
-	public void addGui(PreferenceDialog gui) {
-	    gui.display.setPreferredSize(new Dimension(400,600));
+    public void addGui(PreferenceDialog gui) {
+        gui.display.setPreferredSize(new Dimension(400,600));
         JPanel panel = new JPanel(new GridBagLayout());
         panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
 
-	    // drawRawGpsLines
-		drawRawGpsLines.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
+        // drawRawGpsLines
+        drawRawGpsLines.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
                             forceRawGpsLines.setEnabled(drawRawGpsLines.isSelected());
                             drawRawGpsMaxLineLength.setEnabled(drawRawGpsLines.isSelected());
@@ -52,69 +52,69 @@
                             drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
                             colorTracks.setEnabled(drawRawGpsLines.isSelected());
-			}
-		});
-		drawRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines"));
-		drawRawGpsLines.setToolTipText(tr("If your gps device draw too few lines, select this to draw lines along your way."));
-		panel.add(drawRawGpsLines, GBC.eol().insets(20,0,0,0));
+            }
+        });
+        drawRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines"));
+        drawRawGpsLines.setToolTipText(tr("If your gps device draw too few lines, select this to draw lines along your way."));
+        panel.add(drawRawGpsLines, GBC.eol().insets(20,0,0,0));
 
-		// drawRawGpsMaxLineLength
-		drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length", -1)));
-		drawRawGpsMaxLineLength.setToolTipText(tr("Maximum length (in meters) to draw lines. Set to '-1' to draw all lines."));
-		drawRawGpsMaxLineLength.setEnabled(drawRawGpsLines.isSelected());
-		panel.add(new JLabel(tr("Maximum length (meters)")), GBC.std().insets(40,0,0,0));
-		panel.add(drawRawGpsMaxLineLength, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        // drawRawGpsMaxLineLength
+        drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length", -1)));
+        drawRawGpsMaxLineLength.setToolTipText(tr("Maximum length (in meters) to draw lines. Set to '-1' to draw all lines."));
+        drawRawGpsMaxLineLength.setEnabled(drawRawGpsLines.isSelected());
+        panel.add(new JLabel(tr("Maximum length (meters)")), GBC.std().insets(40,0,0,0));
+        panel.add(drawRawGpsMaxLineLength, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
-		// forceRawGpsLines
-		forceRawGpsLines.setToolTipText(tr("Force drawing of lines if the imported data contain no line information."));
-		forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force"));
-		forceRawGpsLines.setEnabled(drawRawGpsLines.isSelected());
-		panel.add(forceRawGpsLines, GBC.eop().insets(40,0,0,0));
-		
-		// drawGpsArrows
-		drawGpsArrows.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
+        // forceRawGpsLines
+        forceRawGpsLines.setToolTipText(tr("Force drawing of lines if the imported data contain no line information."));
+        forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force"));
+        forceRawGpsLines.setEnabled(drawRawGpsLines.isSelected());
+        panel.add(forceRawGpsLines, GBC.eop().insets(40,0,0,0));
+
+        // drawGpsArrows
+        drawGpsArrows.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
                             drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
                             drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-			}
-		});
-		drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points."));
-		drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction"));
-		drawGpsArrows.setEnabled(drawRawGpsLines.isSelected());
-		panel.add(drawGpsArrows, GBC.eop().insets(40,0,0,0));
+            }
+        });
+        drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points."));
+        drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction"));
+        drawGpsArrows.setEnabled(drawRawGpsLines.isSelected());
+        panel.add(drawGpsArrows, GBC.eop().insets(40,0,0,0));
 
-		// drawGpsArrowsFast
-		drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math."));
-		drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection"));
-		drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-		panel.add(drawGpsArrowsFast, GBC.eop().insets(60,0,0,0));
+        // drawGpsArrowsFast
+        drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math."));
+        drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection"));
+        drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+        panel.add(drawGpsArrowsFast, GBC.eop().insets(60,0,0,0));
 
-		// drawGpsArrowsMinDist
-		drawGpsArrowsMinDist.setToolTipText(tr("Don't draw arrows if they are not at least this distance away from the last one."));
-		drawGpsArrowsMinDist.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.min-arrow-distance", 0)));
-		drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
-		panel.add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(60,0,0,0));
-		panel.add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        // drawGpsArrowsMinDist
+        drawGpsArrowsMinDist.setToolTipText(tr("Don't draw arrows if they are not at least this distance away from the last one."));
+        drawGpsArrowsMinDist.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.min-arrow-distance", 0)));
+        drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
+        panel.add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(60,0,0,0));
+        panel.add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
-		// colorTracks
-		colorTracks.setSelected(Main.pref.getBoolean("draw.rawgps.colors"));
-		colorTracks.setToolTipText(tr("Choose the hue for the track color by the velocity at that point."));
-		colorTracks.setEnabled(drawRawGpsLines.isSelected());
-		panel.add(colorTracks, GBC.eop().insets(40,0,0,0));
-		
-		// largeGpsPoints
-		largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large"));
-		largeGpsPoints.setToolTipText(tr("Draw larger dots for the GPS points."));
-		panel.add(largeGpsPoints, GBC.eop().insets(20,0,0,0));
-		
-		panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-		JScrollPane scrollpane = new JScrollPane(panel);
-		scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-		gui.displaycontent.addTab(tr("GPS Points"), scrollpane);
-		panel = new JPanel(new GridBagLayout());
-		panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        // colorTracks
+        colorTracks.setSelected(Main.pref.getBoolean("draw.rawgps.colors"));
+        colorTracks.setToolTipText(tr("Choose the hue for the track color by the velocity at that point."));
+        colorTracks.setEnabled(drawRawGpsLines.isSelected());
+        panel.add(colorTracks, GBC.eop().insets(40,0,0,0));
 
-		// directionHint
-		directionHint.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
+        // largeGpsPoints
+        largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large"));
+        largeGpsPoints.setToolTipText(tr("Draw larger dots for the GPS points."));
+        panel.add(largeGpsPoints, GBC.eop().insets(20,0,0,0));
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+        JScrollPane scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.displaycontent.addTab(tr("GPS Points"), scrollpane);
+        panel = new JPanel(new GridBagLayout());
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        // directionHint
+        directionHint.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
                             if (directionHint.isSelected()){
                                 interestingDirections.setSelected(Main.pref.getBoolean("draw.segment.relevant_directions_only"));
@@ -123,66 +123,66 @@
                             }
                             interestingDirections.setEnabled(directionHint.isSelected());
-			}
-		});
-		directionHint.setToolTipText(tr("Draw direction hints for way segments."));
-		directionHint.setSelected(Main.pref.getBoolean("draw.segment.direction"));
-		panel.add(directionHint, GBC.eop().insets(20,0,0,0));
+            }
+        });
+        directionHint.setToolTipText(tr("Draw direction hints for way segments."));
+        directionHint.setSelected(Main.pref.getBoolean("draw.segment.direction"));
+        panel.add(directionHint, GBC.eop().insets(20,0,0,0));
 
-		// only interesting directions
-		interestingDirections.setToolTipText(tr("Only interesting direction hints (e.g. with oneway tag)."));
-		interestingDirections.setSelected(Main.pref.getBoolean("draw.segment.relevant_directions_only"));
-		interestingDirections.setEnabled(directionHint.isSelected());
-		panel.add(interestingDirections, GBC.eop().insets(40,0,0,0));
-		
-		// segment order number
-		segmentOrderNumber.setToolTipText(tr("Draw the order numbers of all segments within their way."));
-		segmentOrderNumber.setSelected(Main.pref.getBoolean("draw.segment.order_number"));
-		panel.add(segmentOrderNumber, GBC.eop().insets(20,0,0,0));
-		
-		// antialiasing
-		useAntialiasing.setToolTipText(tr("Apply antialiasing to the map view resulting in a smoother appearance."));
-		useAntialiasing.setSelected(Main.pref.getBoolean("mappaint.use-antialiasing"));
-		panel.add(useAntialiasing, GBC.eop().insets(20,0,0,0));
-		
-		// downloaded area
-		sourceBounds.setToolTipText(tr("Draw the boundaries of data loaded from the server."));
-		sourceBounds.setSelected(Main.pref.getBoolean("draw.data.downloaded_area", true));
-		panel.add(sourceBounds, GBC.eop().insets(20,0,0,0));
+        // only interesting directions
+        interestingDirections.setToolTipText(tr("Only interesting direction hints (e.g. with oneway tag)."));
+        interestingDirections.setSelected(Main.pref.getBoolean("draw.segment.relevant_directions_only"));
+        interestingDirections.setEnabled(directionHint.isSelected());
+        panel.add(interestingDirections, GBC.eop().insets(40,0,0,0));
 
-		// virtual nodes
-		virtualNodes.setToolTipText(tr("Draw virtual nodes in select mode for easy way modification."));
-		virtualNodes.setSelected(Main.pref.getInteger("mappaint.node.virtual-size", 8) != 0);
-		panel.add(virtualNodes, GBC.eop().insets(20,0,0,0));
+        // segment order number
+        segmentOrderNumber.setToolTipText(tr("Draw the order numbers of all segments within their way."));
+        segmentOrderNumber.setSelected(Main.pref.getBoolean("draw.segment.order_number"));
+        panel.add(segmentOrderNumber, GBC.eop().insets(20,0,0,0));
 
-		// background layers in inactive color
-		inactive.setToolTipText(tr("Draw the inactive data layers in a different color."));
-		inactive.setSelected(Main.pref.getBoolean("draw.data.inactive_color", true));
-		panel.add(inactive, GBC.eop().insets(20,0,0,0));
+        // antialiasing
+        useAntialiasing.setToolTipText(tr("Apply antialiasing to the map view resulting in a smoother appearance."));
+        useAntialiasing.setSelected(Main.pref.getBoolean("mappaint.use-antialiasing"));
+        panel.add(useAntialiasing, GBC.eop().insets(20,0,0,0));
 
- 		panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
- 		scrollpane = new JScrollPane(panel);
- 		scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
- 		gui.displaycontent.addTab(tr("OSM Data"), scrollpane);
-	}
+        // downloaded area
+        sourceBounds.setToolTipText(tr("Draw the boundaries of data loaded from the server."));
+        sourceBounds.setSelected(Main.pref.getBoolean("draw.data.downloaded_area", true));
+        panel.add(sourceBounds, GBC.eop().insets(20,0,0,0));
 
-	public void ok() {
-		Main.pref.put("draw.rawgps.lines", drawRawGpsLines.isSelected());
-		Main.pref.put("draw.rawgps.max-line-length", drawRawGpsMaxLineLength.getText());
-		Main.pref.put("draw.rawgps.lines.force", forceRawGpsLines.isSelected());
-		Main.pref.put("draw.rawgps.direction", drawGpsArrows.isSelected());
-		Main.pref.put("draw.rawgps.alternatedirection", drawGpsArrowsFast.isSelected());
-		Main.pref.put("draw.rawgps.min-arrow-distance", drawGpsArrowsMinDist.getText());
-		Main.pref.put("draw.rawgps.colors", colorTracks.isSelected());
-		Main.pref.put("draw.rawgps.large", largeGpsPoints.isSelected());
-		Main.pref.put("draw.segment.direction", directionHint.isSelected());
-		Main.pref.put("draw.segment.relevant_directions_only", interestingDirections.isSelected());
-		Main.pref.put("draw.segment.order_number", segmentOrderNumber.isSelected());
-		Main.pref.put("draw.data.downloaded_area", sourceBounds.isSelected());
-		Main.pref.put("draw.data.inactive_color", inactive.isSelected());
-		Main.pref.put("mappaint.use-antialiasing", useAntialiasing.isSelected());
-		int vn = Main.pref.getInteger("mappaint.node.virtual-size", 8);
-		if(virtualNodes.isSelected()) {	if (vn < 1) vn = 8; }
-		else { vn = 0; }
-		Main.pref.put("mappaint.node.virtual-size", Integer.toString(vn));
-	}
+        // virtual nodes
+        virtualNodes.setToolTipText(tr("Draw virtual nodes in select mode for easy way modification."));
+        virtualNodes.setSelected(Main.pref.getInteger("mappaint.node.virtual-size", 8) != 0);
+        panel.add(virtualNodes, GBC.eop().insets(20,0,0,0));
+
+        // background layers in inactive color
+        inactive.setToolTipText(tr("Draw the inactive data layers in a different color."));
+        inactive.setSelected(Main.pref.getBoolean("draw.data.inactive_color", true));
+        panel.add(inactive, GBC.eop().insets(20,0,0,0));
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+        scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.displaycontent.addTab(tr("OSM Data"), scrollpane);
+    }
+
+    public void ok() {
+        Main.pref.put("draw.rawgps.lines", drawRawGpsLines.isSelected());
+        Main.pref.put("draw.rawgps.max-line-length", drawRawGpsMaxLineLength.getText());
+        Main.pref.put("draw.rawgps.lines.force", forceRawGpsLines.isSelected());
+        Main.pref.put("draw.rawgps.direction", drawGpsArrows.isSelected());
+        Main.pref.put("draw.rawgps.alternatedirection", drawGpsArrowsFast.isSelected());
+        Main.pref.put("draw.rawgps.min-arrow-distance", drawGpsArrowsMinDist.getText());
+        Main.pref.put("draw.rawgps.colors", colorTracks.isSelected());
+        Main.pref.put("draw.rawgps.large", largeGpsPoints.isSelected());
+        Main.pref.put("draw.segment.direction", directionHint.isSelected());
+        Main.pref.put("draw.segment.relevant_directions_only", interestingDirections.isSelected());
+        Main.pref.put("draw.segment.order_number", segmentOrderNumber.isSelected());
+        Main.pref.put("draw.data.downloaded_area", sourceBounds.isSelected());
+        Main.pref.put("draw.data.inactive_color", inactive.isSelected());
+        Main.pref.put("mappaint.use-antialiasing", useAntialiasing.isSelected());
+        int vn = Main.pref.getInteger("mappaint.node.virtual-size", 8);
+        if(virtualNodes.isSelected()) { if (vn < 1) vn = 8; }
+        else { vn = 0; }
+        Main.pref.put("mappaint.node.virtual-size", Integer.toString(vn));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/FilePreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/FilePreferences.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/FilePreferences.java	(revision 1169)
@@ -14,20 +14,20 @@
  * Out of pure laziness, I add the file stuff to connection tab.
  * Feel free to fix this.
- * 
+ *
  * @author imi
  */
 public class FilePreferences implements PreferenceSetting {
 
-	private JCheckBox keepBackup = new JCheckBox(tr("Keep backup files"));
-	
-	public void addGui(PreferenceDialog gui) {
-		gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-		keepBackup.setSelected(Main.pref.getBoolean("save.keepbackup"));
-		keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
-		gui.connection.add(keepBackup, GBC.eol().insets(20,0,0,0));
+    private JCheckBox keepBackup = new JCheckBox(tr("Keep backup files"));
+
+    public void addGui(PreferenceDialog gui) {
+        gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+        keepBackup.setSelected(Main.pref.getBoolean("save.keepbackup"));
+        keepBackup.setToolTipText(tr("When saving, keep backup files ending with a ~"));
+        gui.connection.add(keepBackup, GBC.eol().insets(20,0,0,0));
     }
 
-	public void ok() {
-		Main.pref.put("save.keepbackup", keepBackup.isSelected());
+    public void ok() {
+        Main.pref.put("save.keepbackup", keepBackup.isSelected());
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/LafPreference.java	(revision 1169)
@@ -25,71 +25,71 @@
 public class LafPreference implements PreferenceSetting {
 
-	/**
-	 * ComboBox with all look and feels.
-	 */
-	private JComboBox lafCombo;
-	public JPanel panel = new JPanel(new GridBagLayout());
-	private JCheckBox showSplashScreen = new JCheckBox(tr("Show splash screen at startup"));
-	private JCheckBox showID = new JCheckBox(tr("Show object ID in selection lists"));
+    /**
+     * ComboBox with all look and feels.
+     */
+    private JComboBox lafCombo;
+    public JPanel panel = new JPanel(new GridBagLayout());
+    private JCheckBox showSplashScreen = new JCheckBox(tr("Show splash screen at startup"));
+    private JCheckBox showID = new JCheckBox(tr("Show object ID in selection lists"));
 
-	public void addGui(PreferenceDialog gui) {
-		lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
+    public void addGui(PreferenceDialog gui) {
+        lafCombo = new JComboBox(UIManager.getInstalledLookAndFeels());
 
-		// let's try to load additional LookAndFeels and put them into the list
-		try {
-			Class<?> Cquaqua = Class.forName("ch.randelshofer.quaqua.QuaquaLookAndFeel");
-			Object Oquaqua = Cquaqua.getConstructor((Class[])null).newInstance((Object[])null);
-			// no exception? Then Go!
-			lafCombo.addItem(
-				new UIManager.LookAndFeelInfo(((javax.swing.LookAndFeel)Oquaqua).getName(), "ch.randelshofer.quaqua.QuaquaLookAndFeel")
-			);
-		} catch (Exception ex) {
-			// just ignore, Quaqua may not even be installed...
-			//System.out.println("Failed to load Quaqua: " + ex);
-		}
+        // let's try to load additional LookAndFeels and put them into the list
+        try {
+            Class<?> Cquaqua = Class.forName("ch.randelshofer.quaqua.QuaquaLookAndFeel");
+            Object Oquaqua = Cquaqua.getConstructor((Class[])null).newInstance((Object[])null);
+            // no exception? Then Go!
+            lafCombo.addItem(
+                new UIManager.LookAndFeelInfo(((javax.swing.LookAndFeel)Oquaqua).getName(), "ch.randelshofer.quaqua.QuaquaLookAndFeel")
+            );
+        } catch (Exception ex) {
+            // just ignore, Quaqua may not even be installed...
+            //System.out.println("Failed to load Quaqua: " + ex);
+        }
 
-		String laf = Main.pref.get("laf");
-		for (int i = 0; i < lafCombo.getItemCount(); ++i) {
-			if (((LookAndFeelInfo)lafCombo.getItemAt(i)).getClassName().equals(laf)) {
-				lafCombo.setSelectedIndex(i);
-				break;
-			}
-		}
+        String laf = Main.pref.get("laf");
+        for (int i = 0; i < lafCombo.getItemCount(); ++i) {
+            if (((LookAndFeelInfo)lafCombo.getItemAt(i)).getClassName().equals(laf)) {
+                lafCombo.setSelectedIndex(i);
+                break;
+            }
+        }
 
-		final ListCellRenderer oldRenderer = lafCombo.getRenderer();
-		lafCombo.setRenderer(new DefaultListCellRenderer(){
-			@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-				return oldRenderer.getListCellRendererComponent(list, ((LookAndFeelInfo)value).getName(), index, isSelected, cellHasFocus);
-			}
-		});
-		lafCombo.addActionListener(gui.requireRestartAction);
+        final ListCellRenderer oldRenderer = lafCombo.getRenderer();
+        lafCombo.setRenderer(new DefaultListCellRenderer(){
+            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                return oldRenderer.getListCellRendererComponent(list, ((LookAndFeelInfo)value).getName(), index, isSelected, cellHasFocus);
+            }
+        });
+        lafCombo.addActionListener(gui.requireRestartAction);
 
-		panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
 
-		// Show splash screen on startup
-		showSplashScreen.setToolTipText(tr("Show splash screen at startup"));
-		showSplashScreen.setSelected(Main.pref.getBoolean("draw.splashscreen", true));
-		panel.add(showSplashScreen, GBC.eop().insets(20, 0, 0, 0));
+        // Show splash screen on startup
+        showSplashScreen.setToolTipText(tr("Show splash screen at startup"));
+        showSplashScreen.setSelected(Main.pref.getBoolean("draw.splashscreen", true));
+        panel.add(showSplashScreen, GBC.eop().insets(20, 0, 0, 0));
 
-		// Show ID in selection
-		showID.setToolTipText(tr("Show object ID in selection lists"));
-		showID.setSelected(Main.pref.getBoolean("osm-primitives.showid", false));
-		panel.add(showID, GBC.eop().insets(20, 0, 0, 0));
+        // Show ID in selection
+        showID.setToolTipText(tr("Show object ID in selection lists"));
+        showID.setSelected(Main.pref.getBoolean("osm-primitives.showid", false));
+        panel.add(showID, GBC.eop().insets(20, 0, 0, 0));
 
-		panel.add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
+        panel.add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
 
-		panel.add(new JLabel(tr("Look and Feel")), GBC.std().insets(20, 0, 0, 0));
-		panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-		panel.add(lafCombo, GBC.eol().fill(GBC.HORIZONTAL));
+        panel.add(new JLabel(tr("Look and Feel")), GBC.std().insets(20, 0, 0, 0));
+        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        panel.add(lafCombo, GBC.eol().fill(GBC.HORIZONTAL));
 
-		JScrollPane scrollpane = new JScrollPane(panel);
-		scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
-		gui.displaycontent.addTab(tr("Look and Feel"), scrollpane);
-	}
+        JScrollPane scrollpane = new JScrollPane(panel);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
+        gui.displaycontent.addTab(tr("Look and Feel"), scrollpane);
+    }
 
-	public void ok() {
-		Main.pref.put("laf", ((LookAndFeelInfo)lafCombo.getSelectedItem()).getClassName());
-		Main.pref.put("draw.splashscreen", showSplashScreen.isSelected());
-		Main.pref.put("osm-primitives.showid", showID.isSelected());
+    public void ok() {
+        Main.pref.put("laf", ((LookAndFeelInfo)lafCombo.getSelectedItem()).getClassName());
+        Main.pref.put("draw.splashscreen", showSplashScreen.isSelected());
+        Main.pref.put("osm-primitives.showid", showID.isSelected());
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 1169)
@@ -20,61 +20,61 @@
 
 public class LanguagePreference implements PreferenceSetting {
-	/**
-	 * ComboBox with all available Translations
-	 */
-	private JComboBox langCombo;
-	private final Locale AUTO_LANGUAGE = null;
+    /**
+     * ComboBox with all available Translations
+     */
+    private JComboBox langCombo;
+    private final Locale AUTO_LANGUAGE = null;
 
-	public void addGui(PreferenceDialog gui) {
-		langCombo = new JComboBox(I18n.getAvailableTranslations());
-		langCombo.insertItemAt(AUTO_LANGUAGE, 0); // Default
-		langCombo.insertItemAt(Locale.ENGLISH, 1); // Built-in language
-		String ln = Main.pref.get("language");
-		langCombo.setSelectedIndex(0);
-		
-		if (ln != null) {
-			for (int i = 1; i < langCombo.getItemCount(); ++i) {
-				if (((Locale) langCombo.getItemAt(i)).toString().equals(ln)) {
-					langCombo.setSelectedIndex(i);
-					break;
-				}
-			}
-		}
+    public void addGui(PreferenceDialog gui) {
+        langCombo = new JComboBox(I18n.getAvailableTranslations());
+        langCombo.insertItemAt(AUTO_LANGUAGE, 0); // Default
+        langCombo.insertItemAt(Locale.ENGLISH, 1); // Built-in language
+        String ln = Main.pref.get("language");
+        langCombo.setSelectedIndex(0);
 
-		final ListCellRenderer oldRenderer = langCombo.getRenderer();
-		langCombo.setRenderer(new DefaultListCellRenderer() {
-			@Override
-			public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
-					boolean cellHasFocus) {
-				Locale l = (Locale) value;
-				return oldRenderer.getListCellRendererComponent(list,
-						l == AUTO_LANGUAGE ? tr("Default (Auto determined)") : l.getDisplayName(),
-						index, isSelected, cellHasFocus);
-			}
-		});
-		langCombo.addActionListener(gui.requireRestartAction);
+        if (ln != null) {
+            for (int i = 1; i < langCombo.getItemCount(); ++i) {
+                if (((Locale) langCombo.getItemAt(i)).toString().equals(ln)) {
+                    langCombo.setSelectedIndex(i);
+                    break;
+                }
+            }
+        }
 
-		JPanel panel = null;
-		for(PreferenceSetting s : gui.settings)
-		{
-			if(s instanceof LafPreference)
-				panel = ((LafPreference)s).panel;
-		}
-		panel.add(new JLabel(tr("Language")), GBC.std().insets(20, 0, 0, 0));
-		panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-		panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
-		panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-	}
+        final ListCellRenderer oldRenderer = langCombo.getRenderer();
+        langCombo.setRenderer(new DefaultListCellRenderer() {
+            @Override
+            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+                    boolean cellHasFocus) {
+                Locale l = (Locale) value;
+                return oldRenderer.getListCellRendererComponent(list,
+                        l == AUTO_LANGUAGE ? tr("Default (Auto determined)") : l.getDisplayName(),
+                        index, isSelected, cellHasFocus);
+            }
+        });
+        langCombo.addActionListener(gui.requireRestartAction);
 
-	public void ok() {
-		if(langCombo.getSelectedItem() == null)
-		{
-			Main.pref.put("language", null);
-		}
-		else
-		{
-			String l = ((Locale)langCombo.getSelectedItem()).toString();
-			Main.pref.put("language", l);
-		}
-	}
+        JPanel panel = null;
+        for(PreferenceSetting s : gui.settings)
+        {
+            if(s instanceof LafPreference)
+                panel = ((LafPreference)s).panel;
+        }
+        panel.add(new JLabel(tr("Language")), GBC.std().insets(20, 0, 0, 0));
+        panel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+    }
+
+    public void ok() {
+        if(langCombo.getSelectedItem() == null)
+        {
+            Main.pref.put("language", null);
+        }
+        else
+        {
+            String l = ((Locale)langCombo.getSelectedItem()).toString();
+            Main.pref.put("language", l);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java	(revision 1169)
@@ -5,18 +5,18 @@
 
 public class MapPaintPreference implements PreferenceSetting {
-	
-	public void addGui(final PreferenceDialog gui) {
-		// this is intended for a future configuration panel for mappaint!
-	}
 
-	public void ok() {
-		// dummy
-	}
+    public void addGui(final PreferenceDialog gui) {
+        // this is intended for a future configuration panel for mappaint!
+    }
 
-	/** 
-	 * Initialize the styles
-	 */
-	public static void initialize() {
-		MapPaintStyles.readFromPreferences();
-	}
+    public void ok() {
+        // dummy
+    }
+
+    /**
+     * Initialize the styles
+     */
+    public static void initialize() {
+        MapPaintStyles.readFromPreferences();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 1169)
@@ -49,231 +49,231 @@
 public class PluginPreference implements PreferenceSetting {
 
-	/**
-	 * Only the plugin name, its jar location and the description.
-	 * In other words, this is the minimal requirement the plugin preference page
-	 * needs to show the plugin as available
-	 * 
-	 * @author imi
-	 */
-	public static class PluginDescription implements Comparable<Object> {
-		// Note: All the following need to be public instance variables of
-		// type String.  (Plugin description XMLs from the server are parsed
-		// with tools.XmlObjectParser, which uses reflection to access them.)
-		public String name;
-		public String description;
-		public String resource;
-		public String version;
-		public PluginDescription(String name, String description, String resource, String version) {
-			this.name = name;
-			this.description = description;
-			this.resource = resource;
-			this.version = version;
-		}
-		public PluginDescription() {
-		}
-		public int compareTo(Object n) {
-			if(n instanceof PluginDescription)
-				return name.compareToIgnoreCase(((PluginDescription)n).name);
-			return -1;
-		}
-	}
-
-	private Map<PluginDescription, Boolean> pluginMap;
-	private JPanel plugin;
-	private class MyBox extends Box {
-		int lastwidth;
-		int offset = 40;
-		public MyBox()
-		{
-			super(BoxLayout.Y_AXIS);
-		}
-		public int myGetWidth()
-		{
-			int w = plugin.getWidth()-offset;
-			if(w <= 0) w = 450;
-			lastwidth = w;
-			return w;
-		}
-		public void paint(Graphics g)
-		{
-			if(lastwidth != plugin.getWidth()-offset)
-				refreshPluginPanel(gui);
-			super.paint(g);
-		}
-	}
-	private MyBox pluginPanel = new MyBox();
-	private PreferenceDialog gui;
-
-	public void addGui(final PreferenceDialog gui) {
-		this.gui = gui;
-		plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
-		JScrollPane pluginPane = new JScrollPane(pluginPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-		pluginPane.setBorder(null);
-		plugin.add(pluginPane, GBC.eol().fill(GBC.BOTH));
-		plugin.add(GBC.glue(0,10), GBC.eol());
-		JButton morePlugins = new JButton(tr("Download List"));
-		morePlugins.addActionListener(new ActionListener(){
-		    public void actionPerformed(ActionEvent e) {
-		        int count = PluginDownloader.downloadDescription();
-		        if (count > 0)
-		            JOptionPane.showMessageDialog(Main.parent,
-		                trn("Downloaded plugin information from {0} site",
-		                    "Downloaded plugin information from {0} sites", count, count));
-		        else
-		            JOptionPane.showMessageDialog(Main.parent, tr("No plugin information found."));
-		        refreshPluginPanel(gui);
-			}
-		});
-		plugin.add(morePlugins, GBC.std().insets(0,0,10,0));
-
-		JButton update = new JButton(tr("Update"));
-		update.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				update();
-				refreshPluginPanel(gui);
-			}
-		});
-		plugin.add(update, GBC.std().insets(0,0,10,0));
-
-		JButton configureSites = new JButton(tr("Configure Sites ..."));
-		configureSites.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				configureSites();
-			}
-		});
-		plugin.add(configureSites, GBC.std());
-
-		refreshPluginPanel(gui);
-	}
-
-	private void configureSites() {
-		JPanel p = new JPanel(new GridBagLayout());
-		p.add(new JLabel(tr("Add either site-josm.xml or Wiki Pages.")), GBC.eol());
-		final DefaultListModel model = new DefaultListModel();
-		for (String s : PluginDownloader.getSites())
-			model.addElement(s);
-		final JList list = new JList(model);
-		p.add(new JScrollPane(list), GBC.std().fill());
-		JPanel buttons = new JPanel(new GridBagLayout());
-		buttons.add(new JButton(new AbstractAction(tr("Add")){
-			public void actionPerformed(ActionEvent e) {
-				String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."));
-				if (s != null)
-					model.addElement(s);
-            }
-		}), GBC.eol().fill(GBC.HORIZONTAL));
-		buttons.add(new JButton(new AbstractAction(tr("Edit")){
-			public void actionPerformed(ActionEvent e) {
-				if (list.getSelectedValue() == null) {
-					JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
-					return;
-				}
-				String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."), list.getSelectedValue());
-				model.setElementAt(s, list.getSelectedIndex());
-            }
-		}), GBC.eol().fill(GBC.HORIZONTAL));
-		buttons.add(new JButton(new AbstractAction(tr("Delete")){
-			public void actionPerformed(ActionEvent event) {
-				if (list.getSelectedValue() == null) {
-					JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
-					return;
-				}
-				model.removeElement(list.getSelectedValue());
-            }
-		}), GBC.eol().fill(GBC.HORIZONTAL));
-		p.add(buttons, GBC.eol());
-		int answer = JOptionPane.showConfirmDialog(gui, p, tr("Configure Plugin Sites"), JOptionPane.OK_CANCEL_OPTION);
-		if (answer != JOptionPane.OK_OPTION)
-			return;
-		StringBuilder b = new StringBuilder();
-		for (int i = 0; i < model.getSize(); ++i) {
-			b.append(model.getElementAt(i));
-			if (i < model.getSize()-1)
-				b.append(" ");
-		}
-		Main.pref.put("pluginmanager.sites", b.toString());
-	}
-
-	private void update() {
-		// refresh description
-		int num = PluginDownloader.downloadDescription();
-		Boolean done = false;
-		refreshPluginPanel(gui);
-
-		Set<PluginDescription> toUpdate = new HashSet<PluginDescription>();
-		StringBuilder toUpdateStr = new StringBuilder();
-		for (PluginProxy proxy : Main.plugins) {
-			PluginDescription description = findDescription(proxy.info.name);
-			if (description != null && (description.version == null || description.version.equals(""))
-			? (proxy.info.version != null && proxy.info.version.equals("")) : !description.version.equals(proxy.info.version)) {
-				toUpdate.add(description);
-				toUpdateStr.append(description.name+"\n");
-			}
-		}
-		if (toUpdate.isEmpty()) {
-			JOptionPane.showMessageDialog(Main.parent, tr("All installed plugins are up to date."));
-			done = true;
-		}
-		else
-		{
-			int answer = JOptionPane.showConfirmDialog(Main.parent, tr("Update the following plugins:\n\n{0}",
-			toUpdateStr.toString()), tr("Update"), JOptionPane.OK_CANCEL_OPTION);
-			if (answer == JOptionPane.OK_OPTION)
-			{
-				PluginDownloader.update(toUpdate);
-				done = true;
-			}
-		}
-		if(done && num >= 1)
-			Main.pref.put("pluginmanager.lastupdate", Long.toString(System.currentTimeMillis()));
-	}
-
-	private PluginDescription findDescription(String name) {
-		for (PluginDescription d : pluginMap.keySet())
-			if (d.name.equals(name))
-				return d;
-		return null;
-	}
-
-	private void refreshPluginPanel(final PreferenceDialog gui) {
-		Collection<PluginDescription> availablePlugins = getAvailablePlugins();
-		pluginMap = new HashMap<PluginDescription, Boolean>();
-		pluginPanel.removeAll();
-		int width = pluginPanel.myGetWidth();
-
-		Collection<String> enabledPlugins = Main.pref.getCollection("plugins", null);
-		
-		for (final PluginDescription plugin : availablePlugins) {
-			boolean enabled = enabledPlugins != null && enabledPlugins.contains(plugin.name);
-			String remoteversion = plugin.version;
-			if(remoteversion == null || remoteversion.equals(""))
-				remoteversion = tr("unknown");
-
-			String localversion;
-			PluginInformation p = PluginInformation.findPlugin(plugin.name);
-			if(p != null)
-			{
-				if(p.version != null && !p.version.equals(""))
-					localversion = p.version;
-				else
-					localversion = tr("unknown");
-				localversion = " (" + localversion + ")";
-			}
-			else
-				localversion = "";
-
-			final JCheckBox pluginCheck = new JCheckBox(tr("{0}: Version {1}{2}", plugin.name, remoteversion, localversion), enabled);
-			pluginPanel.add(pluginCheck);
-
-			pluginCheck.setToolTipText(plugin.resource != null ? ""+plugin.resource : tr("Plugin bundled with JOSM"));
-			JLabel label = new JLabel("<html><i>"+(plugin.description==null?tr("no description available"):plugin.description)+"</i></html>");
-			label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
-			label.setMaximumSize(new Dimension(width,1000));
-			pluginPanel.add(label);
-			pluginPanel.add(Box.createVerticalStrut(5));
-
-			pluginMap.put(plugin, enabled);
-			pluginCheck.addActionListener(new ActionListener(){
-				public void actionPerformed(ActionEvent e) {
+    /**
+     * Only the plugin name, its jar location and the description.
+     * In other words, this is the minimal requirement the plugin preference page
+     * needs to show the plugin as available
+     *
+     * @author imi
+     */
+    public static class PluginDescription implements Comparable<Object> {
+        // Note: All the following need to be public instance variables of
+        // type String.  (Plugin description XMLs from the server are parsed
+        // with tools.XmlObjectParser, which uses reflection to access them.)
+        public String name;
+        public String description;
+        public String resource;
+        public String version;
+        public PluginDescription(String name, String description, String resource, String version) {
+            this.name = name;
+            this.description = description;
+            this.resource = resource;
+            this.version = version;
+        }
+        public PluginDescription() {
+        }
+        public int compareTo(Object n) {
+            if(n instanceof PluginDescription)
+                return name.compareToIgnoreCase(((PluginDescription)n).name);
+            return -1;
+        }
+    }
+
+    private Map<PluginDescription, Boolean> pluginMap;
+    private JPanel plugin;
+    private class MyBox extends Box {
+        int lastwidth;
+        int offset = 40;
+        public MyBox()
+        {
+            super(BoxLayout.Y_AXIS);
+        }
+        public int myGetWidth()
+        {
+            int w = plugin.getWidth()-offset;
+            if(w <= 0) w = 450;
+            lastwidth = w;
+            return w;
+        }
+        public void paint(Graphics g)
+        {
+            if(lastwidth != plugin.getWidth()-offset)
+                refreshPluginPanel(gui);
+            super.paint(g);
+        }
+    }
+    private MyBox pluginPanel = new MyBox();
+    private PreferenceDialog gui;
+
+    public void addGui(final PreferenceDialog gui) {
+        this.gui = gui;
+        plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false);
+        JScrollPane pluginPane = new JScrollPane(pluginPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        pluginPane.setBorder(null);
+        plugin.add(pluginPane, GBC.eol().fill(GBC.BOTH));
+        plugin.add(GBC.glue(0,10), GBC.eol());
+        JButton morePlugins = new JButton(tr("Download List"));
+        morePlugins.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                int count = PluginDownloader.downloadDescription();
+                if (count > 0)
+                    JOptionPane.showMessageDialog(Main.parent,
+                        trn("Downloaded plugin information from {0} site",
+                            "Downloaded plugin information from {0} sites", count, count));
+                else
+                    JOptionPane.showMessageDialog(Main.parent, tr("No plugin information found."));
+                refreshPluginPanel(gui);
+            }
+        });
+        plugin.add(morePlugins, GBC.std().insets(0,0,10,0));
+
+        JButton update = new JButton(tr("Update"));
+        update.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                update();
+                refreshPluginPanel(gui);
+            }
+        });
+        plugin.add(update, GBC.std().insets(0,0,10,0));
+
+        JButton configureSites = new JButton(tr("Configure Sites ..."));
+        configureSites.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                configureSites();
+            }
+        });
+        plugin.add(configureSites, GBC.std());
+
+        refreshPluginPanel(gui);
+    }
+
+    private void configureSites() {
+        JPanel p = new JPanel(new GridBagLayout());
+        p.add(new JLabel(tr("Add either site-josm.xml or Wiki Pages.")), GBC.eol());
+        final DefaultListModel model = new DefaultListModel();
+        for (String s : PluginDownloader.getSites())
+            model.addElement(s);
+        final JList list = new JList(model);
+        p.add(new JScrollPane(list), GBC.std().fill());
+        JPanel buttons = new JPanel(new GridBagLayout());
+        buttons.add(new JButton(new AbstractAction(tr("Add")){
+            public void actionPerformed(ActionEvent e) {
+                String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."));
+                if (s != null)
+                    model.addElement(s);
+            }
+        }), GBC.eol().fill(GBC.HORIZONTAL));
+        buttons.add(new JButton(new AbstractAction(tr("Edit")){
+            public void actionPerformed(ActionEvent e) {
+                if (list.getSelectedValue() == null) {
+                    JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
+                    return;
+                }
+                String s = JOptionPane.showInputDialog(gui, tr("Add either site-josm.xml or Wiki Pages."), list.getSelectedValue());
+                model.setElementAt(s, list.getSelectedIndex());
+            }
+        }), GBC.eol().fill(GBC.HORIZONTAL));
+        buttons.add(new JButton(new AbstractAction(tr("Delete")){
+            public void actionPerformed(ActionEvent event) {
+                if (list.getSelectedValue() == null) {
+                    JOptionPane.showMessageDialog(gui, tr("Please select an entry."));
+                    return;
+                }
+                model.removeElement(list.getSelectedValue());
+            }
+        }), GBC.eol().fill(GBC.HORIZONTAL));
+        p.add(buttons, GBC.eol());
+        int answer = JOptionPane.showConfirmDialog(gui, p, tr("Configure Plugin Sites"), JOptionPane.OK_CANCEL_OPTION);
+        if (answer != JOptionPane.OK_OPTION)
+            return;
+        StringBuilder b = new StringBuilder();
+        for (int i = 0; i < model.getSize(); ++i) {
+            b.append(model.getElementAt(i));
+            if (i < model.getSize()-1)
+                b.append(" ");
+        }
+        Main.pref.put("pluginmanager.sites", b.toString());
+    }
+
+    private void update() {
+        // refresh description
+        int num = PluginDownloader.downloadDescription();
+        Boolean done = false;
+        refreshPluginPanel(gui);
+
+        Set<PluginDescription> toUpdate = new HashSet<PluginDescription>();
+        StringBuilder toUpdateStr = new StringBuilder();
+        for (PluginProxy proxy : Main.plugins) {
+            PluginDescription description = findDescription(proxy.info.name);
+            if (description != null && (description.version == null || description.version.equals(""))
+            ? (proxy.info.version != null && proxy.info.version.equals("")) : !description.version.equals(proxy.info.version)) {
+                toUpdate.add(description);
+                toUpdateStr.append(description.name+"\n");
+            }
+        }
+        if (toUpdate.isEmpty()) {
+            JOptionPane.showMessageDialog(Main.parent, tr("All installed plugins are up to date."));
+            done = true;
+        }
+        else
+        {
+            int answer = JOptionPane.showConfirmDialog(Main.parent, tr("Update the following plugins:\n\n{0}",
+            toUpdateStr.toString()), tr("Update"), JOptionPane.OK_CANCEL_OPTION);
+            if (answer == JOptionPane.OK_OPTION)
+            {
+                PluginDownloader.update(toUpdate);
+                done = true;
+            }
+        }
+        if(done && num >= 1)
+            Main.pref.put("pluginmanager.lastupdate", Long.toString(System.currentTimeMillis()));
+    }
+
+    private PluginDescription findDescription(String name) {
+        for (PluginDescription d : pluginMap.keySet())
+            if (d.name.equals(name))
+                return d;
+        return null;
+    }
+
+    private void refreshPluginPanel(final PreferenceDialog gui) {
+        Collection<PluginDescription> availablePlugins = getAvailablePlugins();
+        pluginMap = new HashMap<PluginDescription, Boolean>();
+        pluginPanel.removeAll();
+        int width = pluginPanel.myGetWidth();
+
+        Collection<String> enabledPlugins = Main.pref.getCollection("plugins", null);
+
+        for (final PluginDescription plugin : availablePlugins) {
+            boolean enabled = enabledPlugins != null && enabledPlugins.contains(plugin.name);
+            String remoteversion = plugin.version;
+            if(remoteversion == null || remoteversion.equals(""))
+                remoteversion = tr("unknown");
+
+            String localversion;
+            PluginInformation p = PluginInformation.findPlugin(plugin.name);
+            if(p != null)
+            {
+                if(p.version != null && !p.version.equals(""))
+                    localversion = p.version;
+                else
+                    localversion = tr("unknown");
+                localversion = " (" + localversion + ")";
+            }
+            else
+                localversion = "";
+
+            final JCheckBox pluginCheck = new JCheckBox(tr("{0}: Version {1}{2}", plugin.name, remoteversion, localversion), enabled);
+            pluginPanel.add(pluginCheck);
+
+            pluginCheck.setToolTipText(plugin.resource != null ? ""+plugin.resource : tr("Plugin bundled with JOSM"));
+            JLabel label = new JLabel("<html><i>"+(plugin.description==null?tr("no description available"):plugin.description)+"</i></html>");
+            label.setBorder(BorderFactory.createEmptyBorder(0,20,0,0));
+            label.setMaximumSize(new Dimension(width,1000));
+            pluginPanel.add(label);
+            pluginPanel.add(Box.createVerticalStrut(5));
+
+            pluginMap.put(plugin, enabled);
+            pluginCheck.addActionListener(new ActionListener(){
+                public void actionPerformed(ActionEvent e) {
                     // if user enabled a plugin, it is not loaded but found somewhere on disk: offer to delete jar
                     if (pluginCheck.isSelected()) {
@@ -281,5 +281,5 @@
                         if ((PluginInformation.getLoaded(plugin.name) == null) && (plinfo != null)) {
                             try {
-                                int answer = JOptionPane.showConfirmDialog(Main.parent, 
+                                int answer = JOptionPane.showConfirmDialog(Main.parent,
                                     tr("Plugin archive already available. Do you want to download current version by deleting existing archive?\n\n{0}",
                                     plinfo.file.getCanonicalPath()), tr("Plugin already exists"), JOptionPane.OK_CANCEL_OPTION);
@@ -295,99 +295,99 @@
                         }
                     }
-					pluginMap.put(plugin, pluginCheck.isSelected());
-				}
-			});
-		}
-		plugin.updateUI();
-	}
-
-	private Collection<PluginDescription> getAvailablePlugins() {
-		SortedMap<String, PluginDescription> availablePlugins = new TreeMap<String, PluginDescription>(new Comparator<String>(){
-			public int compare(String o1, String o2) {
-				return o1.compareToIgnoreCase(o2);
-			}
-		});
-		for (String location : PluginInformation.getPluginLocations()) {
-			File[] pluginFiles = new File(location).listFiles();
-			if (pluginFiles != null) {
-				Arrays.sort(pluginFiles);
-				for (File f : pluginFiles) {
-					if (!f.isFile())
-						continue;
-					if (f.getName().endsWith(".jar")) {
-						try {
-							PluginInformation info = new PluginInformation(f);
-							if (!availablePlugins.containsKey(info.name))
-								availablePlugins.put(info.name, new PluginDescription(
-									info.name,
-									info.description,
-									PluginInformation.fileToURL(f).toString(),
-									info.version));
-						} catch (PluginException x) {
-						}
-					} else if (f.getName().matches("^[0-9]+-site.*\\.xml$")) {
-						try {
-							Uniform<PluginDescription> parser = new Uniform<PluginDescription>(new FileReader(f), "plugin", PluginDescription.class);
-							for (PluginDescription pd : parser)
-								if (!availablePlugins.containsKey(pd.name))
-									availablePlugins.put(pd.name, pd);
-						} catch (Exception e) {
-							e.printStackTrace();
-							JOptionPane.showMessageDialog(Main.parent, tr("Error reading plugin information file: {0}", f.getName()));
-						}
-					}
-				}
-			}
-		}
-		for (PluginProxy proxy : Main.plugins)
-			if (!availablePlugins.containsKey(proxy.info.name))
-				availablePlugins.put(proxy.info.name, new PluginDescription(
-						proxy.info.name, 
-						proxy.info.description, 
-						proxy.info.file == null ? null :
-							PluginInformation.fileToURL(proxy.info.file).toString(),
-						proxy.info.version));
-		return availablePlugins.values();
-	}
-
-	public void ok() {
-		Collection<PluginDescription> toDownload = new LinkedList<PluginDescription>();
-		String msg = "";
-		for (Entry<PluginDescription, Boolean> entry : pluginMap.entrySet()) {
-			if (entry.getValue() && PluginInformation.findPlugin(entry.getKey().name) == null) {
-				toDownload.add(entry.getKey());
-				msg += entry.getKey().name+"\n";
-			}
-		}
-		if (!toDownload.isEmpty()) {
-			int answer = JOptionPane.showConfirmDialog(Main.parent,	
-					tr("Download the following plugins?\n\n{0}", msg), 
-					tr("Download missing plugins"),
-					JOptionPane.YES_NO_OPTION);
-			if (answer != JOptionPane.OK_OPTION)
-				for (PluginDescription pd : toDownload)
-					pluginMap.put(pd, false);
-			else
-				for (PluginDescription pd : toDownload)
-					if (!PluginDownloader.downloadPlugin(pd))
-						pluginMap.put(pd, false);
-
-		}
-
-		String oldPlugins = Main.pref.get("plugins");
-	        LinkedList<String> plugins = new LinkedList<String>();
-		Object pd[] = pluginMap.keySet().toArray();
-		Arrays.sort(pd);
-		for (Object d : pd) {
-			if (pluginMap.get(d))
-				plugins.add(((PluginDescription)d).name);
-		}
-
-		Main.pref.putCollection("plugins", plugins);
-		String newPlugins = Main.pref.get("plugins");
-		if(oldPlugins == null && plugins == null)
-			return;
-		if(plugins == null || oldPlugins == null || !plugins.equals(oldPlugins))
-			gui.requiresRestart = true;
-	}
+                    pluginMap.put(plugin, pluginCheck.isSelected());
+                }
+            });
+        }
+        plugin.updateUI();
+    }
+
+    private Collection<PluginDescription> getAvailablePlugins() {
+        SortedMap<String, PluginDescription> availablePlugins = new TreeMap<String, PluginDescription>(new Comparator<String>(){
+            public int compare(String o1, String o2) {
+                return o1.compareToIgnoreCase(o2);
+            }
+        });
+        for (String location : PluginInformation.getPluginLocations()) {
+            File[] pluginFiles = new File(location).listFiles();
+            if (pluginFiles != null) {
+                Arrays.sort(pluginFiles);
+                for (File f : pluginFiles) {
+                    if (!f.isFile())
+                        continue;
+                    if (f.getName().endsWith(".jar")) {
+                        try {
+                            PluginInformation info = new PluginInformation(f);
+                            if (!availablePlugins.containsKey(info.name))
+                                availablePlugins.put(info.name, new PluginDescription(
+                                    info.name,
+                                    info.description,
+                                    PluginInformation.fileToURL(f).toString(),
+                                    info.version));
+                        } catch (PluginException x) {
+                        }
+                    } else if (f.getName().matches("^[0-9]+-site.*\\.xml$")) {
+                        try {
+                            Uniform<PluginDescription> parser = new Uniform<PluginDescription>(new FileReader(f), "plugin", PluginDescription.class);
+                            for (PluginDescription pd : parser)
+                                if (!availablePlugins.containsKey(pd.name))
+                                    availablePlugins.put(pd.name, pd);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            JOptionPane.showMessageDialog(Main.parent, tr("Error reading plugin information file: {0}", f.getName()));
+                        }
+                    }
+                }
+            }
+        }
+        for (PluginProxy proxy : Main.plugins)
+            if (!availablePlugins.containsKey(proxy.info.name))
+                availablePlugins.put(proxy.info.name, new PluginDescription(
+                        proxy.info.name,
+                        proxy.info.description,
+                        proxy.info.file == null ? null :
+                            PluginInformation.fileToURL(proxy.info.file).toString(),
+                        proxy.info.version));
+        return availablePlugins.values();
+    }
+
+    public void ok() {
+        Collection<PluginDescription> toDownload = new LinkedList<PluginDescription>();
+        String msg = "";
+        for (Entry<PluginDescription, Boolean> entry : pluginMap.entrySet()) {
+            if (entry.getValue() && PluginInformation.findPlugin(entry.getKey().name) == null) {
+                toDownload.add(entry.getKey());
+                msg += entry.getKey().name+"\n";
+            }
+        }
+        if (!toDownload.isEmpty()) {
+            int answer = JOptionPane.showConfirmDialog(Main.parent,
+                    tr("Download the following plugins?\n\n{0}", msg),
+                    tr("Download missing plugins"),
+                    JOptionPane.YES_NO_OPTION);
+            if (answer != JOptionPane.OK_OPTION)
+                for (PluginDescription pd : toDownload)
+                    pluginMap.put(pd, false);
+            else
+                for (PluginDescription pd : toDownload)
+                    if (!PluginDownloader.downloadPlugin(pd))
+                        pluginMap.put(pd, false);
+
+        }
+
+        String oldPlugins = Main.pref.get("plugins");
+            LinkedList<String> plugins = new LinkedList<String>();
+        Object pd[] = pluginMap.keySet().toArray();
+        Arrays.sort(pd);
+        for (Object d : pd) {
+            if (pluginMap.get(d))
+                plugins.add(((PluginDescription)d).name);
+        }
+
+        Main.pref.putCollection("plugins", plugins);
+        String newPlugins = Main.pref.get("plugins");
+        if(oldPlugins == null && plugins == null)
+            return;
+        if(plugins == null || oldPlugins == null || !plugins.equals(oldPlugins))
+            gui.requiresRestart = true;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 1169)
@@ -34,30 +34,30 @@
 public class PreferenceDialog extends JTabbedPane {
 
-	public final static Collection<PreferenceSetting> settings = new LinkedList<PreferenceSetting>();
+    public final static Collection<PreferenceSetting> settings = new LinkedList<PreferenceSetting>();
 
-	public boolean requiresRestart = false;
-	public final RequireRestartAction requireRestartAction = new RequireRestartAction();
+    public boolean requiresRestart = false;
+    public final RequireRestartAction requireRestartAction = new RequireRestartAction();
 
-	// some common tabs
-	public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
-	public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."));
-	public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
-	public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
+    // some common tabs
+    public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
+    public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."));
+    public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
+    public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
 
   public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane();
 
-	/**
-	 * Construct a JPanel for the preference settings. Layout is GridBagLayout
-	 * and a centered title label and the description are added. The panel 
-	 * will be shown inside a {@link ScrollPane} 
-	 * @param icon The name of the icon.
-	 * @param title The title of this preference tab.
-	 * @param desc A description in one sentence for this tab. Will be displayed
-	 * 		italic under the title.
-	 * @return The created panel ready to add other controls.
-	 */
-	public JPanel createPreferenceTab(String icon, String title, String desc) {
-		return createPreferenceTab(icon, title, desc, true);
-	}
+    /**
+     * Construct a JPanel for the preference settings. Layout is GridBagLayout
+     * and a centered title label and the description are added. The panel
+     * will be shown inside a {@link ScrollPane}
+     * @param icon The name of the icon.
+     * @param title The title of this preference tab.
+     * @param desc A description in one sentence for this tab. Will be displayed
+     *      italic under the title.
+     * @return The created panel ready to add other controls.
+     */
+    public JPanel createPreferenceTab(String icon, String title, String desc) {
+        return createPreferenceTab(icon, title, desc, true);
+    }
 
     /**
@@ -68,5 +68,5 @@
      * @param desc A description in one sentence for this tab. Will be displayed
      *      italic under the title.
-     * @param inScrollPane if <code>true</code> the added tab will show scroll bars 
+     * @param inScrollPane if <code>true</code> the added tab will show scroll bars
      *        if the panel content is larger than the available space
      * @return The created panel ready to add other controls.
@@ -93,59 +93,59 @@
 
 
-	private final class RequireRestartAction implements ActionListener {
-		public void actionPerformed(ActionEvent e) {
-			requiresRestart = true;
-		}
-	}
+    private final class RequireRestartAction implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            requiresRestart = true;
+        }
+    }
 
-	public void ok() {
-		for (PreferenceSetting setting : settings)
-			setting.ok();
-		if (requiresRestart)
-			JOptionPane.showMessageDialog(Main.parent,tr("You have to restart JOSM for some settings to take effect."));
-		Main.parent.repaint();
-	}
+    public void ok() {
+        for (PreferenceSetting setting : settings)
+            setting.ok();
+        if (requiresRestart)
+            JOptionPane.showMessageDialog(Main.parent,tr("You have to restart JOSM for some settings to take effect."));
+        Main.parent.repaint();
+    }
 
-	/**
-	 * If the dialog is closed with Ok, the preferences will be stored to the preferences-
-	 * file, otherwise no change of the file happens.
-	 */
-	public PreferenceDialog() {
-		super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
-		display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
-		for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
-			try {
-	            it.next().addGui(this);
+    /**
+     * If the dialog is closed with Ok, the preferences will be stored to the preferences-
+     * file, otherwise no change of the file happens.
+     */
+    public PreferenceDialog() {
+        super(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT);
+        display.add(displaycontent, GBC.eol().fill(GBC.BOTH));
+        for (Iterator<PreferenceSetting> it = settings.iterator(); it.hasNext();) {
+            try {
+                it.next().addGui(this);
             } catch (SecurityException e) {
-            	it.remove();
+                it.remove();
             }
-		}
-	}
+        }
+    }
 
-	static {
-		// order is important!
-		settings.add(new DrawingPreference());
-		settings.add(new ColorPreference());
-		settings.add(new LafPreference());
-		settings.add(new LanguagePreference());
-		settings.add(new MapPaintPreference());
-		settings.add(new ServerAccessPreference());
-		settings.add(new FilePreferences());
-		settings.add(new ProxyPreferences());
-		settings.add(new ProjectionPreference());
-		settings.add(new TaggingPresetPreference());
-		settings.add(new PluginPreference());
-		settings.add(Main.toolbar);
-		settings.add(new AudioPreference());
-		settings.add(new ShortcutPreference());
+    static {
+        // order is important!
+        settings.add(new DrawingPreference());
+        settings.add(new ColorPreference());
+        settings.add(new LafPreference());
+        settings.add(new LanguagePreference());
+        settings.add(new MapPaintPreference());
+        settings.add(new ServerAccessPreference());
+        settings.add(new FilePreferences());
+        settings.add(new ProxyPreferences());
+        settings.add(new ProjectionPreference());
+        settings.add(new TaggingPresetPreference());
+        settings.add(new PluginPreference());
+        settings.add(Main.toolbar);
+        settings.add(new AudioPreference());
+        settings.add(new ShortcutPreference());
 
-		for (PluginProxy plugin : Main.plugins) {
-			PreferenceSetting p = plugin.getPreferenceSetting();
-			if (p != null)
-				settings.add(p);
-		}
+        for (PluginProxy plugin : Main.plugins) {
+            PreferenceSetting p = plugin.getPreferenceSetting();
+            if (p != null)
+                settings.add(p);
+        }
 
-		// always the last: advanced tab
-		settings.add(new AdvancedPreference());
-	}
+        // always the last: advanced tab
+        settings.add(new AdvancedPreference());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceSetting.java	(revision 1169)
@@ -4,13 +4,13 @@
 
 public interface PreferenceSetting {
-	/**
-	 * Add the GUI elements to the dialog. The elements should be initialized after
-	 * the current preferences.
-	 */
-	void addGui(PreferenceDialog gui);
+    /**
+     * Add the GUI elements to the dialog. The elements should be initialized after
+     * the current preferences.
+     */
+    void addGui(PreferenceDialog gui);
 
-	/**
-	 * Called when OK is pressed to save the setting in the preferences file.
-	 */
-	void ok();
+    /**
+     * Called when OK is pressed to save the setting in the preferences file.
+     */
+    void ok();
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ProjectionPreference.java	(revision 1169)
@@ -19,44 +19,44 @@
 public class ProjectionPreference implements PreferenceSetting {
 
-	/**
-	 * Combobox with all projections available
-	 */
-	private JComboBox projectionCombo = new JComboBox(Projection.allProjections);
-	private JComboBox coordinatesCombo = new JComboBox(CoordinateFormat.values());
+    /**
+     * Combobox with all projections available
+     */
+    private JComboBox projectionCombo = new JComboBox(Projection.allProjections);
+    private JComboBox coordinatesCombo = new JComboBox(CoordinateFormat.values());
 
-	public void addGui(PreferenceDialog gui) {
-		
-	    for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
-	        if (projectionCombo.getItemAt(i).getClass().getName().equals(Main.pref.get("projection"))) {
-	            projectionCombo.setSelectedIndex(i);
-	            break;
-	        }
-	    }
+    public void addGui(PreferenceDialog gui) {
 
-	    for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
-	        if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(Main.pref.get("coordinates"))) {
-	            coordinatesCombo.setSelectedIndex(i);
-	            break;
-	        }
-	    }
+        for (int i = 0; i < projectionCombo.getItemCount(); ++i) {
+            if (projectionCombo.getItemAt(i).getClass().getName().equals(Main.pref.get("projection"))) {
+                projectionCombo.setSelectedIndex(i);
+                break;
+            }
+        }
 
-		projectionCombo.addActionListener(gui.requireRestartAction);
+        for (int i = 0; i < coordinatesCombo.getItemCount(); ++i) {
+            if (((CoordinateFormat)coordinatesCombo.getItemAt(i)).name().equals(Main.pref.get("coordinates"))) {
+                coordinatesCombo.setSelectedIndex(i);
+                break;
+            }
+        }
+
+        projectionCombo.addActionListener(gui.requireRestartAction);
         coordinatesCombo.addActionListener(gui.requireRestartAction);
-		
-		JPanel projPanel = new JPanel();
-		projPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), tr("Map Projection")));
-		projPanel.setLayout(new GridBagLayout());
-		projPanel.add(new JLabel(tr("Projection method")), GBC.std().insets(5,5,0,5));
-		projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-		projPanel.add(projectionCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-	    projPanel.add(new JLabel(tr("Display coordinates as")), GBC.std().insets(5,5,0,5));
-	    projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
-	    projPanel.add(coordinatesCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
-		gui.map.add(projPanel, GBC.eol().insets(0,0,0,10).fill(GBC.HORIZONTAL));
+
+        JPanel projPanel = new JPanel();
+        projPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), tr("Map Projection")));
+        projPanel.setLayout(new GridBagLayout());
+        projPanel.add(new JLabel(tr("Projection method")), GBC.std().insets(5,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(projectionCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        projPanel.add(new JLabel(tr("Display coordinates as")), GBC.std().insets(5,5,0,5));
+        projPanel.add(GBC.glue(5,0), GBC.std().fill(GBC.HORIZONTAL));
+        projPanel.add(coordinatesCombo, GBC.eop().fill(GBC.HORIZONTAL).insets(0,5,5,5));
+        gui.map.add(projPanel, GBC.eol().insets(0,0,0,10).fill(GBC.HORIZONTAL));
     }
 
-	public void ok() {
-		Main.pref.put("projection", projectionCombo.getSelectedItem().getClass().getName());
-		Main.pref.put("coordinates", ((CoordinateFormat)coordinatesCombo.getSelectedItem()).name());
+    public void ok() {
+        Main.pref.put("projection", projectionCombo.getSelectedItem().getClass().getName());
+        Main.pref.put("coordinates", ((CoordinateFormat)coordinatesCombo.getSelectedItem()).name());
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ProxyPreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ProxyPreferences.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ProxyPreferences.java	(revision 1169)
@@ -20,70 +20,70 @@
 public class ProxyPreferences implements PreferenceSetting {
 
-	public static final String PROXY_ENABLE = "proxy.enable";
-	public static final String PROXY_HOST = "proxy.host";
-	public static final String PROXY_PORT = "proxy.port";
-	public static final String PROXY_ANONYMOUS = "proxy.anonymous";
-	public static final String PROXY_USER = "proxy.user";
-	public static final String PROXY_PASS = "proxy.pass";
+    public static final String PROXY_ENABLE = "proxy.enable";
+    public static final String PROXY_HOST = "proxy.host";
+    public static final String PROXY_PORT = "proxy.port";
+    public static final String PROXY_ANONYMOUS = "proxy.anonymous";
+    public static final String PROXY_USER = "proxy.user";
+    public static final String PROXY_PASS = "proxy.pass";
 
-	private JCheckBox proxyEnable = new JCheckBox(tr("Enable proxy server"));
-	private JTextField proxyHost = new JTextField(20);
-	private JTextField proxyPort = new JTextField(5);
-	private JCheckBox proxyAnonymous = new JCheckBox(tr("Anonymous"));
-	private JTextField proxyUser = new JTextField(20);
-	private JPasswordField proxyPass = new JPasswordField(20);
+    private JCheckBox proxyEnable = new JCheckBox(tr("Enable proxy server"));
+    private JTextField proxyHost = new JTextField(20);
+    private JTextField proxyPort = new JTextField(5);
+    private JCheckBox proxyAnonymous = new JCheckBox(tr("Anonymous"));
+    private JTextField proxyUser = new JTextField(20);
+    private JPasswordField proxyPass = new JPasswordField(20);
 
-	public void addGui(PreferenceDialog gui) {
-		proxyEnable.setSelected(Main.pref.getBoolean(PROXY_ENABLE));
-		proxyEnable.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				proxyHost.setEnabled(proxyEnable.isSelected());
-				proxyPort.setEnabled(proxyEnable.isSelected());
-				proxyAnonymous.setEnabled(proxyEnable.isSelected());
-				proxyUser.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
-				proxyPass.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
-			}
-		});
-		proxyHost.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
-		proxyHost.setText(Main.pref.get(PROXY_HOST));
-		proxyPort.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
-		proxyPort.setText(Main.pref.get(PROXY_PORT));
-		proxyAnonymous.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
-		proxyAnonymous.setSelected(Main.pref.getBoolean(PROXY_ANONYMOUS));
-		proxyAnonymous.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				proxyUser.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
-				proxyPass.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
-			}
-		});
-		proxyUser.setEnabled(Main.pref.getBoolean(PROXY_ENABLE) && (Main.pref.getBoolean(PROXY_ANONYMOUS)));
-		proxyUser.setText(Main.pref.get(PROXY_USER));
-		proxyPass.setEnabled(Main.pref.getBoolean(PROXY_ENABLE) && (Main.pref.getBoolean(PROXY_ANONYMOUS)));
-		proxyPass.setText(Main.pref.get(PROXY_USER));
-		
-		gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-		gui.connection.add(new JLabel(tr("Proxy Settings")), GBC.eol());
-		gui.connection.add(proxyEnable, GBC.eol().insets(20, 0, 0, 0));
-		gui.connection.add(new JLabel(tr("Proxy server host")), GBC.std());
-		gui.connection.add(proxyHost, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-		gui.connection.add(new JLabel(tr("Proxy server port")), GBC.std());
-		gui.connection.add(proxyPort, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-		gui.connection.add(proxyAnonymous, GBC.eop().insets(20, 0, 0, 0));
-		gui.connection.add(new JLabel(tr("Proxy server username")), GBC.std());
-		gui.connection.add(proxyUser, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-		gui.connection.add(new JLabel(tr("Proxy server password")), GBC.std());
-		gui.connection.add(proxyPass, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+    public void addGui(PreferenceDialog gui) {
+        proxyEnable.setSelected(Main.pref.getBoolean(PROXY_ENABLE));
+        proxyEnable.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                proxyHost.setEnabled(proxyEnable.isSelected());
+                proxyPort.setEnabled(proxyEnable.isSelected());
+                proxyAnonymous.setEnabled(proxyEnable.isSelected());
+                proxyUser.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
+                proxyPass.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
+            }
+        });
+        proxyHost.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
+        proxyHost.setText(Main.pref.get(PROXY_HOST));
+        proxyPort.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
+        proxyPort.setText(Main.pref.get(PROXY_PORT));
+        proxyAnonymous.setEnabled(Main.pref.getBoolean(PROXY_ENABLE));
+        proxyAnonymous.setSelected(Main.pref.getBoolean(PROXY_ANONYMOUS));
+        proxyAnonymous.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                proxyUser.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
+                proxyPass.setEnabled(proxyEnable.isSelected() && !proxyAnonymous.isSelected());
+            }
+        });
+        proxyUser.setEnabled(Main.pref.getBoolean(PROXY_ENABLE) && (Main.pref.getBoolean(PROXY_ANONYMOUS)));
+        proxyUser.setText(Main.pref.get(PROXY_USER));
+        proxyPass.setEnabled(Main.pref.getBoolean(PROXY_ENABLE) && (Main.pref.getBoolean(PROXY_ANONYMOUS)));
+        proxyPass.setText(Main.pref.get(PROXY_USER));
 
-		gui.connection.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
-	}
+        gui.connection.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+        gui.connection.add(new JLabel(tr("Proxy Settings")), GBC.eol());
+        gui.connection.add(proxyEnable, GBC.eol().insets(20, 0, 0, 0));
+        gui.connection.add(new JLabel(tr("Proxy server host")), GBC.std());
+        gui.connection.add(proxyHost, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.connection.add(new JLabel(tr("Proxy server port")), GBC.std());
+        gui.connection.add(proxyPort, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.connection.add(proxyAnonymous, GBC.eop().insets(20, 0, 0, 0));
+        gui.connection.add(new JLabel(tr("Proxy server username")), GBC.std());
+        gui.connection.add(proxyUser, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.connection.add(new JLabel(tr("Proxy server password")), GBC.std());
+        gui.connection.add(proxyPass, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
 
-	public void ok() {
-		Main.pref.put(PROXY_ENABLE, proxyEnable.isSelected());
-		Main.pref.put(PROXY_HOST, proxyHost.getText());
-		Main.pref.put(PROXY_PORT, proxyPort.getText());
-		Main.pref.put(PROXY_ANONYMOUS, proxyAnonymous.isSelected());
-		Main.pref.put(PROXY_USER, proxyUser.getText());
-		Main.pref.put(PROXY_PASS, new String(proxyPass.getPassword()));
-	}
+        gui.connection.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+    }
+
+    public void ok() {
+        Main.pref.put(PROXY_ENABLE, proxyEnable.isSelected());
+        Main.pref.put(PROXY_HOST, proxyHost.getText());
+        Main.pref.put(PROXY_PORT, proxyPort.getText());
+        Main.pref.put(PROXY_ANONYMOUS, proxyAnonymous.isSelected());
+        Main.pref.put(PROXY_USER, proxyUser.getText());
+        Main.pref.put(PROXY_PASS, new String(proxyPass.getPassword()));
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java	(revision 1169)
@@ -15,47 +15,47 @@
 public class ServerAccessPreference implements PreferenceSetting {
 
-	/**
-	 * Editfield for the Base url to the REST API from OSM.
-	 */
-	private JTextField osmDataServer = new JTextField(20);
-	/**
-	 * Editfield for the username to the OSM account.
-	 */
-	private JTextField osmDataUsername = new JTextField(20);
-	/**
-	 * Passwordfield for the userpassword of the REST API.
-	 */
-	private JPasswordField osmDataPassword = new JPasswordField(20);
+    /**
+     * Editfield for the Base url to the REST API from OSM.
+     */
+    private JTextField osmDataServer = new JTextField(20);
+    /**
+     * Editfield for the username to the OSM account.
+     */
+    private JTextField osmDataUsername = new JTextField(20);
+    /**
+     * Passwordfield for the userpassword of the REST API.
+     */
+    private JPasswordField osmDataPassword = new JPasswordField(20);
 
-	public void addGui(PreferenceDialog gui) {
-		osmDataServer.setText(Main.pref.get("osm-server.url"));
-		osmDataUsername.setText(Main.pref.get("osm-server.username"));
-		osmDataPassword.setText(Main.pref.get("osm-server.password"));
+    public void addGui(PreferenceDialog gui) {
+        osmDataServer.setText(Main.pref.get("osm-server.url"));
+        osmDataUsername.setText(Main.pref.get("osm-server.username"));
+        osmDataPassword.setText(Main.pref.get("osm-server.password"));
 
-		osmDataServer.setToolTipText(tr("The base URL for the OSM server (REST API)"));
-		osmDataUsername.setToolTipText(tr("Login name (email) to the OSM account."));
-		osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
+        osmDataServer.setToolTipText(tr("The base URL for the OSM server (REST API)"));
+        osmDataUsername.setToolTipText(tr("Login name (email) to the OSM account."));
+        osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
 
-		gui.connection.add(new JLabel(tr("Base Server URL")), GBC.std());
-		gui.connection.add(osmDataServer, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-		gui.connection.add(new JLabel(tr("OSM username (email)")), GBC.std());
-		gui.connection.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
-		gui.connection.add(new JLabel(tr("OSM password")), GBC.std());
-		gui.connection.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
-		JLabel warning = new JLabel(tr("<html>" +
-				"WARNING: The password is stored in plain text in the preferences file.<br>" +
-				"The password is transfered in plain text to the server, encoded in the url.<br>" +
-		"<b>Do not use a valuable Password.</b></html>"));
-		warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
-		gui.connection.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
-	}
+        gui.connection.add(new JLabel(tr("Base Server URL")), GBC.std());
+        gui.connection.add(osmDataServer, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.connection.add(new JLabel(tr("OSM username (email)")), GBC.std());
+        gui.connection.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+        gui.connection.add(new JLabel(tr("OSM password")), GBC.std());
+        gui.connection.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
+        JLabel warning = new JLabel(tr("<html>" +
+                "WARNING: The password is stored in plain text in the preferences file.<br>" +
+                "The password is transfered in plain text to the server, encoded in the url.<br>" +
+        "<b>Do not use a valuable Password.</b></html>"));
+        warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
+        gui.connection.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
+    }
 
-	public void ok() {
-		Main.pref.put("osm-server.url", osmDataServer.getText());
-		Main.pref.put("osm-server.username", osmDataUsername.getText());
-		String pwd = String.valueOf(osmDataPassword.getPassword());
-		if (pwd.equals(""))
-			pwd = null;
-		Main.pref.put("osm-server.password", pwd);
+    public void ok() {
+        Main.pref.put("osm-server.url", osmDataServer.getText());
+        Main.pref.put("osm-server.username", osmDataUsername.getText());
+        String pwd = String.valueOf(osmDataPassword.getPassword());
+        if (pwd.equals(""))
+            pwd = null;
+        Main.pref.put("osm-server.password", pwd);
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ShortcutPreference.java	(revision 1169)
@@ -15,78 +15,78 @@
 public class ShortcutPreference implements PreferenceSetting {
 
-	public void addGui(PreferenceDialog gui) {
-		// icon source: http://www.iconfinder.net/index.php?q=key&page=icondetails&iconid=8553&size=128&q=key&s12=on&s16=on&s22=on&s32=on&s48=on&s64=on&s128=on
-		// icon licence: GPL
-		// icon designer: Paolino, http://www.paolinoland.it/
-		// icon original filename: keyboard.png
-		// icon original size: 128x128
-		// modifications: icon was cropped, then resized
-		JPanel p = gui.createPreferenceTab("shortcuts", tr("Shortcut Preferences"), 
-		        tr("Changing keyboard shortcuts manually."), false);
+    public void addGui(PreferenceDialog gui) {
+        // icon source: http://www.iconfinder.net/index.php?q=key&page=icondetails&iconid=8553&size=128&q=key&s12=on&s16=on&s22=on&s32=on&s48=on&s64=on&s128=on
+        // icon licence: GPL
+        // icon designer: Paolino, http://www.paolinoland.it/
+        // icon original filename: keyboard.png
+        // icon original size: 128x128
+        // modifications: icon was cropped, then resized
+        JPanel p = gui.createPreferenceTab("shortcuts", tr("Shortcut Preferences"),
+                tr("Changing keyboard shortcuts manually."), false);
 
-		prefJPanel prefpanel = new prefJPanel(new scListModel());
-		p.add(prefpanel, GBC.eol().fill(GBC.BOTH));
+        prefJPanel prefpanel = new prefJPanel(new scListModel());
+        p.add(prefpanel, GBC.eol().fill(GBC.BOTH));
 
-	}
+    }
 
-	public void ok() {
+    public void ok() {
    }
 
-	// Maybe move this to prefPanel? There's no need for it to be here.
-	private class scListModel extends AbstractTableModel {
-//		private String[] columnNames = new String[]{tr("Action"), tr("Shortcut"), tr("Group"), tr("ID")};
-		private String[] columnNames = new String[]{tr("Action"), tr("Shortcut")};
-		private Collection<Shortcut> data;
-		public scListModel() {
-			data = Shortcut.listAll();
-		}
-		public int getColumnCount() {
-			return columnNames.length;
-		}
-		public int getRowCount() {
-			return data.size();
-		}
-		public String getColumnName(int col) {
-			return columnNames[col];
-		}
-		public Object getValueAt(int row, int col) {
-			Shortcut sc = (Shortcut)data.toArray()[row];
-			if (col == 0) {
-				return sc.getLongText();
-			} else if (col == 1) {
-				return sc.getKeyText();
-			} /*else if (col == 2) {
-				if (sc.getRequestedGroup() == Shortcut.GROUP_NONE) {
-					return tr("None");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_HOTKEY) {
-					return tr("Hotkey");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_MENU) {
-					return tr("Menu");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_EDIT) {
-					return tr("Edit");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_LAYER) {
-					return tr("Subwindow");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_DIRECT) {
-					return tr("Direct");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_MNEMONIC) {
-					return tr("Mnemonic");
-				} else if (sc.getRequestedGroup() == Shortcut.GROUP_RESERVED) {
-					return tr("System");
-				} else {
-					return tr("Unknown");
-				}
-			} else if (col == 3) {
-				return sc.getShortText();
-			} */else {
-				// This is a kind of hack that allows the actions on the editing controls
-				// to access the underlying shortcut object without introducing another
-				// method. I opted to stay within the interface.
-				return sc;
-			}
-		}
-		public boolean isCellEditable(int row, int col) {
-			return false;
-		}
-	}
+    // Maybe move this to prefPanel? There's no need for it to be here.
+    private class scListModel extends AbstractTableModel {
+//      private String[] columnNames = new String[]{tr("Action"), tr("Shortcut"), tr("Group"), tr("ID")};
+        private String[] columnNames = new String[]{tr("Action"), tr("Shortcut")};
+        private Collection<Shortcut> data;
+        public scListModel() {
+            data = Shortcut.listAll();
+        }
+        public int getColumnCount() {
+            return columnNames.length;
+        }
+        public int getRowCount() {
+            return data.size();
+        }
+        public String getColumnName(int col) {
+            return columnNames[col];
+        }
+        public Object getValueAt(int row, int col) {
+            Shortcut sc = (Shortcut)data.toArray()[row];
+            if (col == 0) {
+                return sc.getLongText();
+            } else if (col == 1) {
+                return sc.getKeyText();
+            } /*else if (col == 2) {
+                if (sc.getRequestedGroup() == Shortcut.GROUP_NONE) {
+                    return tr("None");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_HOTKEY) {
+                    return tr("Hotkey");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_MENU) {
+                    return tr("Menu");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_EDIT) {
+                    return tr("Edit");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_LAYER) {
+                    return tr("Subwindow");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_DIRECT) {
+                    return tr("Direct");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_MNEMONIC) {
+                    return tr("Mnemonic");
+                } else if (sc.getRequestedGroup() == Shortcut.GROUP_RESERVED) {
+                    return tr("System");
+                } else {
+                    return tr("Unknown");
+                }
+            } else if (col == 3) {
+                return sc.getShortText();
+            } */else {
+                // This is a kind of hack that allows the actions on the editing controls
+                // to access the underlying shortcut object without introducing another
+                // method. I opted to stay within the interface.
+                return sc;
+            }
+        }
+        public boolean isCellEditable(int row, int col) {
+            return false;
+        }
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 1169)
@@ -34,119 +34,119 @@
 public class TaggingPresetPreference implements PreferenceSetting {
 
-	public static Collection<TaggingPreset> taggingPresets;
-	private JList taggingPresetSources;
-	private JCheckBox enableDefault;
-	
-	public void addGui(final PreferenceDialog gui) {
-		
-		taggingPresetSources = new JList(new DefaultListModel());
-		enableDefault = new JCheckBox(tr("Enable built-in defaults"), 
-				Main.pref.getBoolean("taggingpreset.enable-defaults", true));
+    public static Collection<TaggingPreset> taggingPresets;
+    private JList taggingPresetSources;
+    private JCheckBox enableDefault;
 
-		String annos = Main.pref.get("taggingpreset.sources");
-		StringTokenizer st = new StringTokenizer(annos, ";");
-		while (st.hasMoreTokens())
-			((DefaultListModel)taggingPresetSources.getModel()).addElement(st.nextToken());
+    public void addGui(final PreferenceDialog gui) {
 
-		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;
-			}
-		});
+        taggingPresetSources = new JList(new DefaultListModel());
+        enableDefault = new JCheckBox(tr("Enable built-in defaults"),
+                Main.pref.getBoolean("taggingpreset.enable-defaults", 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;
-				}
-			}
-		});
+        String annos = Main.pref.get("taggingpreset.sources");
+        StringTokenizer st = new StringTokenizer(annos, ";");
+        while (st.hasMoreTokens())
+            ((DefaultListModel)taggingPresetSources.getModel()).addElement(st.nextToken());
 
-		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);
+        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;
+            }
+        });
 
-		taggingPresetSources.setToolTipText(tr("The sources (url or filename) of tagging preset definition files. See http://josm.openstreetmap.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."));
+        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;
+                }
+            }
+        });
 
-		JPanel tpPanel = new JPanel();
-		tpPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), tr("Tagging Presets")));
-		tpPanel.setLayout(new GridBagLayout());
-		tpPanel.add(enableDefault, GBC.eol().insets(5,5,5,0));
-		tpPanel.add(new JLabel(tr("Tagging preset sources")), GBC.eol().insets(5,5,5,0));
-		tpPanel.add(new JScrollPane(taggingPresetSources), GBC.eol().insets(5,0,5,0).fill(GBC.BOTH));
-		JPanel buttonPanel = new JPanel(new GridBagLayout());
-		tpPanel.add(buttonPanel, GBC.eol().insets(5,0,5,5).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));
-		gui.map.add(tpPanel, GBC.eol().fill(GBC.BOTH));
-	}
+        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);
 
-	public void ok() {
-		Main.pref.put("taggingpreset.enable-defaults", enableDefault.getSelectedObjects() != null);
-		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);
-	}
+        taggingPresetSources.setToolTipText(tr("The sources (url or filename) of tagging preset definition files. See http://josm.openstreetmap.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."));
 
-	/** 
-	 * Initialize the tagging presets (load and may display error)
-	 */
-	public static void initialize() {
-		taggingPresets = TaggingPreset.readFromPreferences();
-		if (taggingPresets.isEmpty()) {
-			Main.main.menu.presetsMenu.setVisible(false);
-		}
-		else
-		{
-			HashMap<TaggingPresetMenu,JMenu> submenus = new HashMap<TaggingPresetMenu,JMenu>();
-			for (final TaggingPreset p : taggingPresets)
-			{
-				JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
-				if (p instanceof TaggingPresetSeparator)
-					m.add(new JSeparator());
-				else if (p instanceof TaggingPresetMenu)
-				{
-					JMenu submenu = new JMenu(p);
-					((TaggingPresetMenu)p).menu = submenu;
-					submenus.put((TaggingPresetMenu)p, submenu);
-					m.add(submenu);
-				}
-				else
-				{
-					JMenuItem mi = new JMenuItem(p);
-					mi.setText(tr(p.name));
-					m.add(mi);
-				}
-			}
-		}
-	}
+        JPanel tpPanel = new JPanel();
+        tpPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), tr("Tagging Presets")));
+        tpPanel.setLayout(new GridBagLayout());
+        tpPanel.add(enableDefault, GBC.eol().insets(5,5,5,0));
+        tpPanel.add(new JLabel(tr("Tagging preset sources")), GBC.eol().insets(5,5,5,0));
+        tpPanel.add(new JScrollPane(taggingPresetSources), GBC.eol().insets(5,0,5,0).fill(GBC.BOTH));
+        JPanel buttonPanel = new JPanel(new GridBagLayout());
+        tpPanel.add(buttonPanel, GBC.eol().insets(5,0,5,5).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));
+        gui.map.add(tpPanel, GBC.eol().fill(GBC.BOTH));
+    }
+
+    public void ok() {
+        Main.pref.put("taggingpreset.enable-defaults", enableDefault.getSelectedObjects() != null);
+        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();
+        if (taggingPresets.isEmpty()) {
+            Main.main.menu.presetsMenu.setVisible(false);
+        }
+        else
+        {
+            HashMap<TaggingPresetMenu,JMenu> submenus = new HashMap<TaggingPresetMenu,JMenu>();
+            for (final TaggingPreset p : taggingPresets)
+            {
+                JMenu m = p.group != null ? submenus.get(p.group) : Main.main.menu.presetsMenu;
+                if (p instanceof TaggingPresetSeparator)
+                    m.add(new JSeparator());
+                else if (p instanceof TaggingPresetMenu)
+                {
+                    JMenu submenu = new JMenu(p);
+                    ((TaggingPresetMenu)p).menu = submenu;
+                    submenus.put((TaggingPresetMenu)p, submenu);
+                    m.add(submenu);
+                }
+                else
+                {
+                    JMenuItem mi = new JMenuItem(p);
+                    mi.setText(tr(p.name));
+                    m.add(mi);
+                }
+            }
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 1169)
@@ -37,242 +37,242 @@
 public class ToolbarPreferences implements PreferenceSetting {
 
-	private final class Move implements ActionListener {
-		public void actionPerformed(ActionEvent e) {
-			if (e.getActionCommand().equals("<<")) {
-				while (unselected.size() > 1) {
-					selected.addElement(unselected.get(0));
-					unselected.remove(0);
-				}
-			} else if (e.getActionCommand().equals("<") && unselectedList.getSelectedIndex() != -1) {
-				while (unselectedList.getSelectedIndex() != -1 && unselectedList.getSelectedIndex() != unselected.size()-1) {
-					selected.addElement(unselectedList.getSelectedValue());
-					unselected.remove(unselectedList.getSelectedIndex());
-				}
-				if (unselectedList.getSelectedIndex() == unselected.size()-1)
-					selected.addElement(null);
-			} else if (e.getActionCommand().equals(">") && selectedList.getSelectedIndex() != -1) {
-				while (selectedList.getSelectedIndex() != -1) {
-					if (selectedList.getSelectedValue() != null)
-						unselected.add(unselected.size()-1, selectedList.getSelectedValue());
-					selected.remove(selectedList.getSelectedIndex());
-				}
-			} else if (e.getActionCommand().equals(">>")) {
-				while (selected.size() > 0) {
-					if (selected.get(0) != null)
-						unselected.add(unselected.size()-1, selected.get(0));
-					selected.remove(0);
-				}
-			} else if (e.getActionCommand().equals("up")) {
-				int i = selectedList.getSelectedIndex();
-				Object o = selected.get(i);
-				if (i != 0) {
-					selected.remove(i);
-					selected.add(i-1, o);
-					selectedList.setSelectedIndex(i-1);
-				}
-			} else if (e.getActionCommand().equals("down")) {
-				int i = selectedList.getSelectedIndex();
-				Object o = selected.get(i);
-				if (i != selected.size()-1) {
-					selected.remove(i);
-					selected.add(i+1, o);
-					selectedList.setSelectedIndex(i+1);
-				}
-			}
-		}
-	}
-	private Move moveAction = new Move();
-
-	/**
-	 * Key: Registered name (property "toolbar" of action).
-	 * Value: The action to execute.
-	 */
-	private Map<String, Action> actions = new HashMap<String, Action>();
-
-	private DefaultListModel selected = new DefaultListModel();
-	private DefaultListModel unselected = new DefaultListModel();
-	private JList selectedList = new JList(selected);
-	private JList unselectedList = new JList(unselected);
-
-	public JToolBar control = new JToolBar();
-
-	private JButton upButton;
-	private JButton downButton;
-
-	public ToolbarPreferences() {
-		control.setFloatable(false);
-
-		final ListCellRenderer oldRenderer = selectedList.getCellRenderer();
-		ListCellRenderer renderer = new DefaultListCellRenderer(){
-			@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-				String s = tr("Separator");
-				Icon i = ImageProvider.get("preferences/separator");
-				if (value != null) {
-					s = (String)((Action)value).getValue(Action.NAME);
-					i = (Icon)((Action)value).getValue(Action.SMALL_ICON);
-				}
-				JLabel l = (JLabel)oldRenderer.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
-				l.setIcon(i);
-				return l;
-			}
-		};
-		selectedList.setCellRenderer(renderer);
-		unselectedList.setCellRenderer(renderer);
-
-		unselectedList.addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				if ((unselectedList.getSelectedIndex() != -1))
-					selectedList.clearSelection();
-				upButton.setEnabled(selectedList.getSelectedIndex() != -1);
-				downButton.setEnabled(selectedList.getSelectedIndex() != -1);
-			}
-		});
-		selectedList.addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				boolean sel = selectedList.getSelectedIndex() != -1;
-				if (sel)
-					unselectedList.clearSelection();
-				upButton.setEnabled(sel);
-				downButton.setEnabled(sel);
-			}
-		});
-	}
-
-	public void addGui(PreferenceDialog gui) {
-		selected.removeAllElements();
-		unselected.removeAllElements();
-		Map<String, Action> us = new TreeMap<String, Action>();
-		for (Action a : actions.values())
-		{
-			us.put(a.getValue(Action.NAME).toString()+a.toString(), a);
-		}
-		for (String a : us.keySet())
-			unselected.addElement(us.get(a));
-		unselected.addElement(null);
-
-		final JPanel left = new JPanel(new GridBagLayout());
-		left.add(new JLabel(tr("Toolbar")), GBC.eol());
-		left.add(new JScrollPane(selectedList), GBC.std().fill(GBC.BOTH));
-
-		final JPanel right = new JPanel(new GridBagLayout());
-		right.add(new JLabel(tr("Available")), GBC.eol());
-		right.add(new JScrollPane(unselectedList), GBC.eol().fill(GBC.BOTH));
-
-		final JPanel buttons = new JPanel(new GridLayout(6,1));
-		buttons.add(upButton = createButton("up"));
-		buttons.add(createButton("<<"));
-		buttons.add(createButton("<"));
-		buttons.add(createButton(">"));
-		buttons.add(createButton(">>"));
-		buttons.add(downButton = createButton("down"));
-		upButton.setEnabled(false);
-		downButton.setEnabled(false);
-		
-		final JPanel p = new JPanel();
-		p.setLayout(new LayoutManager(){
-			public void addLayoutComponent(String name, Component comp) {}
-			public void removeLayoutComponent(Component comp) {}
-			public Dimension minimumLayoutSize(Container parent) {
-				Dimension l = left.getMinimumSize();
-				Dimension r = right.getMinimumSize();
-				Dimension b = buttons.getMinimumSize();
-				return new Dimension(l.width+b.width+10+r.width,l.height+b.height+10+r.height);
-			}
-			public Dimension preferredLayoutSize(Container parent) {
-				Dimension l = left.getPreferredSize();
-				Dimension r = right.getPreferredSize();
-				return new Dimension(l.width+r.width+10+buttons.getPreferredSize().width,Math.max(l.height, r.height));
-			}
-			public void layoutContainer(Container parent) {
-				Dimension d = p.getSize();
-				Dimension b = buttons.getPreferredSize();
-				int width = (d.width-10-b.width)/2;
-				left.setBounds(new Rectangle(0,0,width,d.height));
-				right.setBounds(new Rectangle(width+10+b.width,0,width,d.height));
-				buttons.setBounds(new Rectangle(width+5, d.height/2-b.height/2, b.width, b.height));
-			}
-		});
-		p.add(left);
-		p.add(buttons);
-		p.add(right);
-
-		JPanel panel = gui.createPreferenceTab("toolbar", tr("Toolbar customization"), 
-		        tr("Customize the elements on the toolbar."), false);
-		panel.add(p, GBC.eol().fill(GBC.BOTH));
-
-		for (String s : getToolString()) {
-			if (s.equals("|"))
-				selected.addElement(null);
-			else {
-				Action a = actions.get(s);
-				if (a != null) {
-					selected.addElement(a);
-					unselected.removeElement(a);
-				}
-			}
-		}
-	}
-
-	private String[] getToolString() {
-		String s = Main.pref.get("toolbar", "open;save;exportgpx;|;download;upload;|;undo;redo;|;preference");
-		if (s == null || s.equals("null") || s.equals(""))
-			return new String[0];
-		return s.split(";");
-	}
-
-	private JButton createButton(String name) {
-		JButton b = new JButton();
-		if (name.equals("up"))
-			b.setIcon(ImageProvider.get("dialogs", "up"));
-		else if (name.equals("down"))
-			b.setIcon(ImageProvider.get("dialogs", "down"));
-		else
-			b.setText(name);
-		b.addActionListener(moveAction);
-		b.setActionCommand(name);
-		return b;
-	}
-
-	public void ok() {
-		StringBuilder b = new StringBuilder();
-		for (int i = 0; i < selected.size(); ++i) {
-			if (selected.get(i) == null)
-				b.append("|");
-			else
-				b.append(((Action)selected.get(i)).getValue("toolbar"));
-			b.append(";");
-		}
-		String s = b.toString();
-		if (s.length() > 0)
-			s = s.substring(0, s.length()-1);
-		else
-			s = "null";
-		Main.pref.put("toolbar", s);
-		refreshToolbarControl();
-	}
-
-	/**
-	 * @return The parameter (for better chaining)
-	 */
-	public Action register(Action action) {
-		actions.put((String)action.getValue("toolbar"), action);
-		return action;
-	}
-
-	/**
-	 * Parse the toolbar preference setting and construct the toolbar GUI control.
-	 * 
-	 * Call this, if anything has changed in the toolbar settings and you want to refresh 
-	 * the toolbar content (e.g. after registering actions in a plugin)
-	 */
-	public void refreshToolbarControl() {
-		control.removeAll();
-		for (String s : getToolString()) {
-			if (s.equals("|"))
-				control.addSeparator();
-			else
-				control.add(actions.get(s));
-		}
-		control.setVisible(control.getComponentCount() != 0);
-	}
+    private final class Move implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            if (e.getActionCommand().equals("<<")) {
+                while (unselected.size() > 1) {
+                    selected.addElement(unselected.get(0));
+                    unselected.remove(0);
+                }
+            } else if (e.getActionCommand().equals("<") && unselectedList.getSelectedIndex() != -1) {
+                while (unselectedList.getSelectedIndex() != -1 && unselectedList.getSelectedIndex() != unselected.size()-1) {
+                    selected.addElement(unselectedList.getSelectedValue());
+                    unselected.remove(unselectedList.getSelectedIndex());
+                }
+                if (unselectedList.getSelectedIndex() == unselected.size()-1)
+                    selected.addElement(null);
+            } else if (e.getActionCommand().equals(">") && selectedList.getSelectedIndex() != -1) {
+                while (selectedList.getSelectedIndex() != -1) {
+                    if (selectedList.getSelectedValue() != null)
+                        unselected.add(unselected.size()-1, selectedList.getSelectedValue());
+                    selected.remove(selectedList.getSelectedIndex());
+                }
+            } else if (e.getActionCommand().equals(">>")) {
+                while (selected.size() > 0) {
+                    if (selected.get(0) != null)
+                        unselected.add(unselected.size()-1, selected.get(0));
+                    selected.remove(0);
+                }
+            } else if (e.getActionCommand().equals("up")) {
+                int i = selectedList.getSelectedIndex();
+                Object o = selected.get(i);
+                if (i != 0) {
+                    selected.remove(i);
+                    selected.add(i-1, o);
+                    selectedList.setSelectedIndex(i-1);
+                }
+            } else if (e.getActionCommand().equals("down")) {
+                int i = selectedList.getSelectedIndex();
+                Object o = selected.get(i);
+                if (i != selected.size()-1) {
+                    selected.remove(i);
+                    selected.add(i+1, o);
+                    selectedList.setSelectedIndex(i+1);
+                }
+            }
+        }
+    }
+    private Move moveAction = new Move();
+
+    /**
+     * Key: Registered name (property "toolbar" of action).
+     * Value: The action to execute.
+     */
+    private Map<String, Action> actions = new HashMap<String, Action>();
+
+    private DefaultListModel selected = new DefaultListModel();
+    private DefaultListModel unselected = new DefaultListModel();
+    private JList selectedList = new JList(selected);
+    private JList unselectedList = new JList(unselected);
+
+    public JToolBar control = new JToolBar();
+
+    private JButton upButton;
+    private JButton downButton;
+
+    public ToolbarPreferences() {
+        control.setFloatable(false);
+
+        final ListCellRenderer oldRenderer = selectedList.getCellRenderer();
+        ListCellRenderer renderer = new DefaultListCellRenderer(){
+            @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                String s = tr("Separator");
+                Icon i = ImageProvider.get("preferences/separator");
+                if (value != null) {
+                    s = (String)((Action)value).getValue(Action.NAME);
+                    i = (Icon)((Action)value).getValue(Action.SMALL_ICON);
+                }
+                JLabel l = (JLabel)oldRenderer.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
+                l.setIcon(i);
+                return l;
+            }
+        };
+        selectedList.setCellRenderer(renderer);
+        unselectedList.setCellRenderer(renderer);
+
+        unselectedList.addListSelectionListener(new ListSelectionListener(){
+            public void valueChanged(ListSelectionEvent e) {
+                if ((unselectedList.getSelectedIndex() != -1))
+                    selectedList.clearSelection();
+                upButton.setEnabled(selectedList.getSelectedIndex() != -1);
+                downButton.setEnabled(selectedList.getSelectedIndex() != -1);
+            }
+        });
+        selectedList.addListSelectionListener(new ListSelectionListener(){
+            public void valueChanged(ListSelectionEvent e) {
+                boolean sel = selectedList.getSelectedIndex() != -1;
+                if (sel)
+                    unselectedList.clearSelection();
+                upButton.setEnabled(sel);
+                downButton.setEnabled(sel);
+            }
+        });
+    }
+
+    public void addGui(PreferenceDialog gui) {
+        selected.removeAllElements();
+        unselected.removeAllElements();
+        Map<String, Action> us = new TreeMap<String, Action>();
+        for (Action a : actions.values())
+        {
+            us.put(a.getValue(Action.NAME).toString()+a.toString(), a);
+        }
+        for (String a : us.keySet())
+            unselected.addElement(us.get(a));
+        unselected.addElement(null);
+
+        final JPanel left = new JPanel(new GridBagLayout());
+        left.add(new JLabel(tr("Toolbar")), GBC.eol());
+        left.add(new JScrollPane(selectedList), GBC.std().fill(GBC.BOTH));
+
+        final JPanel right = new JPanel(new GridBagLayout());
+        right.add(new JLabel(tr("Available")), GBC.eol());
+        right.add(new JScrollPane(unselectedList), GBC.eol().fill(GBC.BOTH));
+
+        final JPanel buttons = new JPanel(new GridLayout(6,1));
+        buttons.add(upButton = createButton("up"));
+        buttons.add(createButton("<<"));
+        buttons.add(createButton("<"));
+        buttons.add(createButton(">"));
+        buttons.add(createButton(">>"));
+        buttons.add(downButton = createButton("down"));
+        upButton.setEnabled(false);
+        downButton.setEnabled(false);
+
+        final JPanel p = new JPanel();
+        p.setLayout(new LayoutManager(){
+            public void addLayoutComponent(String name, Component comp) {}
+            public void removeLayoutComponent(Component comp) {}
+            public Dimension minimumLayoutSize(Container parent) {
+                Dimension l = left.getMinimumSize();
+                Dimension r = right.getMinimumSize();
+                Dimension b = buttons.getMinimumSize();
+                return new Dimension(l.width+b.width+10+r.width,l.height+b.height+10+r.height);
+            }
+            public Dimension preferredLayoutSize(Container parent) {
+                Dimension l = left.getPreferredSize();
+                Dimension r = right.getPreferredSize();
+                return new Dimension(l.width+r.width+10+buttons.getPreferredSize().width,Math.max(l.height, r.height));
+            }
+            public void layoutContainer(Container parent) {
+                Dimension d = p.getSize();
+                Dimension b = buttons.getPreferredSize();
+                int width = (d.width-10-b.width)/2;
+                left.setBounds(new Rectangle(0,0,width,d.height));
+                right.setBounds(new Rectangle(width+10+b.width,0,width,d.height));
+                buttons.setBounds(new Rectangle(width+5, d.height/2-b.height/2, b.width, b.height));
+            }
+        });
+        p.add(left);
+        p.add(buttons);
+        p.add(right);
+
+        JPanel panel = gui.createPreferenceTab("toolbar", tr("Toolbar customization"),
+                tr("Customize the elements on the toolbar."), false);
+        panel.add(p, GBC.eol().fill(GBC.BOTH));
+
+        for (String s : getToolString()) {
+            if (s.equals("|"))
+                selected.addElement(null);
+            else {
+                Action a = actions.get(s);
+                if (a != null) {
+                    selected.addElement(a);
+                    unselected.removeElement(a);
+                }
+            }
+        }
+    }
+
+    private String[] getToolString() {
+        String s = Main.pref.get("toolbar", "open;save;exportgpx;|;download;upload;|;undo;redo;|;preference");
+        if (s == null || s.equals("null") || s.equals(""))
+            return new String[0];
+        return s.split(";");
+    }
+
+    private JButton createButton(String name) {
+        JButton b = new JButton();
+        if (name.equals("up"))
+            b.setIcon(ImageProvider.get("dialogs", "up"));
+        else if (name.equals("down"))
+            b.setIcon(ImageProvider.get("dialogs", "down"));
+        else
+            b.setText(name);
+        b.addActionListener(moveAction);
+        b.setActionCommand(name);
+        return b;
+    }
+
+    public void ok() {
+        StringBuilder b = new StringBuilder();
+        for (int i = 0; i < selected.size(); ++i) {
+            if (selected.get(i) == null)
+                b.append("|");
+            else
+                b.append(((Action)selected.get(i)).getValue("toolbar"));
+            b.append(";");
+        }
+        String s = b.toString();
+        if (s.length() > 0)
+            s = s.substring(0, s.length()-1);
+        else
+            s = "null";
+        Main.pref.put("toolbar", s);
+        refreshToolbarControl();
+    }
+
+    /**
+     * @return The parameter (for better chaining)
+     */
+    public Action register(Action action) {
+        actions.put((String)action.getValue("toolbar"), action);
+        return action;
+    }
+
+    /**
+     * Parse the toolbar preference setting and construct the toolbar GUI control.
+     *
+     * Call this, if anything has changed in the toolbar settings and you want to refresh
+     * the toolbar content (e.g. after registering actions in a plugin)
+     */
+    public void refreshToolbarControl() {
+        control.removeAll();
+        for (String s : getToolString()) {
+            if (s.equals("|"))
+                control.addSeparator();
+            else
+                control.add(actions.get(s));
+        }
+        control.setVisible(control.getComponentCount() != 0);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/prefJPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/prefJPanel.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/prefJPanel.java	(revision 1169)
@@ -29,73 +29,73 @@
 public class prefJPanel extends javax.swing.JPanel {
 
-		// table of shortcuts
-		private TableModel model;
-		// comboboxes of modifier groups, mapping selectedIndex to real data
-		private static int[] modifInts = new int[]{
-			-1,
-			0,
-			KeyEvent.SHIFT_DOWN_MASK,
-			KeyEvent.CTRL_DOWN_MASK,
-			KeyEvent.ALT_DOWN_MASK,
-			KeyEvent.META_DOWN_MASK,
-			KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-			KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-			KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
-			KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
-			KeyEvent.CTRL_DOWN_MASK | KeyEvent.META_DOWN_MASK,
-			KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK,
-			KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
-			KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK
-		};
-		// and here are the texts fro the comboboxes
-		private static String[] modifList = new String[] {
-			tr("disabled"),
-			tr("no modifier"),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[2]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[3]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[4]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[5]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[6]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[7]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[8]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[9]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[10]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[11]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[12]).getModifiers()),
-			KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[13]).getModifiers())
-		};
-		// this are the display(!) texts for the checkboxes. Let the JVM do the i18n for us <g>.
-		// Ok, there's a real reason for this: The JVM should know best how the keys are labelled
-		// on the physical keyboard. What language pack is installed in JOSM is completely
-		// independent from the keyboard's labelling. But the operation system's locale
-		// usually matches the keyboard. This even works with my English Windows and my German
-		// keyboard.
-		private static String SHIFT = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.SHIFT_DOWN_MASK).getModifiers());
-		private static String CTRL  = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK).getModifiers());
-		private static String ALT   = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_DOWN_MASK).getModifiers());
-		private static String META  = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK).getModifiers());
-
-		// A list of keys to present the user. Sadly this really is a list of keys Java knows about,
-		// not a list of real physical keys. If someone knows how to get that list?
-		private static Map<Integer, String> keyList = setKeyList();
-
-		private static Map<Integer, String> setKeyList() {
-			Map<Integer, String> list = new LinkedHashMap<Integer, String>();
-			// I hate this, but I found no alternative...
-			for (int i = 0; i < 65534; i++) {
-				String s = KeyEvent.getKeyText(i);
-				if (s != null && s.length() > 0 && !s.contains("Unknown")) {
-					list.put(new Integer(i), s);
-					//System.out.println(i+": "+s);
-				}
-			}
-			list.put(new Integer(-1), "");
-			return list;
-		}
+        // table of shortcuts
+        private TableModel model;
+        // comboboxes of modifier groups, mapping selectedIndex to real data
+        private static int[] modifInts = new int[]{
+            -1,
+            0,
+            KeyEvent.SHIFT_DOWN_MASK,
+            KeyEvent.CTRL_DOWN_MASK,
+            KeyEvent.ALT_DOWN_MASK,
+            KeyEvent.META_DOWN_MASK,
+            KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+            KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+            KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
+            KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
+            KeyEvent.CTRL_DOWN_MASK | KeyEvent.META_DOWN_MASK,
+            KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK,
+            KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK,
+            KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK
+        };
+        // and here are the texts fro the comboboxes
+        private static String[] modifList = new String[] {
+            tr("disabled"),
+            tr("no modifier"),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[2]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[3]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[4]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[5]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[6]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[7]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[8]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[9]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[10]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[11]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[12]).getModifiers()),
+            KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, modifInts[13]).getModifiers())
+        };
+        // this are the display(!) texts for the checkboxes. Let the JVM do the i18n for us <g>.
+        // Ok, there's a real reason for this: The JVM should know best how the keys are labelled
+        // on the physical keyboard. What language pack is installed in JOSM is completely
+        // independent from the keyboard's labelling. But the operation system's locale
+        // usually matches the keyboard. This even works with my English Windows and my German
+        // keyboard.
+        private static String SHIFT = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.SHIFT_DOWN_MASK).getModifiers());
+        private static String CTRL  = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK).getModifiers());
+        private static String ALT   = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_DOWN_MASK).getModifiers());
+        private static String META  = KeyEvent.getKeyModifiersText(javax.swing.KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.META_DOWN_MASK).getModifiers());
+
+        // A list of keys to present the user. Sadly this really is a list of keys Java knows about,
+        // not a list of real physical keys. If someone knows how to get that list?
+        private static Map<Integer, String> keyList = setKeyList();
+
+        private static Map<Integer, String> setKeyList() {
+            Map<Integer, String> list = new LinkedHashMap<Integer, String>();
+            // I hate this, but I found no alternative...
+            for (int i = 0; i < 65534; i++) {
+                String s = KeyEvent.getKeyText(i);
+                if (s != null && s.length() > 0 && !s.contains("Unknown")) {
+                    list.put(new Integer(i), s);
+                    //System.out.println(i+": "+s);
+                }
+            }
+            list.put(new Integer(-1), "");
+            return list;
+        }
 
     /** Creates new form prefJPanel */
     // Ain't those auto-generated comments helpful or what? <g>
     public prefJPanel(TableModel model) {
-    	this.model = model;
+        this.model = model;
         initComponents();
     }
@@ -156,33 +156,33 @@
         setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
 
-				// If someone wants to move this text into some resource, feel free.
-				infoTab.setLayout(new javax.swing.BoxLayout(shortcutTab, javax.swing.BoxLayout.Y_AXIS));
-				JEditorPane editor = new JEditorPane();
-				editor.setEditable(false);
-				editor.setContentType("text/html");
-				editor.setText(
-					tr("<h1><a name=\"top\">Keyboard Shortcuts</a></h1>")+
-					tr("<p>Please note that shortcuts keys are assigned to the actions when JOSM is started. So you need to <b>restart</b> "
-					  +"JOSM to see your changes.</p>")+
-					tr("<p>Furthermore, the shortcuts are activated when the actions are assigned to a menu entry of button for the first "
-					  +"time. So some of your changes may become active even without restart --- but also without collistion handling. "
-					  +"This is another reason to <b>restart</b> JOSM after making any changes here.</p>")+
-					tr("<p>You may notice that the key selection list on the next page lists all keys that exist on all kinds of keyboards "
-					  +"Java knows about, not just those keys that exist on your keyboard. Please use only those values that correspond to "
-					  +"a real key on your keyboard. So if your keyboard has no 'Copy' key (PC keyboard don't have them, Sun keyboards do), "
-					  +"the do not use it. Also there will be 'keys' listed that correspond to a shortcut on your keyboard (e.g. ':'/Colon). "
-					  +"Please also do not use them, use the base key (';'/Semicolon on US keyboards, '.'/Period on German keyboards, ...) "
-					  +"instead. Not doing so may result in conflicts, as there is no way for JOSM to know that Ctrl+Shift+; and Ctrl+: "
-					  +"actually is the same thing on an US keyboard...</p>")+
-					tr("<p>Thank you for your understanding</p>")+
-					tr("<h1>Modifier Groups</h1>")+
-					tr("<p>The last page lists the modifier keys JOSM will automatically assign to shortcuts. For every of the four kinds "
-					  +"of shortcuts there are three alternatives. JOSM will try those alternative in the listed order when managing a "
-					  +"conflict. If all alternatives would result in shortcuts that are already taken, it will assign a random shortcut "
-					  +"instead.</p>")+
-					tr("<p>The pseudo-modifier 'disabled' will disable the shortcut when encountered.</p>")
-				);
-				editor.setCaretPosition(0); // scroll up
-				prefTabPane.addTab(tr("Read First"), new JScrollPane(editor));
+                // If someone wants to move this text into some resource, feel free.
+                infoTab.setLayout(new javax.swing.BoxLayout(shortcutTab, javax.swing.BoxLayout.Y_AXIS));
+                JEditorPane editor = new JEditorPane();
+                editor.setEditable(false);
+                editor.setContentType("text/html");
+                editor.setText(
+                    tr("<h1><a name=\"top\">Keyboard Shortcuts</a></h1>")+
+                    tr("<p>Please note that shortcuts keys are assigned to the actions when JOSM is started. So you need to <b>restart</b> "
+                      +"JOSM to see your changes.</p>")+
+                    tr("<p>Furthermore, the shortcuts are activated when the actions are assigned to a menu entry of button for the first "
+                      +"time. So some of your changes may become active even without restart --- but also without collistion handling. "
+                      +"This is another reason to <b>restart</b> JOSM after making any changes here.</p>")+
+                    tr("<p>You may notice that the key selection list on the next page lists all keys that exist on all kinds of keyboards "
+                      +"Java knows about, not just those keys that exist on your keyboard. Please use only those values that correspond to "
+                      +"a real key on your keyboard. So if your keyboard has no 'Copy' key (PC keyboard don't have them, Sun keyboards do), "
+                      +"the do not use it. Also there will be 'keys' listed that correspond to a shortcut on your keyboard (e.g. ':'/Colon). "
+                      +"Please also do not use them, use the base key (';'/Semicolon on US keyboards, '.'/Period on German keyboards, ...) "
+                      +"instead. Not doing so may result in conflicts, as there is no way for JOSM to know that Ctrl+Shift+; and Ctrl+: "
+                      +"actually is the same thing on an US keyboard...</p>")+
+                    tr("<p>Thank you for your understanding</p>")+
+                    tr("<h1>Modifier Groups</h1>")+
+                    tr("<p>The last page lists the modifier keys JOSM will automatically assign to shortcuts. For every of the four kinds "
+                      +"of shortcuts there are three alternatives. JOSM will try those alternative in the listed order when managing a "
+                      +"conflict. If all alternatives would result in shortcuts that are already taken, it will assign a random shortcut "
+                      +"instead.</p>")+
+                    tr("<p>The pseudo-modifier 'disabled' will disable the shortcut when encountered.</p>")
+                );
+                editor.setCaretPosition(0); // scroll up
+                prefTabPane.addTab(tr("Read First"), new JScrollPane(editor));
 
         shortcutTab.setLayout(new javax.swing.BoxLayout(shortcutTab, javax.swing.BoxLayout.Y_AXIS));
@@ -342,19 +342,19 @@
         subwindowGroupPane.add(bxTer4);
 
-				initbx();
-				bxPrim1.setAction(action2);
-				bxSec1.setAction(action2);
-				bxTer1.setAction(action2);
-				bxPrim2.setAction(action2);
-				bxSec2.setAction(action2);
-				bxTer2.setAction(action2);
-				bxPrim3.setAction(action2);
-				bxSec3.setAction(action2);
-				bxTer3.setAction(action2);
-				bxPrim4.setAction(action2);
-				bxSec4.setAction(action2);
-				bxTer4.setAction(action2);
-
-		modifierTab.add(subwindowGroupPane);
+                initbx();
+                bxPrim1.setAction(action2);
+                bxSec1.setAction(action2);
+                bxTer1.setAction(action2);
+                bxPrim2.setAction(action2);
+                bxSec2.setAction(action2);
+                bxTer2.setAction(action2);
+                bxPrim3.setAction(action2);
+                bxSec3.setAction(action2);
+                bxTer3.setAction(action2);
+                bxPrim4.setAction(action2);
+                bxSec4.setAction(action2);
+                bxTer4.setAction(action2);
+
+        modifierTab.add(subwindowGroupPane);
 
         prefTabPane.addTab(tr("Modifier Groups"), modifierScroller);
@@ -363,147 +363,147 @@
     }
 
-	// this allows to edit shortcuts. it:
-	//  * sets the edit controls to the selected shortcut
-	//  * enabled/disables the controls as needed
-	//  * writes the user's changes to the shortcut
-	// And after I finally had it working, I realized that those two methods
-	// are playing ping-pong (politically correct: table tennis, I know) and
-	// even have some duplicated code. Feel free to refactor, If you have
-	// more expirience with GUI coding than I have.
-	private class cbAction extends javax.swing.AbstractAction implements ListSelectionListener {
-		private prefJPanel panel;
-			public cbAction (prefJPanel panel) {
-				this.panel = panel;
-		}
-		public void valueChanged(ListSelectionEvent e) {
-			ListSelectionModel lsm = panel.shortcutTable.getSelectionModel(); // can't use e here
-			if (!lsm.isSelectionEmpty()) {
-				int row = lsm.getMinSelectionIndex();
-				Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
-				panel.cbDefault.setSelected(!sc.getAssignedUser());
-				panel.cbDisable.setSelected(sc.getKeyStroke() == null);
-				panel.cbShift.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.SHIFT_DOWN_MASK) != 0);
-				panel.cbCtrl.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.CTRL_DOWN_MASK) != 0);
-				panel.cbAlt.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.ALT_DOWN_MASK) != 0);
-				panel.cbMeta.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.META_DOWN_MASK) != 0);
-				if (sc.getKeyStroke() != null) {
-					tfKey.setSelectedItem(keyList.get(sc.getKeyStroke().getKeyCode()));
-				} else {
-					tfKey.setSelectedItem(keyList.get(-1));
-				}
-				if (sc.getAutomatic()) {
-					panel.cbDefault.setEnabled(false);
-					panel.cbDisable.setEnabled(false);
-					panel.cbShift.setEnabled(false);
-					panel.cbCtrl.setEnabled(false);
-					panel.cbAlt.setEnabled(false);
-					panel.cbMeta.setEnabled(false);
-					panel.tfKey.setEnabled(false);
-				} else {
-					panel.cbDefault.setEnabled(true);
-					actionPerformed(null);
-				}
-			} else {
-				panel.cbDefault.setEnabled(false);
-				panel.cbDisable.setEnabled(false);
-				panel.cbShift.setEnabled(false);
-				panel.cbCtrl.setEnabled(false);
-				panel.cbAlt.setEnabled(false);
-				panel.cbMeta.setEnabled(false);
-				panel.tfKey.setEnabled(false);
-			}
-		}
-		public void actionPerformed(java.awt.event.ActionEvent e) {
-			ListSelectionModel lsm = panel.shortcutTable.getSelectionModel();
-			if (lsm != null && !lsm.isSelectionEmpty()) {
-				if (e != null) { // only if we've been called by a user action
-					int row = lsm.getMinSelectionIndex();
-					Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
-					sc.setAssignedUser(!panel.cbDefault.isSelected());
-					if (panel.cbDisable.isSelected()) {
-						sc.setAssignedModifier(-1);
-					} else if (panel.tfKey.getSelectedItem().equals("")) {
-						sc.setAssignedModifier(KeyEvent.VK_CANCEL);
-					} else {
-						sc.setAssignedModifier(
-							(panel.cbShift.isSelected() ? KeyEvent.SHIFT_DOWN_MASK : 0) |
-							(panel.cbCtrl.isSelected() ? KeyEvent.CTRL_DOWN_MASK : 0) |
-							(panel.cbAlt.isSelected() ? KeyEvent.ALT_DOWN_MASK : 0) |
-							(panel.cbMeta.isSelected() ? KeyEvent.META_DOWN_MASK : 0)
-						);
-						for (Map.Entry<Integer, String> entry : keyList.entrySet()) {
-							if (entry.getValue().equals(panel.tfKey.getSelectedItem())) {
-								sc.setAssignedKey(entry.getKey());
-							}
-						}
-					}
-					valueChanged(null);
-				}
-				boolean state = !panel.cbDefault.isSelected();
-				panel.cbDisable.setEnabled(state);
-				state = state && !panel.cbDisable.isSelected();
-				panel.cbShift.setEnabled(state);
-				panel.cbCtrl.setEnabled(state);
-				panel.cbAlt.setEnabled(state);
-				panel.cbMeta.setEnabled(state);
-				panel.tfKey.setEnabled(state);
-			} else {
-				panel.cbDefault.setEnabled(false);
-				panel.cbDisable.setEnabled(false);
-				panel.cbShift.setEnabled(false);
-				panel.cbCtrl.setEnabled(false);
-				panel.cbAlt.setEnabled(false);
-				panel.cbMeta.setEnabled(false);
-				panel.tfKey.setEnabled(false);
-			}
-		}
-	}
-
-	// this handles the modifier groups
-	private class bxAction extends javax.swing.AbstractAction {
-		public void actionPerformed(java.awt.event.ActionEvent e) {
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString( modifInts[bxPrim1.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT),    Integer.toString( modifInts[ bxSec1.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT),    Integer.toString( modifInts[ bxTer1.getSelectedIndex()] ));
-
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString( modifInts[bxPrim2.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU),    Integer.toString( modifInts[ bxSec2.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU),    Integer.toString( modifInts[ bxTer2.getSelectedIndex()] ));
-
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[bxPrim3.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[ bxSec3.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[ bxTer3.getSelectedIndex()] ));
-
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString( modifInts[bxPrim4.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER),   Integer.toString( modifInts[ bxSec4.getSelectedIndex()] ));
-			Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER),   Integer.toString( modifInts[ bxTer4.getSelectedIndex()] ));
-		}
-	}
-
-	private void initbx() {
-		setBx(bxPrim1, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT));
-		setBx(bxSec1,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT));
-		setBx(bxTer1,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT));
-
-		setBx(bxPrim2, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU));
-		setBx(bxSec2,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU));
-		setBx(bxTer2,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU));
-
-		setBx(bxPrim3, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY));
-		setBx(bxSec3,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY));
-		setBx(bxTer3,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY));
-
-		setBx(bxPrim4, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER));
-		setBx(bxSec4,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER));
-		setBx(bxTer4,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER));
-	}
-	private void setBx(javax.swing.JComboBox bx, String key) {
-		int target = Main.pref.getInteger(key, -1);
-		for (int i = 0; i < modifInts.length; i++) {
-			if (modifInts[i] == target) {
-				bx.setSelectedIndex(i);
-			}
-		}
-	}
+    // this allows to edit shortcuts. it:
+    //  * sets the edit controls to the selected shortcut
+    //  * enabled/disables the controls as needed
+    //  * writes the user's changes to the shortcut
+    // And after I finally had it working, I realized that those two methods
+    // are playing ping-pong (politically correct: table tennis, I know) and
+    // even have some duplicated code. Feel free to refactor, If you have
+    // more expirience with GUI coding than I have.
+    private class cbAction extends javax.swing.AbstractAction implements ListSelectionListener {
+        private prefJPanel panel;
+            public cbAction (prefJPanel panel) {
+                this.panel = panel;
+        }
+        public void valueChanged(ListSelectionEvent e) {
+            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel(); // can't use e here
+            if (!lsm.isSelectionEmpty()) {
+                int row = lsm.getMinSelectionIndex();
+                Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
+                panel.cbDefault.setSelected(!sc.getAssignedUser());
+                panel.cbDisable.setSelected(sc.getKeyStroke() == null);
+                panel.cbShift.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.SHIFT_DOWN_MASK) != 0);
+                panel.cbCtrl.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.CTRL_DOWN_MASK) != 0);
+                panel.cbAlt.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.ALT_DOWN_MASK) != 0);
+                panel.cbMeta.setSelected(sc.getAssignedModifier() != -1 && (sc.getAssignedModifier() & KeyEvent.META_DOWN_MASK) != 0);
+                if (sc.getKeyStroke() != null) {
+                    tfKey.setSelectedItem(keyList.get(sc.getKeyStroke().getKeyCode()));
+                } else {
+                    tfKey.setSelectedItem(keyList.get(-1));
+                }
+                if (sc.getAutomatic()) {
+                    panel.cbDefault.setEnabled(false);
+                    panel.cbDisable.setEnabled(false);
+                    panel.cbShift.setEnabled(false);
+                    panel.cbCtrl.setEnabled(false);
+                    panel.cbAlt.setEnabled(false);
+                    panel.cbMeta.setEnabled(false);
+                    panel.tfKey.setEnabled(false);
+                } else {
+                    panel.cbDefault.setEnabled(true);
+                    actionPerformed(null);
+                }
+            } else {
+                panel.cbDefault.setEnabled(false);
+                panel.cbDisable.setEnabled(false);
+                panel.cbShift.setEnabled(false);
+                panel.cbCtrl.setEnabled(false);
+                panel.cbAlt.setEnabled(false);
+                panel.cbMeta.setEnabled(false);
+                panel.tfKey.setEnabled(false);
+            }
+        }
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            ListSelectionModel lsm = panel.shortcutTable.getSelectionModel();
+            if (lsm != null && !lsm.isSelectionEmpty()) {
+                if (e != null) { // only if we've been called by a user action
+                    int row = lsm.getMinSelectionIndex();
+                    Shortcut sc = (Shortcut)panel.model.getValueAt(row, -1);
+                    sc.setAssignedUser(!panel.cbDefault.isSelected());
+                    if (panel.cbDisable.isSelected()) {
+                        sc.setAssignedModifier(-1);
+                    } else if (panel.tfKey.getSelectedItem().equals("")) {
+                        sc.setAssignedModifier(KeyEvent.VK_CANCEL);
+                    } else {
+                        sc.setAssignedModifier(
+                            (panel.cbShift.isSelected() ? KeyEvent.SHIFT_DOWN_MASK : 0) |
+                            (panel.cbCtrl.isSelected() ? KeyEvent.CTRL_DOWN_MASK : 0) |
+                            (panel.cbAlt.isSelected() ? KeyEvent.ALT_DOWN_MASK : 0) |
+                            (panel.cbMeta.isSelected() ? KeyEvent.META_DOWN_MASK : 0)
+                        );
+                        for (Map.Entry<Integer, String> entry : keyList.entrySet()) {
+                            if (entry.getValue().equals(panel.tfKey.getSelectedItem())) {
+                                sc.setAssignedKey(entry.getKey());
+                            }
+                        }
+                    }
+                    valueChanged(null);
+                }
+                boolean state = !panel.cbDefault.isSelected();
+                panel.cbDisable.setEnabled(state);
+                state = state && !panel.cbDisable.isSelected();
+                panel.cbShift.setEnabled(state);
+                panel.cbCtrl.setEnabled(state);
+                panel.cbAlt.setEnabled(state);
+                panel.cbMeta.setEnabled(state);
+                panel.tfKey.setEnabled(state);
+            } else {
+                panel.cbDefault.setEnabled(false);
+                panel.cbDisable.setEnabled(false);
+                panel.cbShift.setEnabled(false);
+                panel.cbCtrl.setEnabled(false);
+                panel.cbAlt.setEnabled(false);
+                panel.cbMeta.setEnabled(false);
+                panel.tfKey.setEnabled(false);
+            }
+        }
+    }
+
+    // this handles the modifier groups
+    private class bxAction extends javax.swing.AbstractAction {
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString( modifInts[bxPrim1.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT),    Integer.toString( modifInts[ bxSec1.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT),    Integer.toString( modifInts[ bxTer1.getSelectedIndex()] ));
+
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString( modifInts[bxPrim2.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU),    Integer.toString( modifInts[ bxSec2.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU),    Integer.toString( modifInts[ bxTer2.getSelectedIndex()] ));
+
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[bxPrim3.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[ bxSec3.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY),  Integer.toString( modifInts[ bxTer3.getSelectedIndex()] ));
+
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString( modifInts[bxPrim4.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER),   Integer.toString( modifInts[ bxSec4.getSelectedIndex()] ));
+            Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER),   Integer.toString( modifInts[ bxTer4.getSelectedIndex()] ));
+        }
+    }
+
+    private void initbx() {
+        setBx(bxPrim1, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT));
+        setBx(bxSec1,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_EDIT));
+        setBx(bxTer1,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_EDIT));
+
+        setBx(bxPrim2, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU));
+        setBx(bxSec2,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_MENU));
+        setBx(bxTer2,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_MENU));
+
+        setBx(bxPrim3, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY));
+        setBx(bxSec3,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_HOTKEY));
+        setBx(bxTer3,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_HOTKEY));
+
+        setBx(bxPrim4, "shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER));
+        setBx(bxSec4,  "shortcut.groups."+(Shortcut.GROUPS_ALT1   +Shortcut.GROUP_LAYER));
+        setBx(bxTer4,  "shortcut.groups."+(Shortcut.GROUPS_ALT2   +Shortcut.GROUP_LAYER));
+    }
+    private void setBx(javax.swing.JComboBox bx, String key) {
+        int target = Main.pref.getInteger(key, -1);
+        for (int i = 0; i < modifInts.length; i++) {
+            if (modifInts[i] == target) {
+                bx.setSelectedIndex(i);
+            }
+        }
+    }
 
     private javax.swing.JComboBox bxPrim1;
Index: trunk/src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java	(revision 1169)
@@ -13,17 +13,17 @@
  */
 public final class ForwardActionListener implements ActionListener {
-	public final TaggingPreset preset;
+    public final TaggingPreset preset;
 
-	private final PropertiesDialog propertiesDialog;
+    private final PropertiesDialog propertiesDialog;
 
-	public ForwardActionListener(PropertiesDialog propertiesDialog, TaggingPreset preset) {
-		this.propertiesDialog = propertiesDialog;
-		this.preset = preset;
-	}
+    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);
-	}
+    public void actionPerformed(ActionEvent e) {
+        this.propertiesDialog.taggingPresets.setSelectedIndex(0);
+        e.setSource(this);
+        preset.actionPerformed(e);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java	(revision 1169)
@@ -15,32 +15,32 @@
 
 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;
-	}
+    @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: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 1169)
@@ -50,526 +50,526 @@
  * 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 TaggingPresetMenu group = null;
-	public String name;
-
-	public static abstract class Item {
-		public boolean focus = false;
-		abstract void addToPanel(JPanel p, Collection<OsmPrimitive> sel);
-		abstract void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds);
-		boolean requestFocusInWindow() {return false;}
-	}
-	
-	public static class Usage {
-		Set<String> values;
-		Boolean hadKeys = false;
-		Boolean hadEmpty = false;
-		public Boolean allSimilar()
-		{
-			return values.size() == 1 && !hadEmpty;
-		}
-		public Boolean unused()
-		{
-			return values.size() == 0;
-		}
-		public String getFirst()
-		{
-			return (String)(values.toArray()[0]);
-		}
-		public Boolean hadKeys()
-		{
-			return hadKeys;
-		}
-	}
-	
-	public static final String DIFFERENT = tr("<different>");
-	
-	static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
-		Usage returnValue = new Usage();
-		returnValue.values = new HashSet<String>();
-		for (OsmPrimitive s : sel) {
-			String v = s.get(key);
-			if (v != null)
-				returnValue.values.add(v);
-			else
-				returnValue.hadEmpty = true;
-			if(s.keys != null && s.keys.size() > 0)
-				returnValue.hadKeys = true;
-		}
-		return returnValue;
-	}
-
-	static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
-
-		Usage returnValue = new Usage();
-		returnValue.values = new HashSet<String>();
-		for (OsmPrimitive s : sel) {
-			returnValue.values.add(OsmUtils.getNamedOsmBoolean(s.get(key)));
-		}
-		return returnValue;
-	}
-	
-	public static class Text extends Item {
-		
-		public String key;
-		public String text;
-		public String locale_text;
-		public String default_;
-		public String originalValue;
-		public boolean use_last_as_default = false;
-		public boolean delete_if_empty = false;
-
-		private JComponent value;
-		
-		@Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
-			
-			// find out if our key is already used in the selection.
-			Usage usage = determineTextUsage(sel, key);
-			if (usage.unused())
-			{
-				value = new JTextField();
-				if (use_last_as_default && lastValue.containsKey(key)) {
-					((JTextField)value).setText(lastValue.get(key));
-				} else {
-					((JTextField)value).setText(default_);
-				}
-				originalValue = null;
-			} else if (usage.allSimilar()) {
-				// all objects use the same value
-				value = new JTextField();
-				for (String s : usage.values) ((JTextField) value).setText(s);
-				originalValue = ((JTextField)value).getText();
-			} else {
-				// the objects have different values
-				value = new JComboBox(usage.values.toArray());
-				((JComboBox)value).setEditable(true);
-				((JComboBox)value).getEditor().setItem(DIFFERENT);
-				originalValue = DIFFERENT;
-			}
-			if(locale_text == null)
-				locale_text = tr(text);
-			p.add(new JLabel(locale_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) {
-			
-			// return if unchanged
-			String v = (value instanceof JComboBox) ? 
-				((JComboBox)value).getEditor().getItem().toString() : 
-				((JTextField)value).getText();
-
-			if (use_last_as_default) lastValue.put(key, v);
-			if (v.equals(originalValue) || (originalValue == null && v.length() == 0)) return;
-
-			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 String locale_text;
-		public boolean default_ = false; // not used!
-		public boolean use_last_as_default = false;
-
-		private QuadStateCheckBox check;
-		private QuadStateCheckBox.State initialState;
-		
-		@Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
-			
-			// find out if our key is already used in the selection.
-			Usage usage = determineBooleanUsage(sel, key);
-
-			if(locale_text == null)
-				locale_text = tr(text);
-
-			String oneValue = null;
-			for (String s : usage.values) oneValue = s;
-			if (usage.values.size() < 2 && (oneValue == null || OsmUtils.trueval.equals(oneValue) || OsmUtils.falseval.equals(oneValue))) {
-				// all selected objects share the same value which is either true or false or unset, 
-				// we can display a standard check box.
-				initialState = OsmUtils.trueval.equals(oneValue) ? 
-							QuadStateCheckBox.State.SELECTED :
-							OsmUtils.falseval.equals(oneValue) ? 
-							QuadStateCheckBox.State.NOT_SELECTED :
-							QuadStateCheckBox.State.UNSET;
-				check = new QuadStateCheckBox(locale_text, initialState, 
-						new QuadStateCheckBox.State[] { 
-						QuadStateCheckBox.State.SELECTED,
-						QuadStateCheckBox.State.NOT_SELECTED,
-						QuadStateCheckBox.State.UNSET });
-			} else {
-				// the objects have different values, or one or more objects have something
-				// else than true/false. we display a quad-state check box
-				// in "partial" state.
-				initialState = QuadStateCheckBox.State.PARTIAL;
-				check = new QuadStateCheckBox(locale_text, QuadStateCheckBox.State.PARTIAL, 
-						new QuadStateCheckBox.State[] { 
-						QuadStateCheckBox.State.PARTIAL,
-						QuadStateCheckBox.State.SELECTED,
-						QuadStateCheckBox.State.NOT_SELECTED,
-						QuadStateCheckBox.State.UNSET });
-			}
-			p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
-		}
-		
-		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
-			// if the user hasn't changed anything, don't create a command.
-			if (check.getState() == initialState) return;
-			
-			// otherwise change things according to the selected value.
-			cmds.add(new ChangePropertyCommand(sel, key, 
-					check.getState() == QuadStateCheckBox.State.SELECTED ? OsmUtils.trueval :
-					check.getState() == QuadStateCheckBox.State.NOT_SELECTED ? OsmUtils.falseval :
-					null));
-		}
-		@Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
-	}
-
-	public static class Combo extends Item {
-		
-		public String key;
-		public String text;
-		public String locale_text;
-		public String values;
-		public String display_values;
-		public String locale_display_values;
-		public String default_;
-		public boolean delete_if_empty = false;
-		public boolean editable = true;
-		public boolean use_last_as_default = false;
-
-		private JComboBox combo;
-		private LinkedHashMap<String,String> lhm;
-		private Usage usage;
-		private String originalValue;
-		
-		@Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
-			
-			// find out if our key is already used in the selection.
-			usage = determineTextUsage(sel, key);
-			
-			String[] value_array = values.split(",");
-			String[] display_array;
-			if(locale_display_values != null)
-				display_array = locale_display_values.split(",");
-			else if(display_values != null)
-				display_array = display_values.split(",");
-			else
-				display_array = value_array;
-
-			lhm = new LinkedHashMap<String,String>();
-			if (!usage.allSimilar() && !usage.unused())
-			{
-				lhm.put(DIFFERENT, DIFFERENT);
-			}
-			for (int i=0; i<value_array.length; i++) {
-				lhm.put(value_array[i],
-				(locale_display_values == null) ?
-				tr(display_array[i]) : display_array[i]);
-			}
-			if(!usage.unused())
-			{
-				for (String s : usage.values) {
-					if (!lhm.containsKey(s)) lhm.put(s, s);
-				}
-			}
-			if (default_ != null && !lhm.containsKey(default_)) lhm.put(default_, default_);
-			if(!lhm.containsKey("")) lhm.put("", "");
-
-			combo = new JComboBox(lhm.values().toArray());
-			combo.setEditable(editable);
-			if (usage.allSimilar() && !usage.unused())
-			{
-				originalValue=usage.getFirst();
-				combo.setSelectedItem(lhm.get(originalValue));
-			}
-			// use default only in case it is a totally new entry
-			else if(default_ != null && !usage.hadKeys())
-			{
-				combo.setSelectedItem(default_);
-				originalValue=DIFFERENT;
-			}
-			else if(usage.unused())
-			{
-				combo.setSelectedItem("");
-				originalValue="";
-			}
-			else
-			{
-				combo.setSelectedItem(DIFFERENT);
-				originalValue=DIFFERENT;
-			}
-
-			if(locale_text == null)
-				locale_text = tr(text);
-			p.add(new JLabel(locale_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) {
-			Object obj = combo.getSelectedItem();
-			String display = (obj == null) ? null : obj.toString();
-			String value = null;
-			if(display == null && combo.isEditable())
-				display = combo.getEditor().getItem().toString();
-
-			if (display != null)
-			{
-				for (String key : lhm.keySet()) {
-					String k = lhm.get(key);
-					if (k != null && k.equals(display)) value=key;
-				}
-				if(value == null)
-					value = display;
-			}
-			else
-				value = "";
-
-			// no change if same as before
-			if (value.equals(originalValue) || (originalValue == null && (value == null || value.length() == 0))) return;
-			
-			if (delete_if_empty && value != null && value.length() == 0)
-				value = null;
-			cmds.add(new ChangePropertyCommand(sel, key, value));
-		}
-		@Override boolean requestFocusInWindow() {return combo.requestFocusInWindow();}
-	}
-
-	public static class Label extends Item {
-		public String text;
-		public String locale_text;
-
-		@Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
-			if(locale_text == null)
-				locale_text = tr(text);
-			p.add(new JLabel(locale_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, Collection<OsmPrimitive> sel) { }
-		@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;
-	public List<Item> data = new LinkedList<Item>();
-	private static HashMap<String,String> lastValue = new HashMap<String,String>();
-
-	/**
-	 * 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() {}
-
-	/**
-	 * Change the display name without changing the toolbar value.
-	 */
-	public void setDisplayName() {
-		putValue(Action.NAME, getName());
-		putValue("toolbar", "tagging_" + getRawName());
-		putValue(SHORT_DESCRIPTION, "<html>"+ (group != null ?
-		tr("Use preset ''{0}'' of group ''{1}''", tr(name), group.getName()) :
-		tr("Use preset ''{0}''", tr(name)))
-		+"</html>");
-	}
-
-	public String getName() {
-		return group != null ? group.getName() + "/" + tr(name) : tr(name);
-	}
-	public String getRawName() {
-		return group != null ? group.getRawName() + "/" + name : name;
-	}
-	/**
-	 * Called from the XML parser to set the icon
-	 * 
-	 * FIXME for Java 1.6 - use 24x24 icons for LARGE_ICON_KEY (button bar)
-	 * and the 16x16 icons for SMALL_ICON.
-	 */
-	public void setIcon(String iconName) {
-		String s = Main.pref.get("taggingpreset.iconpaths");
-		ImageIcon icon = ImageProvider.getIfAvailable((s != null ? s.split(";") : null), "presets", null, iconName);
-		if (icon == null)
-		{
-			System.out.println("Could not get presets icon " + iconName);
-			icon = new ImageIcon(iconName);
-		}
-		if (Math.max(icon.getIconHeight(), icon.getIconWidth()) != 16)
-			icon = new ImageIcon(icon.getImage().getScaledInstance(16, 16, 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(Reader in) throws SAXException {
-		XmlObjectParser parser = new XmlObjectParser();
-		parser.mapOnStart("item", TaggingPreset.class);
-		parser.mapOnStart("separator", TaggingPresetSeparator.class);
-		parser.mapBoth("group", TaggingPresetMenu.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>();
-		TaggingPresetMenu lastmenu = null;
-		parser.start(in);
-		while(parser.hasNext()) {
-			Object o = parser.next();
-			if (o instanceof TaggingPresetMenu) {
-				TaggingPresetMenu tp = (TaggingPresetMenu) o;
-				if(tp == lastmenu)
-					lastmenu = tp.group;
-				else
-				{
-					tp.setDisplayName();
-					tp.group = lastmenu;
-					lastmenu = tp;
-					all.add(tp);
-					Main.toolbar.register(tp);
-					
-				}
-			} else if (o instanceof TaggingPresetSeparator) {
-				TaggingPresetSeparator tp = (TaggingPresetSeparator) o;
-				tp.group = lastmenu;
-				all.add(tp);
-			} else if (o instanceof TaggingPreset) {
-				TaggingPreset tp = (TaggingPreset) o;
-				tp.group = lastmenu;
-				tp.setDisplayName();
-				all.add(tp);
-				Main.toolbar.register(tp);
-			} 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");
-		
-		if (Main.pref.getBoolean("taggingpreset.enable-defaults", true))
-		{
-			allTaggingPresets = "resource://presets/presets.xml"
-			+ (allTaggingPresets != null ? ";"+allTaggingPresets : "");
-		}
-		
-		for(String source : allTaggingPresets.split(";"))
-		{
-			try {
-				MirroredInputStream s = new MirroredInputStream(source);
-				InputStreamReader r;
-				try
-				{
-					r = new InputStreamReader(s, "UTF-8");
-				}
-				catch (UnsupportedEncodingException e)
-				{
-					r = new InputStreamReader(s);
-				}
-				allPresets.addAll(TaggingPreset.readAll(new BufferedReader(r)));
-			} 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(Collection<OsmPrimitive> selected) {
-		if (data == null)
-			return null;
-		JPanel p = new JPanel(new GridBagLayout());
-
-		for (Item i : data)
-			i.addToPanel(p, selected);
-		return p;
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		Collection<OsmPrimitive> sel = Main.ds.getSelected();
-		JPanel p = createPanel(sel);
-		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) {
-							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.undoRedo.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);
-	}
+    public TaggingPresetMenu group = null;
+    public String name;
+
+    public static abstract class Item {
+        public boolean focus = false;
+        abstract void addToPanel(JPanel p, Collection<OsmPrimitive> sel);
+        abstract void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds);
+        boolean requestFocusInWindow() {return false;}
+    }
+
+    public static class Usage {
+        Set<String> values;
+        Boolean hadKeys = false;
+        Boolean hadEmpty = false;
+        public Boolean allSimilar()
+        {
+            return values.size() == 1 && !hadEmpty;
+        }
+        public Boolean unused()
+        {
+            return values.size() == 0;
+        }
+        public String getFirst()
+        {
+            return (String)(values.toArray()[0]);
+        }
+        public Boolean hadKeys()
+        {
+            return hadKeys;
+        }
+    }
+
+    public static final String DIFFERENT = tr("<different>");
+
+    static Usage determineTextUsage(Collection<OsmPrimitive> sel, String key) {
+        Usage returnValue = new Usage();
+        returnValue.values = new HashSet<String>();
+        for (OsmPrimitive s : sel) {
+            String v = s.get(key);
+            if (v != null)
+                returnValue.values.add(v);
+            else
+                returnValue.hadEmpty = true;
+            if(s.keys != null && s.keys.size() > 0)
+                returnValue.hadKeys = true;
+        }
+        return returnValue;
+    }
+
+    static Usage determineBooleanUsage(Collection<OsmPrimitive> sel, String key) {
+
+        Usage returnValue = new Usage();
+        returnValue.values = new HashSet<String>();
+        for (OsmPrimitive s : sel) {
+            returnValue.values.add(OsmUtils.getNamedOsmBoolean(s.get(key)));
+        }
+        return returnValue;
+    }
+
+    public static class Text extends Item {
+
+        public String key;
+        public String text;
+        public String locale_text;
+        public String default_;
+        public String originalValue;
+        public boolean use_last_as_default = false;
+        public boolean delete_if_empty = false;
+
+        private JComponent value;
+
+        @Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
+
+            // find out if our key is already used in the selection.
+            Usage usage = determineTextUsage(sel, key);
+            if (usage.unused())
+            {
+                value = new JTextField();
+                if (use_last_as_default && lastValue.containsKey(key)) {
+                    ((JTextField)value).setText(lastValue.get(key));
+                } else {
+                    ((JTextField)value).setText(default_);
+                }
+                originalValue = null;
+            } else if (usage.allSimilar()) {
+                // all objects use the same value
+                value = new JTextField();
+                for (String s : usage.values) ((JTextField) value).setText(s);
+                originalValue = ((JTextField)value).getText();
+            } else {
+                // the objects have different values
+                value = new JComboBox(usage.values.toArray());
+                ((JComboBox)value).setEditable(true);
+                ((JComboBox)value).getEditor().setItem(DIFFERENT);
+                originalValue = DIFFERENT;
+            }
+            if(locale_text == null)
+                locale_text = tr(text);
+            p.add(new JLabel(locale_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) {
+
+            // return if unchanged
+            String v = (value instanceof JComboBox) ?
+                ((JComboBox)value).getEditor().getItem().toString() :
+                ((JTextField)value).getText();
+
+            if (use_last_as_default) lastValue.put(key, v);
+            if (v.equals(originalValue) || (originalValue == null && v.length() == 0)) return;
+
+            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 String locale_text;
+        public boolean default_ = false; // not used!
+        public boolean use_last_as_default = false;
+
+        private QuadStateCheckBox check;
+        private QuadStateCheckBox.State initialState;
+
+        @Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
+
+            // find out if our key is already used in the selection.
+            Usage usage = determineBooleanUsage(sel, key);
+
+            if(locale_text == null)
+                locale_text = tr(text);
+
+            String oneValue = null;
+            for (String s : usage.values) oneValue = s;
+            if (usage.values.size() < 2 && (oneValue == null || OsmUtils.trueval.equals(oneValue) || OsmUtils.falseval.equals(oneValue))) {
+                // all selected objects share the same value which is either true or false or unset,
+                // we can display a standard check box.
+                initialState = OsmUtils.trueval.equals(oneValue) ?
+                            QuadStateCheckBox.State.SELECTED :
+                            OsmUtils.falseval.equals(oneValue) ?
+                            QuadStateCheckBox.State.NOT_SELECTED :
+                            QuadStateCheckBox.State.UNSET;
+                check = new QuadStateCheckBox(locale_text, initialState,
+                        new QuadStateCheckBox.State[] {
+                        QuadStateCheckBox.State.SELECTED,
+                        QuadStateCheckBox.State.NOT_SELECTED,
+                        QuadStateCheckBox.State.UNSET });
+            } else {
+                // the objects have different values, or one or more objects have something
+                // else than true/false. we display a quad-state check box
+                // in "partial" state.
+                initialState = QuadStateCheckBox.State.PARTIAL;
+                check = new QuadStateCheckBox(locale_text, QuadStateCheckBox.State.PARTIAL,
+                        new QuadStateCheckBox.State[] {
+                        QuadStateCheckBox.State.PARTIAL,
+                        QuadStateCheckBox.State.SELECTED,
+                        QuadStateCheckBox.State.NOT_SELECTED,
+                        QuadStateCheckBox.State.UNSET });
+            }
+            p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
+        }
+
+        @Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+            // if the user hasn't changed anything, don't create a command.
+            if (check.getState() == initialState) return;
+
+            // otherwise change things according to the selected value.
+            cmds.add(new ChangePropertyCommand(sel, key,
+                    check.getState() == QuadStateCheckBox.State.SELECTED ? OsmUtils.trueval :
+                    check.getState() == QuadStateCheckBox.State.NOT_SELECTED ? OsmUtils.falseval :
+                    null));
+        }
+        @Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
+    }
+
+    public static class Combo extends Item {
+
+        public String key;
+        public String text;
+        public String locale_text;
+        public String values;
+        public String display_values;
+        public String locale_display_values;
+        public String default_;
+        public boolean delete_if_empty = false;
+        public boolean editable = true;
+        public boolean use_last_as_default = false;
+
+        private JComboBox combo;
+        private LinkedHashMap<String,String> lhm;
+        private Usage usage;
+        private String originalValue;
+
+        @Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
+
+            // find out if our key is already used in the selection.
+            usage = determineTextUsage(sel, key);
+
+            String[] value_array = values.split(",");
+            String[] display_array;
+            if(locale_display_values != null)
+                display_array = locale_display_values.split(",");
+            else if(display_values != null)
+                display_array = display_values.split(",");
+            else
+                display_array = value_array;
+
+            lhm = new LinkedHashMap<String,String>();
+            if (!usage.allSimilar() && !usage.unused())
+            {
+                lhm.put(DIFFERENT, DIFFERENT);
+            }
+            for (int i=0; i<value_array.length; i++) {
+                lhm.put(value_array[i],
+                (locale_display_values == null) ?
+                tr(display_array[i]) : display_array[i]);
+            }
+            if(!usage.unused())
+            {
+                for (String s : usage.values) {
+                    if (!lhm.containsKey(s)) lhm.put(s, s);
+                }
+            }
+            if (default_ != null && !lhm.containsKey(default_)) lhm.put(default_, default_);
+            if(!lhm.containsKey("")) lhm.put("", "");
+
+            combo = new JComboBox(lhm.values().toArray());
+            combo.setEditable(editable);
+            if (usage.allSimilar() && !usage.unused())
+            {
+                originalValue=usage.getFirst();
+                combo.setSelectedItem(lhm.get(originalValue));
+            }
+            // use default only in case it is a totally new entry
+            else if(default_ != null && !usage.hadKeys())
+            {
+                combo.setSelectedItem(default_);
+                originalValue=DIFFERENT;
+            }
+            else if(usage.unused())
+            {
+                combo.setSelectedItem("");
+                originalValue="";
+            }
+            else
+            {
+                combo.setSelectedItem(DIFFERENT);
+                originalValue=DIFFERENT;
+            }
+
+            if(locale_text == null)
+                locale_text = tr(text);
+            p.add(new JLabel(locale_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) {
+            Object obj = combo.getSelectedItem();
+            String display = (obj == null) ? null : obj.toString();
+            String value = null;
+            if(display == null && combo.isEditable())
+                display = combo.getEditor().getItem().toString();
+
+            if (display != null)
+            {
+                for (String key : lhm.keySet()) {
+                    String k = lhm.get(key);
+                    if (k != null && k.equals(display)) value=key;
+                }
+                if(value == null)
+                    value = display;
+            }
+            else
+                value = "";
+
+            // no change if same as before
+            if (value.equals(originalValue) || (originalValue == null && (value == null || value.length() == 0))) return;
+
+            if (delete_if_empty && value != null && value.length() == 0)
+                value = null;
+            cmds.add(new ChangePropertyCommand(sel, key, value));
+        }
+        @Override boolean requestFocusInWindow() {return combo.requestFocusInWindow();}
+    }
+
+    public static class Label extends Item {
+        public String text;
+        public String locale_text;
+
+        @Override public void addToPanel(JPanel p, Collection<OsmPrimitive> sel) {
+            if(locale_text == null)
+                locale_text = tr(text);
+            p.add(new JLabel(locale_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, Collection<OsmPrimitive> sel) { }
+        @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;
+    public List<Item> data = new LinkedList<Item>();
+    private static HashMap<String,String> lastValue = new HashMap<String,String>();
+
+    /**
+     * 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() {}
+
+    /**
+     * Change the display name without changing the toolbar value.
+     */
+    public void setDisplayName() {
+        putValue(Action.NAME, getName());
+        putValue("toolbar", "tagging_" + getRawName());
+        putValue(SHORT_DESCRIPTION, "<html>"+ (group != null ?
+        tr("Use preset ''{0}'' of group ''{1}''", tr(name), group.getName()) :
+        tr("Use preset ''{0}''", tr(name)))
+        +"</html>");
+    }
+
+    public String getName() {
+        return group != null ? group.getName() + "/" + tr(name) : tr(name);
+    }
+    public String getRawName() {
+        return group != null ? group.getRawName() + "/" + name : name;
+    }
+    /**
+     * Called from the XML parser to set the icon
+     *
+     * FIXME for Java 1.6 - use 24x24 icons for LARGE_ICON_KEY (button bar)
+     * and the 16x16 icons for SMALL_ICON.
+     */
+    public void setIcon(String iconName) {
+        String s = Main.pref.get("taggingpreset.iconpaths");
+        ImageIcon icon = ImageProvider.getIfAvailable((s != null ? s.split(";") : null), "presets", null, iconName);
+        if (icon == null)
+        {
+            System.out.println("Could not get presets icon " + iconName);
+            icon = new ImageIcon(iconName);
+        }
+        if (Math.max(icon.getIconHeight(), icon.getIconWidth()) != 16)
+            icon = new ImageIcon(icon.getImage().getScaledInstance(16, 16, 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(Reader in) throws SAXException {
+        XmlObjectParser parser = new XmlObjectParser();
+        parser.mapOnStart("item", TaggingPreset.class);
+        parser.mapOnStart("separator", TaggingPresetSeparator.class);
+        parser.mapBoth("group", TaggingPresetMenu.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>();
+        TaggingPresetMenu lastmenu = null;
+        parser.start(in);
+        while(parser.hasNext()) {
+            Object o = parser.next();
+            if (o instanceof TaggingPresetMenu) {
+                TaggingPresetMenu tp = (TaggingPresetMenu) o;
+                if(tp == lastmenu)
+                    lastmenu = tp.group;
+                else
+                {
+                    tp.setDisplayName();
+                    tp.group = lastmenu;
+                    lastmenu = tp;
+                    all.add(tp);
+                    Main.toolbar.register(tp);
+
+                }
+            } else if (o instanceof TaggingPresetSeparator) {
+                TaggingPresetSeparator tp = (TaggingPresetSeparator) o;
+                tp.group = lastmenu;
+                all.add(tp);
+            } else if (o instanceof TaggingPreset) {
+                TaggingPreset tp = (TaggingPreset) o;
+                tp.group = lastmenu;
+                tp.setDisplayName();
+                all.add(tp);
+                Main.toolbar.register(tp);
+            } 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");
+
+        if (Main.pref.getBoolean("taggingpreset.enable-defaults", true))
+        {
+            allTaggingPresets = "resource://presets/presets.xml"
+            + (allTaggingPresets != null ? ";"+allTaggingPresets : "");
+        }
+
+        for(String source : allTaggingPresets.split(";"))
+        {
+            try {
+                MirroredInputStream s = new MirroredInputStream(source);
+                InputStreamReader r;
+                try
+                {
+                    r = new InputStreamReader(s, "UTF-8");
+                }
+                catch (UnsupportedEncodingException e)
+                {
+                    r = new InputStreamReader(s);
+                }
+                allPresets.addAll(TaggingPreset.readAll(new BufferedReader(r)));
+            } 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(Collection<OsmPrimitive> selected) {
+        if (data == null)
+            return null;
+        JPanel p = new JPanel(new GridBagLayout());
+
+        for (Item i : data)
+            i.addToPanel(p, selected);
+        return p;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        Collection<OsmPrimitive> sel = Main.ds.getSelected();
+        JPanel p = createPanel(sel);
+        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) {
+                            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.undoRedo.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: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java	(revision 1169)
@@ -16,33 +16,33 @@
 
 public class TaggingPresetMenu extends TaggingPreset {
-	public JMenu menu = null; // set by TaggingPresetPreferences
-	public void setDisplayName() {
-		String n = getName();
-		putValue(Action.NAME, n);
-		putValue(SHORT_DESCRIPTION, "<html>"+tr("Preset group ''{0}''", n)+"</html>");
-		putValue("toolbar", "tagginggroup_" + getRawName());
-	}
-	public void setIcon(String iconName) {
-		super.setIcon(iconName);
-	}
-	public void actionPerformed(ActionEvent e) {
-		Object s = e.getSource();
-		if(menu != null && s instanceof Component)
-		{
-			Component co = (Component)s;
-			JPopupMenu pm = new JPopupMenu(getName());
-			for(Component c : menu.getMenuComponents())
-			{
-				if(c instanceof JMenuItem)
-				{
-					JMenuItem j = new JMenuItem(((JMenuItem)c).getAction());
-					j.setText(((JMenuItem)c).getText());
-					pm.add(j);
-				}
-				else if(c instanceof JSeparator)
-					pm.addSeparator();
-			}
-			pm.show(co, co.getWidth()/2, co.getHeight()/2);
-		}
-	}
+    public JMenu menu = null; // set by TaggingPresetPreferences
+    public void setDisplayName() {
+        String n = getName();
+        putValue(Action.NAME, n);
+        putValue(SHORT_DESCRIPTION, "<html>"+tr("Preset group ''{0}''", n)+"</html>");
+        putValue("toolbar", "tagginggroup_" + getRawName());
+    }
+    public void setIcon(String iconName) {
+        super.setIcon(iconName);
+    }
+    public void actionPerformed(ActionEvent e) {
+        Object s = e.getSource();
+        if(menu != null && s instanceof Component)
+        {
+            Component co = (Component)s;
+            JPopupMenu pm = new JPopupMenu(getName());
+            for(Component c : menu.getMenuComponents())
+            {
+                if(c instanceof JMenuItem)
+                {
+                    JMenuItem j = new JMenuItem(((JMenuItem)c).getAction());
+                    j.setText(((JMenuItem)c).getText());
+                    pm.add(j);
+                }
+                else if(c instanceof JSeparator)
+                    pm.addSeparator();
+            }
+            pm.show(co, co.getWidth()/2, co.getHeight()/2);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSeparator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSeparator.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSeparator.java	(revision 1169)
@@ -5,4 +5,4 @@
 
 public class TaggingPresetSeparator extends TaggingPreset {
-	public void setDisplayName() {}
+    public void setDisplayName() {}
 }
Index: trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java	(revision 1169)
@@ -15,103 +15,103 @@
 public class BoundingBoxDownloader extends OsmServerReader {
 
-	/**
-	 * The boundings of the desired map data.
-	 */
-	private final double lat1;
-	private final double lon1;
-	private final double lat2;
-	private final double lon2;
+    /**
+     * The boundings of the desired map data.
+     */
+    private final double lat1;
+    private final double lon1;
+    private final double lat2;
+    private final double lon2;
 
-	public BoundingBoxDownloader(double lat1, double lon1, double lat2, double lon2) {
-		this.lat1 = lat1;
-		this.lon1 = lon1;
-		this.lat2 = lat2;
-		this.lon2 = lon2;
-		// store the bounding box in the preferences so it can be
-		// re-used across invocations of josm
-		Main.pref.put("osm-download.bounds", lat1+";"+lon1+";"+lat2+";"+lon2);
-	}
+    public BoundingBoxDownloader(double lat1, double lon1, double lat2, double lon2) {
+        this.lat1 = lat1;
+        this.lon1 = lon1;
+        this.lat2 = lat2;
+        this.lon2 = lon2;
+        // store the bounding box in the preferences so it can be
+        // re-used across invocations of josm
+        Main.pref.put("osm-download.bounds", lat1+";"+lon1+";"+lat2+";"+lon2);
+    }
 
-	/**
-	 * Retrieve raw gps waypoints from the server API.
-	 * @return A list of all primitives retrieved. Currently, the list of lists
-	 *      contain only one list, since the server cannot distinguish between
-	 *      ways.
-	 */
-	public GpxData parseRawGps() throws IOException, SAXException {
-		Main.pleaseWaitDlg.progress.setValue(0);
-		Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
-		try {
-			String url = "trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=";
+    /**
+     * Retrieve raw gps waypoints from the server API.
+     * @return A list of all primitives retrieved. Currently, the list of lists
+     *      contain only one list, since the server cannot distinguish between
+     *      ways.
+     */
+    public GpxData parseRawGps() throws IOException, SAXException {
+        Main.pleaseWaitDlg.progress.setValue(0);
+        Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+        try {
+            String url = "trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=";
 
-			boolean done = false;
-			GpxData result = null;
-			for (int i = 0;!done;++i) {
-				Main.pleaseWaitDlg.currentAction.setText(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000)));
-				InputStream in = getInputStream(url+i, Main.pleaseWaitDlg);
-				if (in == null)
-					break;
-				GpxData currentGpx = new GpxReader(in, null).data;
-				if (result == null) {
-					result = currentGpx;
-				} else if (currentGpx.hasTrackPoints()) {
-					result.mergeFrom(currentGpx);
-				} else{
-					done = true;
-				}
-				in.close();
-				activeConnection = null;
-			}
-			result.fromServer = true;
-			return result;
-		} catch (IllegalArgumentException e) {
-			// caused by HttpUrlConnection in case of illegal stuff in the response
-			if (cancel)
-				return null;
-			throw new SAXException("Illegal characters within the HTTP-header response", e);
-		} catch (IOException e) {
-			if (cancel)
-				return null;
-			throw e;
-		} catch (SAXException e) {
-			throw e;
-		} catch (Exception e) {
-			if (cancel)
-				return null;
-			if (e instanceof RuntimeException)
-				throw (RuntimeException)e;
-			throw new RuntimeException(e);
-		}
-	}
+            boolean done = false;
+            GpxData result = null;
+            for (int i = 0;!done;++i) {
+                Main.pleaseWaitDlg.currentAction.setText(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000)));
+                InputStream in = getInputStream(url+i, Main.pleaseWaitDlg);
+                if (in == null)
+                    break;
+                GpxData currentGpx = new GpxReader(in, null).data;
+                if (result == null) {
+                    result = currentGpx;
+                } else if (currentGpx.hasTrackPoints()) {
+                    result.mergeFrom(currentGpx);
+                } else{
+                    done = true;
+                }
+                in.close();
+                activeConnection = null;
+            }
+            result.fromServer = true;
+            return result;
+        } catch (IllegalArgumentException e) {
+            // caused by HttpUrlConnection in case of illegal stuff in the response
+            if (cancel)
+                return null;
+            throw new SAXException("Illegal characters within the HTTP-header response", e);
+        } catch (IOException e) {
+            if (cancel)
+                return null;
+            throw e;
+        } catch (SAXException e) {
+            throw e;
+        } catch (Exception e) {
+            if (cancel)
+                return null;
+            if (e instanceof RuntimeException)
+                throw (RuntimeException)e;
+            throw new RuntimeException(e);
+        }
+    }
 
-	/**
-	 * Read the data from the osm server address.
-	 * @return A data set containing all data retrieved from that url
-	 */
-	public DataSet parseOsm() throws SAXException, IOException {
-		try {
-			Main.pleaseWaitDlg.progress.setValue(0);
-			Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
-			final InputStream in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, Main.pleaseWaitDlg);
-			if (in == null)
-				return null;
-			Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
-			final DataSet data = OsmReader.parseDataSet(in, null, Main.pleaseWaitDlg);
-			in.close();
-			activeConnection = null;
-			return data;
-		} catch (IOException e) {
-			if (cancel)
-				return null;
-			throw e;
-		} catch (SAXException e) {
-			throw e;
-		} catch (Exception e) {
-			if (cancel)
-				return null;
-			if (e instanceof RuntimeException)
-				throw (RuntimeException)e;
-			throw new RuntimeException(e);
-		}
-	}
+    /**
+     * Read the data from the osm server address.
+     * @return A data set containing all data retrieved from that url
+     */
+    public DataSet parseOsm() throws SAXException, IOException {
+        try {
+            Main.pleaseWaitDlg.progress.setValue(0);
+            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+            final InputStream in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, Main.pleaseWaitDlg);
+            if (in == null)
+                return null;
+            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
+            final DataSet data = OsmReader.parseDataSet(in, null, Main.pleaseWaitDlg);
+            in.close();
+            activeConnection = null;
+            return data;
+        } catch (IOException e) {
+            if (cancel)
+                return null;
+            throw e;
+        } catch (SAXException e) {
+            throw e;
+        } catch (Exception e) {
+            if (cancel)
+                return null;
+            if (e instanceof RuntimeException)
+                throw (RuntimeException)e;
+            throw new RuntimeException(e);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/DiffResultReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/DiffResultReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/DiffResultReader.java	(revision 1169)
@@ -41,5 +41,5 @@
  */
 public class DiffResultReader implements Visitor {
-    
+
     /**
      * mapping from old id to new id/version
@@ -47,10 +47,10 @@
     private Map<String, Long[]> versions = new HashMap<String, Long[]>();
     private Collection<OsmPrimitive> processed;
-    private Map<OsmPrimitive,Long> newIdMap; 
+    private Map<OsmPrimitive,Long> newIdMap;
 
-    /** 
+    /**
      * List of protocol versions that will be accepted on reading
      */
-    
+
     private class Parser extends DefaultHandler {
 
@@ -81,5 +81,5 @@
      *  elemet found there is returned.
      */
-    public static void parseDiffResult(InputStream source, Collection<OsmPrimitive> osm, Collection<OsmPrimitive> processed, Map<OsmPrimitive,Long> newIdMap, PleaseWaitDialog pleaseWaitDlg) 
+    public static void parseDiffResult(InputStream source, Collection<OsmPrimitive> osm, Collection<OsmPrimitive> processed, Map<OsmPrimitive,Long> newIdMap, PleaseWaitDialog pleaseWaitDlg)
     throws SAXException, IOException {
 
@@ -107,5 +107,5 @@
        }
     }
-    
+
     public void visit(Node n) {
         String key = "node:" + (newIdMap.containsKey(n) ? newIdMap.get(n) : n.id);
@@ -127,5 +127,5 @@
                 w.id = nv[0]; w.version = nv[1].intValue();
             }
-        }        
+        }
     }
     public void visit(Relation r) {
@@ -137,5 +137,5 @@
                 r.id = nv[0]; r.version = nv[1].intValue();
             }
-        }   
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 1169)
@@ -35,271 +35,271 @@
  */
 public class GpxReader {
-	// TODO: implement GPX 1.0 parsing
-
-	/**
-	 * The resulting gpx data
-	 */
-	public GpxData data;
-	public enum state { init, metadata, wpt, rte, trk, ext, author, link, trkseg }
-
-	private class Parser extends DefaultHandler {
-
-		private GpxData currentData;
-		private GpxTrack currentTrack;
-		private Collection<WayPoint> currentTrackSeg;
-		private GpxRoute currentRoute;
-		private WayPoint currentWayPoint;
-
-		private state currentState = state.init;
-	
-		private GpxLink currentLink;
-		private Stack<state> states;
-
-		private StringBuffer accumulator = new StringBuffer();
-
-		@Override public void startDocument() {
-			accumulator = new StringBuffer();
-			states = new Stack<state>();
-			currentData = new GpxData();
-		}		
-
-		private double parseCoord(String s) {
-			try {
-				return Double.parseDouble(s);
-			} catch (NumberFormatException ex) {
-				return Double.NaN;
-			}
-		}
-
-		private LatLon parseLatLon(Attributes atts) {
-			return new LatLon(
-				parseCoord(atts.getValue("lat")),
-				parseCoord(atts.getValue("lon")));
-		}
-
-		@Override public void startElement(String namespaceURI, String qName, String rqName, Attributes atts) throws SAXException {
-			switch(currentState) {
-			case init:
-				if (qName.equals("metadata")) {
-					states.push(currentState);
-					currentState = state.metadata;
-				} else if (qName.equals("wpt")) {
-					states.push(currentState);
-					currentState = state.wpt;
-					currentWayPoint = new WayPoint(parseLatLon(atts));
-				} else if (qName.equals("rte")) {
-					states.push(currentState);
-					currentState = state.rte;
-					currentRoute = new GpxRoute();
-				} else if (qName.equals("trk")) {
-					states.push(currentState);
-					currentState = state.trk;
-					currentTrack = new GpxTrack();
-				} else if (qName.equals("extensions")) {
-					states.push(currentState);
-					currentState = state.ext;
-				}
-				break;
-			case author:
-				if (qName.equals("link")) {
-					states.push(currentState);
-					currentState = state.link;
-					currentLink = new GpxLink(atts.getValue("href"));
-				}
-				break;
-			case trk:
-				if (qName.equals("trkseg")) {
-					states.push(currentState);
-					currentState = state.trkseg;
-					currentTrackSeg = new ArrayList<WayPoint>();
-				} else if (qName.equals("link")) {
-					states.push(currentState);
-					currentState = state.link;
-					currentLink = new GpxLink(atts.getValue("href"));
-				} else if (qName.equals("extensions")) {
-					states.push(currentState);
-					currentState = state.ext;
-				}
-				break;
-			case metadata:
-				if (qName.equals("author")) {
-					states.push(currentState);
-					currentState = state.author;
-				} else if (qName.equals("extensions")) {
-					states.push(currentState);
-					currentState = state.ext;
-				}
-				break;
-			case trkseg:
-				if (qName.equals("trkpt")) {
-					states.push(currentState);
-					currentState = state.wpt;
-					currentWayPoint = new WayPoint(parseLatLon(atts));
-				}
-				break;
-			case wpt:
-				if (qName.equals("link")) {
-					states.push(currentState);
-					currentState = state.link;
-					currentLink = new GpxLink(atts.getValue("href"));
-				} else if (qName.equals("extensions")) {
-					states.push(currentState);
-					currentState = state.ext;
-				}
-				break;
-			case rte:
-				if (qName.equals("link")) {
-					states.push(currentState);
-					currentState = state.link;
-					currentLink = new GpxLink(atts.getValue("href"));
-				} else if (qName.equals("rtept")) {
-					states.push(currentState);
-					currentState = state.wpt;
-					currentWayPoint = new WayPoint(parseLatLon(atts));
-				} else if (qName.equals("extensions")) {
-					states.push(currentState);
-					currentState = state.ext;
-				}
-				break;
-			default:
-			}
-			accumulator.setLength(0);
-		}
-
-		@Override public void characters(char[] ch, int start, int length) {
-			accumulator.append(ch, start, length);
-		}
-
-		private Map<String, Object> getAttr() {
-			switch (currentState) {
-				case rte: return currentRoute.attr;
-				case metadata: return currentData.attr;
-				case wpt: return currentWayPoint.attr;
-				case trk: return currentTrack.attr;
-				default: return null;
-			}
-		}
-
-		@Override public void endElement(String namespaceURI, String qName, String rqName) {
-			switch (currentState) {
-			case metadata:
-				if (qName.equals("name") || qName.equals("desc") ||
-						qName.equals("time") || qName.equals("keywords")) {
-					currentData.attr.put(qName, accumulator.toString());
-				} else if (qName.equals("metadata")) {
-					currentState = states.pop();
-				}
-				//TODO: parse copyright, bounds, extensions
-				break;
-			case author:
-				if (qName.equals("author")) {
-					currentState = states.pop();
-				} else if (qName.equals("name") || qName.equals("email")) {
-					currentData.attr.put("author" + qName, accumulator.toString());
-				} else if (qName.equals("link")) {
-					currentData.attr.put("authorlink", currentLink);
-				}
-				break;
-			case link:
-				if (qName.equals("text")) {
-					currentLink.text = accumulator.toString();
-				} else if (qName.equals("type")) {
-					currentLink.type = accumulator.toString();
-				} else if (qName.equals("link")) {
-					// <link>URL</link>
-					if (currentLink.uri == null)
-						currentLink.uri = accumulator.toString();
-
-					currentState = states.pop();
-				}
-				if (currentState == state.author) {
-					currentData.attr.put("authorlink", currentLink);
-				} else if (currentState != state.link) {
-					Map<String, Object> attr = getAttr();
-					if (!attr.containsKey("link")) {
-						attr.put("link", new LinkedList<GpxLink>());
-					}
-					((Collection<GpxLink>) attr.get("link")).add(currentLink);
-				}
-				break;
-			case wpt:
-				if (qName.equals("ele") || qName.equals("magvar")
-						|| qName.equals("geoidheight") || qName.equals("name")
-						|| qName.equals("sym") || qName.equals("type")) {
-					currentWayPoint.attr.put(qName, accumulator.toString());
-				} else if (qName.equals("time")) {
-					currentWayPoint.attr.put(qName, accumulator.toString());
-					currentWayPoint.setTime();					
-				} else if (qName.equals("cmt") || qName.equals("desc")) {
-					currentWayPoint.attr.put(qName, accumulator.toString());
-					currentWayPoint.setGarminCommentTime(qName);					
-				} else if (qName.equals("rtept")) {
-					currentState = states.pop();
-					currentRoute.routePoints.add(currentWayPoint);
-				} else if (qName.equals("trkpt")) {
-					currentState = states.pop();
-					currentTrackSeg.add(currentWayPoint);
-				} else if (qName.equals("wpt")) {
-					currentState = states.pop();
-					currentData.waypoints.add(currentWayPoint);
-				}
-				break;
-			case trkseg:
-				if (qName.equals("trkseg")) {
-					currentState = states.pop();
-					currentTrack.trackSegs.add(currentTrackSeg);
-				}
-				break;
-			case trk:
-				if (qName.equals("trk")) {
-					currentState = states.pop();
-					currentData.tracks.add(currentTrack);
-				} else if (qName.equals("name") || qName.equals("cmt")
-						|| qName.equals("desc") || qName.equals("src")
-						|| qName.equals("type") || qName.equals("number")) {
-					currentTrack.attr.put(qName, accumulator.toString());
-				}
-				break;
-			case ext:
-				if (qName.equals("extensions")) {
-					currentState = states.pop();
-				}
-				break;
-			default:
-				if (qName.equals("wpt")) {
-					currentState = states.pop();
-				} else if (qName.equals("rte")) {
-					currentState = states.pop();
-					currentData.routes.add(currentRoute);
-				}
-			}
-		}
-
-		@Override public void endDocument() throws SAXException  {
-			if (!states.empty()) {
-				throw new SAXException(tr("Parse error: invalid document structure for gpx document"));
-			}
-			data = currentData;
-		}
-	}
-
-	/**
-	 * Parse the input stream and store the result in trackData and markerData
-	 * 
-	 * @param relativeMarkerPath The directory to use as relative path for all &lt;wpt&gt; 
-	 *    marker tags. Maybe <code>null</code>, in which case no relative urls are constructed for the markers. 
-	 */
-	public GpxReader(InputStream source, File relativeMarkerPath) throws SAXException, IOException {
-		
-		Parser parser = new Parser();
-		InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8"));
-		try {
-			SAXParserFactory factory = SAXParserFactory.newInstance();
-			factory.setNamespaceAware(true);
-			factory.newSAXParser().parse(inputSource, parser);
-		} catch (ParserConfigurationException e) {
-			e.printStackTrace(); // broken SAXException chaining
-			throw new SAXException(e);
-		}
-	}
+    // TODO: implement GPX 1.0 parsing
+
+    /**
+     * The resulting gpx data
+     */
+    public GpxData data;
+    public enum state { init, metadata, wpt, rte, trk, ext, author, link, trkseg }
+
+    private class Parser extends DefaultHandler {
+
+        private GpxData currentData;
+        private GpxTrack currentTrack;
+        private Collection<WayPoint> currentTrackSeg;
+        private GpxRoute currentRoute;
+        private WayPoint currentWayPoint;
+
+        private state currentState = state.init;
+
+        private GpxLink currentLink;
+        private Stack<state> states;
+
+        private StringBuffer accumulator = new StringBuffer();
+
+        @Override public void startDocument() {
+            accumulator = new StringBuffer();
+            states = new Stack<state>();
+            currentData = new GpxData();
+        }
+
+        private double parseCoord(String s) {
+            try {
+                return Double.parseDouble(s);
+            } catch (NumberFormatException ex) {
+                return Double.NaN;
+            }
+        }
+
+        private LatLon parseLatLon(Attributes atts) {
+            return new LatLon(
+                parseCoord(atts.getValue("lat")),
+                parseCoord(atts.getValue("lon")));
+        }
+
+        @Override public void startElement(String namespaceURI, String qName, String rqName, Attributes atts) throws SAXException {
+            switch(currentState) {
+            case init:
+                if (qName.equals("metadata")) {
+                    states.push(currentState);
+                    currentState = state.metadata;
+                } else if (qName.equals("wpt")) {
+                    states.push(currentState);
+                    currentState = state.wpt;
+                    currentWayPoint = new WayPoint(parseLatLon(atts));
+                } else if (qName.equals("rte")) {
+                    states.push(currentState);
+                    currentState = state.rte;
+                    currentRoute = new GpxRoute();
+                } else if (qName.equals("trk")) {
+                    states.push(currentState);
+                    currentState = state.trk;
+                    currentTrack = new GpxTrack();
+                } else if (qName.equals("extensions")) {
+                    states.push(currentState);
+                    currentState = state.ext;
+                }
+                break;
+            case author:
+                if (qName.equals("link")) {
+                    states.push(currentState);
+                    currentState = state.link;
+                    currentLink = new GpxLink(atts.getValue("href"));
+                }
+                break;
+            case trk:
+                if (qName.equals("trkseg")) {
+                    states.push(currentState);
+                    currentState = state.trkseg;
+                    currentTrackSeg = new ArrayList<WayPoint>();
+                } else if (qName.equals("link")) {
+                    states.push(currentState);
+                    currentState = state.link;
+                    currentLink = new GpxLink(atts.getValue("href"));
+                } else if (qName.equals("extensions")) {
+                    states.push(currentState);
+                    currentState = state.ext;
+                }
+                break;
+            case metadata:
+                if (qName.equals("author")) {
+                    states.push(currentState);
+                    currentState = state.author;
+                } else if (qName.equals("extensions")) {
+                    states.push(currentState);
+                    currentState = state.ext;
+                }
+                break;
+            case trkseg:
+                if (qName.equals("trkpt")) {
+                    states.push(currentState);
+                    currentState = state.wpt;
+                    currentWayPoint = new WayPoint(parseLatLon(atts));
+                }
+                break;
+            case wpt:
+                if (qName.equals("link")) {
+                    states.push(currentState);
+                    currentState = state.link;
+                    currentLink = new GpxLink(atts.getValue("href"));
+                } else if (qName.equals("extensions")) {
+                    states.push(currentState);
+                    currentState = state.ext;
+                }
+                break;
+            case rte:
+                if (qName.equals("link")) {
+                    states.push(currentState);
+                    currentState = state.link;
+                    currentLink = new GpxLink(atts.getValue("href"));
+                } else if (qName.equals("rtept")) {
+                    states.push(currentState);
+                    currentState = state.wpt;
+                    currentWayPoint = new WayPoint(parseLatLon(atts));
+                } else if (qName.equals("extensions")) {
+                    states.push(currentState);
+                    currentState = state.ext;
+                }
+                break;
+            default:
+            }
+            accumulator.setLength(0);
+        }
+
+        @Override public void characters(char[] ch, int start, int length) {
+            accumulator.append(ch, start, length);
+        }
+
+        private Map<String, Object> getAttr() {
+            switch (currentState) {
+                case rte: return currentRoute.attr;
+                case metadata: return currentData.attr;
+                case wpt: return currentWayPoint.attr;
+                case trk: return currentTrack.attr;
+                default: return null;
+            }
+        }
+
+        @Override public void endElement(String namespaceURI, String qName, String rqName) {
+            switch (currentState) {
+            case metadata:
+                if (qName.equals("name") || qName.equals("desc") ||
+                        qName.equals("time") || qName.equals("keywords")) {
+                    currentData.attr.put(qName, accumulator.toString());
+                } else if (qName.equals("metadata")) {
+                    currentState = states.pop();
+                }
+                //TODO: parse copyright, bounds, extensions
+                break;
+            case author:
+                if (qName.equals("author")) {
+                    currentState = states.pop();
+                } else if (qName.equals("name") || qName.equals("email")) {
+                    currentData.attr.put("author" + qName, accumulator.toString());
+                } else if (qName.equals("link")) {
+                    currentData.attr.put("authorlink", currentLink);
+                }
+                break;
+            case link:
+                if (qName.equals("text")) {
+                    currentLink.text = accumulator.toString();
+                } else if (qName.equals("type")) {
+                    currentLink.type = accumulator.toString();
+                } else if (qName.equals("link")) {
+                    // <link>URL</link>
+                    if (currentLink.uri == null)
+                        currentLink.uri = accumulator.toString();
+
+                    currentState = states.pop();
+                }
+                if (currentState == state.author) {
+                    currentData.attr.put("authorlink", currentLink);
+                } else if (currentState != state.link) {
+                    Map<String, Object> attr = getAttr();
+                    if (!attr.containsKey("link")) {
+                        attr.put("link", new LinkedList<GpxLink>());
+                    }
+                    ((Collection<GpxLink>) attr.get("link")).add(currentLink);
+                }
+                break;
+            case wpt:
+                if (qName.equals("ele") || qName.equals("magvar")
+                        || qName.equals("geoidheight") || qName.equals("name")
+                        || qName.equals("sym") || qName.equals("type")) {
+                    currentWayPoint.attr.put(qName, accumulator.toString());
+                } else if (qName.equals("time")) {
+                    currentWayPoint.attr.put(qName, accumulator.toString());
+                    currentWayPoint.setTime();
+                } else if (qName.equals("cmt") || qName.equals("desc")) {
+                    currentWayPoint.attr.put(qName, accumulator.toString());
+                    currentWayPoint.setGarminCommentTime(qName);
+                } else if (qName.equals("rtept")) {
+                    currentState = states.pop();
+                    currentRoute.routePoints.add(currentWayPoint);
+                } else if (qName.equals("trkpt")) {
+                    currentState = states.pop();
+                    currentTrackSeg.add(currentWayPoint);
+                } else if (qName.equals("wpt")) {
+                    currentState = states.pop();
+                    currentData.waypoints.add(currentWayPoint);
+                }
+                break;
+            case trkseg:
+                if (qName.equals("trkseg")) {
+                    currentState = states.pop();
+                    currentTrack.trackSegs.add(currentTrackSeg);
+                }
+                break;
+            case trk:
+                if (qName.equals("trk")) {
+                    currentState = states.pop();
+                    currentData.tracks.add(currentTrack);
+                } else if (qName.equals("name") || qName.equals("cmt")
+                        || qName.equals("desc") || qName.equals("src")
+                        || qName.equals("type") || qName.equals("number")) {
+                    currentTrack.attr.put(qName, accumulator.toString());
+                }
+                break;
+            case ext:
+                if (qName.equals("extensions")) {
+                    currentState = states.pop();
+                }
+                break;
+            default:
+                if (qName.equals("wpt")) {
+                    currentState = states.pop();
+                } else if (qName.equals("rte")) {
+                    currentState = states.pop();
+                    currentData.routes.add(currentRoute);
+                }
+            }
+        }
+
+        @Override public void endDocument() throws SAXException  {
+            if (!states.empty()) {
+                throw new SAXException(tr("Parse error: invalid document structure for gpx document"));
+            }
+            data = currentData;
+        }
+    }
+
+    /**
+     * Parse the input stream and store the result in trackData and markerData
+     *
+     * @param relativeMarkerPath The directory to use as relative path for all &lt;wpt&gt;
+     *    marker tags. Maybe <code>null</code>, in which case no relative urls are constructed for the markers.
+     */
+    public GpxReader(InputStream source, File relativeMarkerPath) throws SAXException, IOException {
+
+        Parser parser = new Parser();
+        InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8"));
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance();
+            factory.setNamespaceAware(true);
+            factory.newSAXParser().parse(inputSource, parser);
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace(); // broken SAXException chaining
+            throw new SAXException(e);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 1169)
@@ -97,7 +97,7 @@
         for (WayPoint pnt : data.waypoints) {
             wayPoint(pnt, WAY_POINT);
-        }        
-    }
-    
+        }
+    }
+
     private void writeRoutes() {
         for (GpxRoute rte : data.routes) {
@@ -110,5 +110,5 @@
         }
     }
-    
+
     private void writeTracks() {
         for (GpxTrack trk : data.tracks) {
@@ -140,5 +140,5 @@
         indent += "  ";
     }
-    
+
     private void inline(String tag, String attributes) {
         out.println(indent + "<" + tag + " " + attributes + " />");
@@ -155,5 +155,5 @@
     }
 
-    /**       
+    /**
      * if content not null, open tag, write encoded content, and close tag
      * else do nothing.
@@ -168,5 +168,5 @@
     }
 
-    /**       
+    /**
      * output link
      */
@@ -180,5 +180,5 @@
     }
 
-    /**       
+    /**
      * output a point
      */
Index: trunk/src/org/openstreetmap/josm/io/MirroredInputStream.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/MirroredInputStream.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/MirroredInputStream.java	(revision 1169)
@@ -20,137 +20,137 @@
  */
 public class MirroredInputStream extends InputStream {
-	InputStream fs = null;
+    InputStream fs = null;
 
-	public MirroredInputStream(String name) throws IOException
-	{
-		this(name, null, -1L);
-	}
+    public MirroredInputStream(String name) throws IOException
+    {
+        this(name, null, -1L);
+    }
 
-	public MirroredInputStream(String name, long maxTime) throws IOException
-	{
-		this(name, null, maxTime);
-	}
+    public MirroredInputStream(String name, long maxTime) throws IOException
+    {
+        this(name, null, maxTime);
+    }
 
-	public MirroredInputStream(String name, String destDir, long maxTime) throws IOException
-	{
-		URL url;
-		File file = null;
-		try
-		{
-			url = new URL(name);
-			if(url.getProtocol().equals("file"))
-			{
-				file = new File(name.substring("file:/".length()));
-				if(!file.exists())
-					file = new File(name.substring("file://".length()));
-			}
-			else
-				file = checkLocal(url, destDir, maxTime);
-		}
-		catch(java.net.MalformedURLException e)
-		{
-			if(name.startsWith("resource://"))
-			{
-				fs = getClass().getResourceAsStream(
-				name.substring("resource:/".length()));
-				return;
-			}
-			else
-				file = new File(name);
-		}
-		if(file == null)
-			throw new IOException();
-		fs = new FileInputStream(file);
-	}
+    public MirroredInputStream(String name, String destDir, long maxTime) throws IOException
+    {
+        URL url;
+        File file = null;
+        try
+        {
+            url = new URL(name);
+            if(url.getProtocol().equals("file"))
+            {
+                file = new File(name.substring("file:/".length()));
+                if(!file.exists())
+                    file = new File(name.substring("file://".length()));
+            }
+            else
+                file = checkLocal(url, destDir, maxTime);
+        }
+        catch(java.net.MalformedURLException e)
+        {
+            if(name.startsWith("resource://"))
+            {
+                fs = getClass().getResourceAsStream(
+                name.substring("resource:/".length()));
+                return;
+            }
+            else
+                file = new File(name);
+        }
+        if(file == null)
+            throw new IOException();
+        fs = new FileInputStream(file);
+    }
 
-	private File checkLocal(URL url, String destDir, long maxTime)
-	{
-		String localPath = Main.pref.get("mirror." + url);
-		File file = null;
-		if(localPath != null && localPath.length() > 0)
-		{
-			String[] lp = localPath.split(";");
-			file = new File(lp[1]);
-			if(maxTime <= 0)
-				maxTime = Main.pref.getInteger("mirror.maxtime", 7*24*60*60);
-			if(System.currentTimeMillis() - Long.parseLong(lp[0]) < maxTime*1000)
-			{
-				if(file.exists())
-				{
-					return file;
-				}
-			}
-		}
-		if(destDir == null)
-			destDir = Main.pref.getPreferencesDir();
+    private File checkLocal(URL url, String destDir, long maxTime)
+    {
+        String localPath = Main.pref.get("mirror." + url);
+        File file = null;
+        if(localPath != null && localPath.length() > 0)
+        {
+            String[] lp = localPath.split(";");
+            file = new File(lp[1]);
+            if(maxTime <= 0)
+                maxTime = Main.pref.getInteger("mirror.maxtime", 7*24*60*60);
+            if(System.currentTimeMillis() - Long.parseLong(lp[0]) < maxTime*1000)
+            {
+                if(file.exists())
+                {
+                    return file;
+                }
+            }
+        }
+        if(destDir == null)
+            destDir = Main.pref.getPreferencesDir();
 
-		File destDirFile = new File(destDir);
-		if(!destDirFile.exists() )
-			destDirFile.mkdirs();
+        File destDirFile = new File(destDir);
+        if(!destDirFile.exists() )
+            destDirFile.mkdirs();
 
-		localPath = "mirror_" + new File(url.getPath()).getName();
-		destDirFile = new File(destDir, localPath + ".tmp");
-		BufferedOutputStream bos = null;
-		BufferedInputStream bis = null;
-		try
-		{
-			URLConnection conn = url.openConnection();
-			conn.setConnectTimeout(5000);
-			bis = new BufferedInputStream(conn.getInputStream());
-			bos = new BufferedOutputStream( new FileOutputStream(destDirFile));
-			byte[] buffer = new byte[4096];
-			int length;
-			while((length = bis.read(buffer)) > -1)
-				bos.write(buffer, 0, length);
-		}
-		catch(IOException ioe)
-		{
-			if(file != null)
-				return file;
-			else
-				return null;
-		}
-		finally
-		{
-			if(bis != null)
-			{
-				try
-				{
-					bis.close();
-				}
-				catch (IOException e)
-				{
-					e.printStackTrace();
-				}
-			}
-			if(bos != null)
-			{
-				try
-				{
-					bos.close();
-				}
-				catch (IOException e)
-				{
-					e.printStackTrace();
-				}
-			}
-			file = new File(destDir, localPath);
-			destDirFile.renameTo(file);
-			Main.pref.put("mirror." + url, System.currentTimeMillis() + ";" + file);
-		}
+        localPath = "mirror_" + new File(url.getPath()).getName();
+        destDirFile = new File(destDir, localPath + ".tmp");
+        BufferedOutputStream bos = null;
+        BufferedInputStream bis = null;
+        try
+        {
+            URLConnection conn = url.openConnection();
+            conn.setConnectTimeout(5000);
+            bis = new BufferedInputStream(conn.getInputStream());
+            bos = new BufferedOutputStream( new FileOutputStream(destDirFile));
+            byte[] buffer = new byte[4096];
+            int length;
+            while((length = bis.read(buffer)) > -1)
+                bos.write(buffer, 0, length);
+        }
+        catch(IOException ioe)
+        {
+            if(file != null)
+                return file;
+            else
+                return null;
+        }
+        finally
+        {
+            if(bis != null)
+            {
+                try
+                {
+                    bis.close();
+                }
+                catch (IOException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+            if(bos != null)
+            {
+                try
+                {
+                    bos.close();
+                }
+                catch (IOException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+            file = new File(destDir, localPath);
+            destDirFile.renameTo(file);
+            Main.pref.put("mirror." + url, System.currentTimeMillis() + ";" + file);
+        }
 
-		return file;
-	}
-	public int available() throws IOException
-	{ return fs.available(); }
-	public void close() throws IOException
-	{ fs.close(); }
-	public int read() throws IOException
-	{ return fs.read(); }
-	public int read(byte[] b) throws IOException
-	{ return fs.read(b); }
-	public int read(byte[] b, int off, int len) throws IOException
-	{ return fs.read(b,off, len); }
-	public long skip(long n) throws IOException
-	{ return fs.skip(n); }
+        return file;
+    }
+    public int available() throws IOException
+    { return fs.available(); }
+    public void close() throws IOException
+    { fs.close(); }
+    public int read() throws IOException
+    { return fs.read(); }
+    public int read(byte[] b) throws IOException
+    { return fs.read(b); }
+    public int read(byte[] b, int off, int len) throws IOException
+    { return fs.read(b,off, len); }
+    public long skip(long n) throws IOException
+    { return fs.skip(n); }
 }
Index: trunk/src/org/openstreetmap/josm/io/MultiPartFormOutputStream.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/MultiPartFormOutputStream.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/MultiPartFormOutputStream.java	(revision 1169)
@@ -3,33 +3,33 @@
 
 License
-				
+
 Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved.
-Redistribution and use in source and binary forms, with or without modification, 
+Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:
- 
-    * Redistribution of source code must retain the above copyright notice, this list 
+
+    * Redistribution of source code must retain the above copyright notice, this list
       of conditions and the following disclaimer.
 
-    * Redistribution in binary form must reproduce the above copyright notice, this 
-      list of conditions and the following disclaimer in the documentation and/or other 
+    * Redistribution in binary form must reproduce the above copyright notice, this
+      list of conditions and the following disclaimer in the documentation and/or other
       materials provided with the distribution.
 
- 
-Neither the name of Sun Microsystems, Inc. or the names of contributors may be used to 
-endorse or promote products derived from this software without specific prior written 
+
+Neither the name of Sun Microsystems, Inc. or the names of contributors may be used to
+endorse or promote products derived from this software without specific prior written
 permission.
- 
-This software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR IMPLIED 
-CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
-FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, 
-INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS 
-A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT 
-WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, 
-INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 
-REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS 
+
+This software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR IMPLIED
+CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS,
+INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS
+A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT
+WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
+INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS
 SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- 
-You acknowledge that this software is not designed, licensed or intended for use in the 
-design, construction, operation or maintenance of any nuclear facility. 
+
+You acknowledge that this software is not designed, licensed or intended for use in the
+design, construction, operation or maintenance of any nuclear facility.
 */
 
@@ -44,392 +44,392 @@
 import java.net.URLConnection;
 
-	 
+
 /**
- * <code>MultiPartFormOutputStream</code> is used to write 
- * "multipart/form-data" to a <code>java.net.URLConnection</code> for 
- * POSTing.  This is primarily for file uploading to HTTP servers.  
- * 
+ * <code>MultiPartFormOutputStream</code> is used to write
+ * "multipart/form-data" to a <code>java.net.URLConnection</code> for
+ * POSTing.  This is primarily for file uploading to HTTP servers.
+ *
  * @since  JDK1.3
  */
 public class MultiPartFormOutputStream extends OsmConnection {
-	/**
-	 * The line end characters.  
-	 */
-	private static final String NEWLINE = "\r\n";
-
-	/**
-	 * The boundary prefix.  
-	 */
-	private static final String PREFIX = "--";
-
-	/**
-	 * The output stream to write to.  
-	 */
-	private DataOutputStream out = null;
-
-	/**
-	 * The multipart boundary string.  
-	 */
-	private String boundary = null;
-
-	/**
-	 * Creates a new <code>MultiPartFormOutputStream</code> object using 
-	 * the specified output stream and boundary.  The boundary is required 
-	 * to be created before using this method, as described in the 
-	 * description for the <code>getContentType(String)</code> method.  
-	 * The boundary is only checked for <code>null</code> or empty string, 
-	 * but it is recommended to be at least 6 characters.  (Or use the 
-	 * static createBoundary() method to create one.)
-	 * 
-	 * @param  os        the output stream
-	 * @param  boundary  the boundary
-	 * @see  #createBoundary()
-	 * @see  #getContentType(String)
-	 */
-	public MultiPartFormOutputStream(OutputStream os, String boundary) {
-		if(os == null) {
-			throw new IllegalArgumentException("Output stream is required.");
-		}
-		if(boundary == null || boundary.length() == 0) {
-			throw new IllegalArgumentException("Boundary stream is required.");
-		}
-		this.out = new DataOutputStream(os);
-		this.boundary = boundary;
-		initAuthentication();
-	}
-
-	/**
-	 * Writes an boolean field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, boolean value) 
-	throws java.io.IOException {
-		writeField(name, new Boolean(value).toString());
-	}
-
-	/**
-	 * Writes an double field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, double value) 
-	throws java.io.IOException {
-		writeField(name, Double.toString(value));
-	}
-
-	/**
-	 * Writes an float field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, float value) 
-	throws java.io.IOException {
-		writeField(name, Float.toString(value));
-	}
-
-	/**
-	 * Writes an long field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, long value) 
-	throws java.io.IOException {
-		writeField(name, Long.toString(value));
-	}
-
-	/**
-	 * Writes an int field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, int value) 
-	throws java.io.IOException {
-		writeField(name, Integer.toString(value));
-	}
-
-	/**
-	 * Writes an short field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, short value) 
-	throws java.io.IOException {
-		writeField(name, Short.toString(value));
-	}
-
-	/**
-	 * Writes an char field value.  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, char value) 
-	throws java.io.IOException {
-		writeField(name, new Character(value).toString());
-	}
-
-	/**
-	 * Writes an string field value.  If the value is null, an empty string 
-	 * is sent ("").  
-	 * 
-	 * @param  name   the field name (required)
-	 * @param  value  the field value
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeField(String name, String value) 
-	throws java.io.IOException {
-		if(name == null) {
-			throw new IllegalArgumentException("Name cannot be null or empty.");
-		}
-		if(value == null) {
-			value = "";
-		}
-		/*
-			--boundary\r\n
-			Content-Disposition: form-data; name="<fieldName>"\r\n
-			\r\n
-			<value>\r\n
-		 */
-		// write boundary
-		out.writeBytes(PREFIX);
-		out.writeBytes(boundary);
-		out.writeBytes(NEWLINE);
-		// write content header
-		out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
-		out.writeBytes(NEWLINE);
-		out.writeBytes(NEWLINE);
-		// write content
-		out.writeBytes(value);
-		out.writeBytes(NEWLINE);
-		out.flush();
-	}
-
-	/**
-	 * Writes a file's contents.  If the file is null, does not exists, or 
-	 * is a directory, a <code>java.lang.IllegalArgumentException</code> 
-	 * will be thrown.  
-	 * 
-	 * @param  name      the field name
-	 * @param  mimeType  the file content type (optional, recommended)
-	 * @param  file      the file (the file must exist)
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeFile(String name, String mimeType, java.io.File file) 
-	throws java.io.IOException {
-		if(file == null) {
-			throw new IllegalArgumentException("File cannot be null.");
-		}
-		if(!file.exists()) {
-			throw new IllegalArgumentException("File does not exist.");
-		}
-		if(file.isDirectory()) {
-			throw new IllegalArgumentException("File cannot be a directory.");
-		}
-		writeFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(file));
-	}
-
-	/**
-	 * Writes a input stream's contents.  If the input stream is null, a 
-	 * <code>java.lang.IllegalArgumentException</code> will be thrown.  
-	 * 
-	 * @param  name      the field name
-	 * @param  mimeType  the file content type (optional, recommended)
-	 * @param  fileName  the file name (required)
-	 * @param  is        the input stream
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeFile(String name, String mimeType, 
-			String fileName, InputStream is) 
-	throws java.io.IOException {
-		if(is == null) {
-			throw new IllegalArgumentException("Input stream cannot be null.");
-		}
-		if(fileName == null || fileName.length() == 0) {
-			throw new IllegalArgumentException("File name cannot be null or empty.");
-		}
-		/*
-			--boundary\r\n
-			Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
-			Content-Type: <mime-type>\r\n
-			\r\n
-			<file-data>\r\n
-		 */
-		// write boundary
-		out.writeBytes(PREFIX);
-		out.writeBytes(boundary);
-		out.writeBytes(NEWLINE);
-		// write content header
-		out.writeBytes("Content-Disposition: form-data; name=\"" + name + 
-				"\"; filename=\"" + fileName + "\"");
-		out.writeBytes(NEWLINE);
-		if(mimeType != null) {
-			out.writeBytes("Content-Type: " + mimeType);
-			out.writeBytes(NEWLINE);
-		}
-		out.writeBytes(NEWLINE);
-		// write content
-		byte[] data = new byte[1024];
-		int r = 0;
-		while((r = is.read(data, 0, data.length)) != -1) {
-			out.write(data, 0, r);
-		}
-		// close input stream, but ignore any possible exception for it
-		try {
-			is.close();
-		} catch(Exception e) {}
-		out.writeBytes(NEWLINE);
-		out.flush();
-	}
-
-	/**
-	 * Writes the given bytes.  The bytes are assumed to be the contents 
-	 * of a file, and will be sent as such.  If the data is null, a 
-	 * <code>java.lang.IllegalArgumentException</code> will be thrown.  
-	 * 
-	 * @param  name      the field name
-	 * @param  mimeType  the file content type (optional, recommended)
-	 * @param  fileName  the file name (required)
-	 * @param  data      the file data
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void writeFile(String name, String mimeType, 
-			String fileName, byte[] data) 
-	throws java.io.IOException {
-		if(data == null) {
-			throw new IllegalArgumentException("Data cannot be null.");
-		}
-		if(fileName == null || fileName.length() == 0) {
-			throw new IllegalArgumentException("File name cannot be null or empty.");
-		}
-		/*
-			--boundary\r\n
-			Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
-			Content-Type: <mime-type>\r\n
-			\r\n
-			<file-data>\r\n
-		 */
-		// write boundary
-		out.writeBytes(PREFIX);
-		out.writeBytes(boundary);
-		out.writeBytes(NEWLINE);
-		// write content header
-		out.writeBytes("Content-Disposition: form-data; name=\"" + name + 
-				"\"; filename=\"" + fileName + "\"");
-		out.writeBytes(NEWLINE);
-		if(mimeType != null) {
-			out.writeBytes("Content-Type: " + mimeType);
-			out.writeBytes(NEWLINE);
-		}
-		out.writeBytes(NEWLINE);
-		// write content
-		out.write(data, 0, data.length);
-		out.writeBytes(NEWLINE);
-		out.flush();
-	}
-
-	/**
-	 * Flushes the stream.  Actually, this method does nothing, as the only 
-	 * write methods are highly specialized and automatically flush.  
-	 */
-	public void flush() {
-		// out.flush();
-	}
-
-	/**
-	 * Closes the stream.  <br/>
-	 * <br/>
-	 * <b>NOTE:</b> This method <b>MUST</b> be called to finalize the 
-	 * multipart stream.
-	 * 
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public void close() throws java.io.IOException {
-		// write final boundary
-		out.writeBytes(PREFIX);
-		out.writeBytes(boundary);
-		out.writeBytes(PREFIX);
-		out.writeBytes(NEWLINE);
-		out.flush();
-		out.close();
-	}
-
-	/**
-	 * Gets the multipart boundary string being used by this stream.  
-	 * 
-	 * @return  the boundary
-	 */
-	public String getBoundary() {
-		return this.boundary;
-	}
-
-	/**
-	 * Creates a new <code>java.net.URLConnection</code> object from the 
-	 * specified <code>java.net.URL</code>.  This is a convenience method 
-	 * which will set the <code>doInput</code>, <code>doOutput</code>, 
-	 * <code>useCaches</code> and <code>defaultUseCaches</code> fields to 
-	 * the appropriate settings in the correct order.  
-	 * 
-	 * @return  a <code>java.net.URLConnection</code> object for the URL
-	 * @throws  java.io.IOException  on input/output errors
-	 */
-	public static URLConnection createConnection(URL url) 
-	throws java.io.IOException {
-		URLConnection urlConn = url.openConnection();
-		if(urlConn instanceof HttpURLConnection) {
-			HttpURLConnection httpConn = (HttpURLConnection)urlConn;
-			httpConn.setRequestMethod("POST");
-		}
-		urlConn.setDoInput(true);
-		urlConn.setDoOutput(true);
-		urlConn.setUseCaches(false);
-		urlConn.setDefaultUseCaches(false);
-		return urlConn;
-	}
-
-	/**
-	 * Creates a multipart boundary string by concatenating 20 hyphens (-) 
-	 * and the hexadecimal (base-16) representation of the current time in 
-	 * milliseconds.  
-	 * 
-	 * @return  a multipart boundary string
-	 * @see  #getContentType(String)
-	 */
-	public static String createBoundary() {
-		return "--------------------" + 
-		Long.toString(System.currentTimeMillis(), 16);
-	}
-
-	/**
-	 * Gets the content type string suitable for the 
-	 * <code>java.net.URLConnection</code> which includes the multipart 
-	 * boundary string.  <br/>
-	 * <br/>
-	 * This method is static because, due to the nature of the 
-	 * <code>java.net.URLConnection</code> class, once the output stream 
-	 * for the connection is acquired, it's too late to set the content 
-	 * type (or any other request parameter).  So one has to create a 
-	 * multipart boundary string first before using this class, such as 
-	 * with the <code>createBoundary()</code> method.  
-	 * 
-	 * @param  boundary  the boundary string
-	 * @return  the content type string
-	 * @see  #createBoundary()
-	 */
-	public static String getContentType(String boundary) {
-		return "multipart/form-data; boundary=" + boundary;
-	}
+    /**
+     * The line end characters.
+     */
+    private static final String NEWLINE = "\r\n";
+
+    /**
+     * The boundary prefix.
+     */
+    private static final String PREFIX = "--";
+
+    /**
+     * The output stream to write to.
+     */
+    private DataOutputStream out = null;
+
+    /**
+     * The multipart boundary string.
+     */
+    private String boundary = null;
+
+    /**
+     * Creates a new <code>MultiPartFormOutputStream</code> object using
+     * the specified output stream and boundary.  The boundary is required
+     * to be created before using this method, as described in the
+     * description for the <code>getContentType(String)</code> method.
+     * The boundary is only checked for <code>null</code> or empty string,
+     * but it is recommended to be at least 6 characters.  (Or use the
+     * static createBoundary() method to create one.)
+     *
+     * @param  os        the output stream
+     * @param  boundary  the boundary
+     * @see  #createBoundary()
+     * @see  #getContentType(String)
+     */
+    public MultiPartFormOutputStream(OutputStream os, String boundary) {
+        if(os == null) {
+            throw new IllegalArgumentException("Output stream is required.");
+        }
+        if(boundary == null || boundary.length() == 0) {
+            throw new IllegalArgumentException("Boundary stream is required.");
+        }
+        this.out = new DataOutputStream(os);
+        this.boundary = boundary;
+        initAuthentication();
+    }
+
+    /**
+     * Writes an boolean field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, boolean value)
+    throws java.io.IOException {
+        writeField(name, new Boolean(value).toString());
+    }
+
+    /**
+     * Writes an double field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, double value)
+    throws java.io.IOException {
+        writeField(name, Double.toString(value));
+    }
+
+    /**
+     * Writes an float field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, float value)
+    throws java.io.IOException {
+        writeField(name, Float.toString(value));
+    }
+
+    /**
+     * Writes an long field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, long value)
+    throws java.io.IOException {
+        writeField(name, Long.toString(value));
+    }
+
+    /**
+     * Writes an int field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, int value)
+    throws java.io.IOException {
+        writeField(name, Integer.toString(value));
+    }
+
+    /**
+     * Writes an short field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, short value)
+    throws java.io.IOException {
+        writeField(name, Short.toString(value));
+    }
+
+    /**
+     * Writes an char field value.
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, char value)
+    throws java.io.IOException {
+        writeField(name, new Character(value).toString());
+    }
+
+    /**
+     * Writes an string field value.  If the value is null, an empty string
+     * is sent ("").
+     *
+     * @param  name   the field name (required)
+     * @param  value  the field value
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeField(String name, String value)
+    throws java.io.IOException {
+        if(name == null) {
+            throw new IllegalArgumentException("Name cannot be null or empty.");
+        }
+        if(value == null) {
+            value = "";
+        }
+        /*
+            --boundary\r\n
+            Content-Disposition: form-data; name="<fieldName>"\r\n
+            \r\n
+            <value>\r\n
+         */
+        // write boundary
+        out.writeBytes(PREFIX);
+        out.writeBytes(boundary);
+        out.writeBytes(NEWLINE);
+        // write content header
+        out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
+        out.writeBytes(NEWLINE);
+        out.writeBytes(NEWLINE);
+        // write content
+        out.writeBytes(value);
+        out.writeBytes(NEWLINE);
+        out.flush();
+    }
+
+    /**
+     * Writes a file's contents.  If the file is null, does not exists, or
+     * is a directory, a <code>java.lang.IllegalArgumentException</code>
+     * will be thrown.
+     *
+     * @param  name      the field name
+     * @param  mimeType  the file content type (optional, recommended)
+     * @param  file      the file (the file must exist)
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeFile(String name, String mimeType, java.io.File file)
+    throws java.io.IOException {
+        if(file == null) {
+            throw new IllegalArgumentException("File cannot be null.");
+        }
+        if(!file.exists()) {
+            throw new IllegalArgumentException("File does not exist.");
+        }
+        if(file.isDirectory()) {
+            throw new IllegalArgumentException("File cannot be a directory.");
+        }
+        writeFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(file));
+    }
+
+    /**
+     * Writes a input stream's contents.  If the input stream is null, a
+     * <code>java.lang.IllegalArgumentException</code> will be thrown.
+     *
+     * @param  name      the field name
+     * @param  mimeType  the file content type (optional, recommended)
+     * @param  fileName  the file name (required)
+     * @param  is        the input stream
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeFile(String name, String mimeType,
+            String fileName, InputStream is)
+    throws java.io.IOException {
+        if(is == null) {
+            throw new IllegalArgumentException("Input stream cannot be null.");
+        }
+        if(fileName == null || fileName.length() == 0) {
+            throw new IllegalArgumentException("File name cannot be null or empty.");
+        }
+        /*
+            --boundary\r\n
+            Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
+            Content-Type: <mime-type>\r\n
+            \r\n
+            <file-data>\r\n
+         */
+        // write boundary
+        out.writeBytes(PREFIX);
+        out.writeBytes(boundary);
+        out.writeBytes(NEWLINE);
+        // write content header
+        out.writeBytes("Content-Disposition: form-data; name=\"" + name +
+                "\"; filename=\"" + fileName + "\"");
+        out.writeBytes(NEWLINE);
+        if(mimeType != null) {
+            out.writeBytes("Content-Type: " + mimeType);
+            out.writeBytes(NEWLINE);
+        }
+        out.writeBytes(NEWLINE);
+        // write content
+        byte[] data = new byte[1024];
+        int r = 0;
+        while((r = is.read(data, 0, data.length)) != -1) {
+            out.write(data, 0, r);
+        }
+        // close input stream, but ignore any possible exception for it
+        try {
+            is.close();
+        } catch(Exception e) {}
+        out.writeBytes(NEWLINE);
+        out.flush();
+    }
+
+    /**
+     * Writes the given bytes.  The bytes are assumed to be the contents
+     * of a file, and will be sent as such.  If the data is null, a
+     * <code>java.lang.IllegalArgumentException</code> will be thrown.
+     *
+     * @param  name      the field name
+     * @param  mimeType  the file content type (optional, recommended)
+     * @param  fileName  the file name (required)
+     * @param  data      the file data
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void writeFile(String name, String mimeType,
+            String fileName, byte[] data)
+    throws java.io.IOException {
+        if(data == null) {
+            throw new IllegalArgumentException("Data cannot be null.");
+        }
+        if(fileName == null || fileName.length() == 0) {
+            throw new IllegalArgumentException("File name cannot be null or empty.");
+        }
+        /*
+            --boundary\r\n
+            Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
+            Content-Type: <mime-type>\r\n
+            \r\n
+            <file-data>\r\n
+         */
+        // write boundary
+        out.writeBytes(PREFIX);
+        out.writeBytes(boundary);
+        out.writeBytes(NEWLINE);
+        // write content header
+        out.writeBytes("Content-Disposition: form-data; name=\"" + name +
+                "\"; filename=\"" + fileName + "\"");
+        out.writeBytes(NEWLINE);
+        if(mimeType != null) {
+            out.writeBytes("Content-Type: " + mimeType);
+            out.writeBytes(NEWLINE);
+        }
+        out.writeBytes(NEWLINE);
+        // write content
+        out.write(data, 0, data.length);
+        out.writeBytes(NEWLINE);
+        out.flush();
+    }
+
+    /**
+     * Flushes the stream.  Actually, this method does nothing, as the only
+     * write methods are highly specialized and automatically flush.
+     */
+    public void flush() {
+        // out.flush();
+    }
+
+    /**
+     * Closes the stream.  <br/>
+     * <br/>
+     * <b>NOTE:</b> This method <b>MUST</b> be called to finalize the
+     * multipart stream.
+     *
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public void close() throws java.io.IOException {
+        // write final boundary
+        out.writeBytes(PREFIX);
+        out.writeBytes(boundary);
+        out.writeBytes(PREFIX);
+        out.writeBytes(NEWLINE);
+        out.flush();
+        out.close();
+    }
+
+    /**
+     * Gets the multipart boundary string being used by this stream.
+     *
+     * @return  the boundary
+     */
+    public String getBoundary() {
+        return this.boundary;
+    }
+
+    /**
+     * Creates a new <code>java.net.URLConnection</code> object from the
+     * specified <code>java.net.URL</code>.  This is a convenience method
+     * which will set the <code>doInput</code>, <code>doOutput</code>,
+     * <code>useCaches</code> and <code>defaultUseCaches</code> fields to
+     * the appropriate settings in the correct order.
+     *
+     * @return  a <code>java.net.URLConnection</code> object for the URL
+     * @throws  java.io.IOException  on input/output errors
+     */
+    public static URLConnection createConnection(URL url)
+    throws java.io.IOException {
+        URLConnection urlConn = url.openConnection();
+        if(urlConn instanceof HttpURLConnection) {
+            HttpURLConnection httpConn = (HttpURLConnection)urlConn;
+            httpConn.setRequestMethod("POST");
+        }
+        urlConn.setDoInput(true);
+        urlConn.setDoOutput(true);
+        urlConn.setUseCaches(false);
+        urlConn.setDefaultUseCaches(false);
+        return urlConn;
+    }
+
+    /**
+     * Creates a multipart boundary string by concatenating 20 hyphens (-)
+     * and the hexadecimal (base-16) representation of the current time in
+     * milliseconds.
+     *
+     * @return  a multipart boundary string
+     * @see  #getContentType(String)
+     */
+    public static String createBoundary() {
+        return "--------------------" +
+        Long.toString(System.currentTimeMillis(), 16);
+    }
+
+    /**
+     * Gets the content type string suitable for the
+     * <code>java.net.URLConnection</code> which includes the multipart
+     * boundary string.  <br/>
+     * <br/>
+     * This method is static because, due to the nature of the
+     * <code>java.net.URLConnection</code> class, once the output stream
+     * for the connection is acquired, it's too late to set the content
+     * type (or any other request parameter).  So one has to create a
+     * multipart boundary string first before using this class, such as
+     * with the <code>createBoundary()</code> method.
+     *
+     * @param  boundary  the boundary string
+     * @return  the content type string
+     * @see  #createBoundary()
+     */
+    public static String getContentType(String boundary) {
+        return "multipart/form-data; boundary=" + boundary;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/MyHttpHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/MyHttpHandler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/MyHttpHandler.java	(revision 1169)
@@ -26,5 +26,5 @@
                 proxyPort = port;
             }
-  
+
             protected java.net.URLConnection openConnection(URL u, Proxy p)
                     throws IOException {
Index: trunk/src/org/openstreetmap/josm/io/NmeaReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/NmeaReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/NmeaReader.java	(revision 1169)
@@ -28,444 +28,444 @@
 public class NmeaReader {
 
-	/** Handler for the different types that NMEA speaks. */
-	public static enum NMEA_TYPE {
-
-		/** RMC = recommended minimum sentence C. */
-		GPRMC("$GPRMC"),
-		/** GPS positions. */
-		GPGGA("$GPGGA"),
-		/** SA = satellites active. */
-		GPGSA("$GPGSA"),
-		/** Course over ground and ground speed */
-		GPVTG("$GPVTG");
-
-		private final String type;
-
-		NMEA_TYPE(String type) {
-			this.type = type;
-		}
-
-		public String getType() {
-			return this.type;
-		}
-
-		public boolean equals(String type) {
-			return this.type.equals(type);
-		}
-	}
-
-	// GPVTG
-	public static enum GPVTG {
-		COURSE(1),COURSE_REF(2), // true course
-		COURSE_M(3), COURSE_M_REF(4), // magnetic course
-		SPEED_KN(5), SPEED_KN_UNIT(6), // speed in knots
-		SPEED_KMH(7), SPEED_KMH_UNIT(8), // speed in km/h
-		REST(9); // version-specific rest
-
-		public final int position;
-
-		GPVTG(int position) {
-			this.position = position;
-		}
-	}
-
-	// The following only applies to GPRMC
-	public static enum GPRMC {
-		TIME(1),
-		/** Warning from the receiver (A = data ok, V = warning) */
-		RECEIVER_WARNING(2),
-		WIDTH_NORTH(3), WIDTH_NORTH_NAME(4), // Latitude, NS
-		LENGTH_EAST(5), LENGTH_EAST_NAME(6), // Longitude, EW
-		SPEED(7), COURSE(8), DATE(9),           // Speed in knots
-		MAGNETIC_DECLINATION(10), UNKNOWN(11),  // magnetic declination
-		/**
-		 * Mode (A = autonom; D = differential; E = estimated; N = not valid; S
-		 * = simulated)
-		 *
-		 * @since NMEA 2.3
-		 */
-		MODE(12);
-
-		public final int position;
-
-		GPRMC(int position) {
-			this.position = position;
-		}
-	}
-
-	// The following only applies to GPGGA
-	public static enum GPGGA {
-		TIME(1), LATITUDE(2), LATITUDE_NAME(3), LONGITUDE(4), LONGITUDE_NAME(5),
-		/**
-		 * Quality (0 = invalid, 1 = GPS, 2 = DGPS, 6 = estimanted (@since NMEA
-		 * 2.3))
-		 */
-		QUALITY(6), SATELLITE_COUNT(7),
-		HDOP(8), // HDOP (horizontal dilution of precision)
-		HEIGHT(9), HEIGHT_UNTIS(10), // height above NN (above geoid)
-		HEIGHT_2(11), HEIGHT_2_UNTIS(12), // height geoid - height ellipsoid (WGS84)
-		GPS_AGE(13),// Age of differential GPS data
-		REF(14); // REF station
-
-		public final int position;
-		GPGGA(int position) {
-			this.position = position;
-		}
-	}
-
-	public static enum GPGSA {
-		AUTOMATIC(1),
-		FIX_TYPE(2), // 1 = not fixed, 2 = 2D fixed, 3 = 3D fixed)
-		// PRN numbers for max 12 satellites
-		PRN_1(3), PRN_2(4), PRN_3(5), PRN_4(6), PRN_5(7), PRN_6(8),
-		PRN_7(9), PRN_8(10), PRN_9(11), PRN_10(12), PRN_11(13), PRN_12(14),
-		PDOP(15),   // PDOP (precision)
-		HDOP(16),   // HDOP (horizontal precision)
-		VDOP(17), ; // VDOP (vertical precision)
-
-		public final int position;
-		GPGSA(int position) {
-			this.position = position;
-		}
-	}
-
-	public GpxData data;
+    /** Handler for the different types that NMEA speaks. */
+    public static enum NMEA_TYPE {
+
+        /** RMC = recommended minimum sentence C. */
+        GPRMC("$GPRMC"),
+        /** GPS positions. */
+        GPGGA("$GPGGA"),
+        /** SA = satellites active. */
+        GPGSA("$GPGSA"),
+        /** Course over ground and ground speed */
+        GPVTG("$GPVTG");
+
+        private final String type;
+
+        NMEA_TYPE(String type) {
+            this.type = type;
+        }
+
+        public String getType() {
+            return this.type;
+        }
+
+        public boolean equals(String type) {
+            return this.type.equals(type);
+        }
+    }
+
+    // GPVTG
+    public static enum GPVTG {
+        COURSE(1),COURSE_REF(2), // true course
+        COURSE_M(3), COURSE_M_REF(4), // magnetic course
+        SPEED_KN(5), SPEED_KN_UNIT(6), // speed in knots
+        SPEED_KMH(7), SPEED_KMH_UNIT(8), // speed in km/h
+        REST(9); // version-specific rest
+
+        public final int position;
+
+        GPVTG(int position) {
+            this.position = position;
+        }
+    }
+
+    // The following only applies to GPRMC
+    public static enum GPRMC {
+        TIME(1),
+        /** Warning from the receiver (A = data ok, V = warning) */
+        RECEIVER_WARNING(2),
+        WIDTH_NORTH(3), WIDTH_NORTH_NAME(4), // Latitude, NS
+        LENGTH_EAST(5), LENGTH_EAST_NAME(6), // Longitude, EW
+        SPEED(7), COURSE(8), DATE(9),           // Speed in knots
+        MAGNETIC_DECLINATION(10), UNKNOWN(11),  // magnetic declination
+        /**
+         * Mode (A = autonom; D = differential; E = estimated; N = not valid; S
+         * = simulated)
+         *
+         * @since NMEA 2.3
+         */
+        MODE(12);
+
+        public final int position;
+
+        GPRMC(int position) {
+            this.position = position;
+        }
+    }
+
+    // The following only applies to GPGGA
+    public static enum GPGGA {
+        TIME(1), LATITUDE(2), LATITUDE_NAME(3), LONGITUDE(4), LONGITUDE_NAME(5),
+        /**
+         * Quality (0 = invalid, 1 = GPS, 2 = DGPS, 6 = estimanted (@since NMEA
+         * 2.3))
+         */
+        QUALITY(6), SATELLITE_COUNT(7),
+        HDOP(8), // HDOP (horizontal dilution of precision)
+        HEIGHT(9), HEIGHT_UNTIS(10), // height above NN (above geoid)
+        HEIGHT_2(11), HEIGHT_2_UNTIS(12), // height geoid - height ellipsoid (WGS84)
+        GPS_AGE(13),// Age of differential GPS data
+        REF(14); // REF station
+
+        public final int position;
+        GPGGA(int position) {
+            this.position = position;
+        }
+    }
+
+    public static enum GPGSA {
+        AUTOMATIC(1),
+        FIX_TYPE(2), // 1 = not fixed, 2 = 2D fixed, 3 = 3D fixed)
+        // PRN numbers for max 12 satellites
+        PRN_1(3), PRN_2(4), PRN_3(5), PRN_4(6), PRN_5(7), PRN_6(8),
+        PRN_7(9), PRN_8(10), PRN_9(11), PRN_10(12), PRN_11(13), PRN_12(14),
+        PDOP(15),   // PDOP (precision)
+        HDOP(16),   // HDOP (horizontal precision)
+        VDOP(17), ; // VDOP (vertical precision)
+
+        public final int position;
+        GPGSA(int position) {
+            this.position = position;
+        }
+    }
+
+    public GpxData data;
 
 //  private final static SimpleDateFormat GGATIMEFMT =
 //      new SimpleDateFormat("HHmmss.SSS");
-	private final static SimpleDateFormat RMCTIMEFMT =
-		new SimpleDateFormat("ddMMyyHHmmss.SSS");
-
-	// functons for reading the error stats
-	public NMEAParserState ps;
-
-	public int getParserUnknown() {
-		return ps.unknown;
-	}
-	public int getParserZeroCoordinates() {
-		return ps.zero_coord;
-	}
-	public int getParserChecksumErrors() {
-		return ps.checksum_errors;
-	}
-	public int getParserMalformed() {
-		return ps.malformed;
-	}
-	public int getNumberOfCoordinates() {
-		return ps.success;
-	}
-
-	public NmeaReader(InputStream source, File relativeMarkerPath) {
-
-		// create the data tree
-		data = new GpxData();
-		GpxTrack currentTrack = new GpxTrack();
-		data.tracks.add(currentTrack);
-
-		try {
-			BufferedReader rd =
-				new BufferedReader(new InputStreamReader(source));
-
-			StringBuffer sb = new StringBuffer(1024);
-			int loopstart_char = rd.read();
-			if(loopstart_char == -1) {// zero size file
-				//TODO tell user about the problem?
-				return;
-			}
-			sb.append((char)loopstart_char);
-			ps = new NMEAParserState();
-			ps.p_Date="010100"; // TODO date problem
-			while(true) {
-				// don't load unparsable files completely to memory
-				if(sb.length()>=1020) sb.delete(0, sb.length()-1);
-				int c = rd.read();
-				if(c=='$') {
-					ParseNMEASentence(sb.toString(), ps);
-					sb.delete(0, sb.length());
-					sb.append('$');
-				} else if(c == -1) {
-					// EOF: add last WayPoint if it works out
-					ParseNMEASentence(sb.toString(),ps);
-					break;
-				} else sb.append((char)c);
-			}
-			rd.close();
-			Object[] wparr = ps.waypoints.toArray();
-			currentTrack.trackSegs.add(ps.waypoints);
-			data.recalculateBounds();
-
-		} catch (final IOException e) {
-			// TODO tell user about the problem?
-		}
-	}
-	private class NMEAParserState {
-		protected Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
-		protected String p_Time;
-		protected String p_Date;
-		protected WayPoint p_Wp;
-
-		protected int success = 0; // number of successfully parsend sentences
-		protected int malformed = 0;
-		protected int checksum_errors = 0;
-		protected int unknown = 0;
-		protected int zero_coord = 0;
-	}
-
-	// Parses split up sentences into WayPoints which are stored
-	// in the collection in the NMEAParserState object.
-	// Returns true if the input made sence, false otherwise.
-	private boolean ParseNMEASentence(String s, NMEAParserState ps) {
-		try {
-			if(s.equals("")) throw(null);
-
-			// checksum check:
-			// the bytes between the $ and the * are xored;
-			// if there is no * or other meanities it will throw
-			// and result in a malformed packet.
-			String[] chkstrings = s.split("\\*");
-			byte[] chb = chkstrings[0].getBytes();
-			int chk=0;
-			for(int i = 1; i < chb.length; i++) chk ^= chb[i];
-			if(Integer.parseInt(chkstrings[1].substring(0,2),16) != chk) {
-				//System.out.println("Checksum error");
-				ps.checksum_errors++;
-				ps.p_Wp=null;
-				return false;
-			}
-			// now for the content
-			String[] e = chkstrings[0].split(",");
-			String accu;
-
-			WayPoint currentwp = ps.p_Wp;
-			String currentDate = ps.p_Date;
-
-			// handle the packet content
-			if(e[0].equals("$GPGGA")) {
-				// Position
-				LatLon latLon = parseLatLon(
-						e[GPGGA.LATITUDE_NAME.position],
-						e[GPGGA.LONGITUDE_NAME.position],
-						e[GPGGA.LATITUDE.position],
-						e[GPGGA.LONGITUDE.position]
-					);
-				if(latLon==null) throw(null); // malformed
-
-				if((latLon.lat()==0.0) && (latLon.lon()==0.0)) {
-					ps.zero_coord++;
-					return false;
-				}
-
-				// time
-				accu = e[GPGGA.TIME.position];
-				Date d = RMCTIMEFMT.parse(currentDate+accu, new ParsePosition(0));
-				if (d == null) throw(null); // malformed
-
-				if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(accu)) {
-					// this node is newer than the previous, create a new waypoint.
-					// no matter if previous WayPoint was null, we got something
-					// better now.
-					ps.p_Time=accu;
-					currentwp = new WayPoint(latLon);
-				}
-				if(!currentwp.attr.containsKey("time")) {
-					// As this sentence has no complete time only use it
-					// if there is no time so far
-					String gpxdate = WayPoint.GPXTIMEFMT.format(d);
-					currentwp.attr.put("time", gpxdate);
-				}
-				// elevation
-				accu=e[GPGGA.HEIGHT_UNTIS.position];
-				if(accu.equals("M")) {
-						// Ignore heights that are not in meters for now
-						accu=e[GPGGA.HEIGHT.position];
-						if(!accu.equals("")) {
-						Double.parseDouble(accu);
-						// if it throws it's malformed; this should only happen if the
-						// device sends nonstandard data.
-						if(!accu.equals("")) currentwp.attr.put("ele", accu);
-					}
-				}
-				// number of sattelites
-				accu=e[GPGGA.SATELLITE_COUNT.position];
-				int sat = 0;
-				if(!accu.equals("")) {
-					sat = Integer.parseInt(accu);
-					currentwp.attr.put("sat", accu);
-				}
-				// h-dilution
-				accu=e[GPGGA.HDOP.position];
-				if(!accu.equals("")) {
-					Double.parseDouble(accu);
-					currentwp.attr.put("hdop", accu);
-				}
-				// fix
-				accu=e[GPGGA.QUALITY.position];
-				if(!accu.equals("")) {
-					int fixtype = Integer.parseInt(accu);
-					switch(fixtype) {
-					case 0:
-						currentwp.attr.put("fix", "none");
-						break;
-					case 1:
-						if(sat < 4) currentwp.attr.put("fix", "2d");
-						else currentwp.attr.put("fix", "3d");
-						break;
-					case 2:
-						currentwp.attr.put("fix", "dgps");
-						break;
-					default:
-						break;
-					}
-				}
-			} else if(e[0].equals("$GPVTG")) {
-				// COURSE
-				accu = e[GPVTG.COURSE_REF.position];
-				if(accu.equals("T")) {
-					// other values than (T)rue are ignored
-					accu = e[GPVTG.COURSE.position];
-					if(!accu.equals("")) {
-						Double.parseDouble(accu);
-						currentwp.attr.put("course", accu);
-					}
-				}
-				// SPEED
-				accu = e[GPVTG.SPEED_KMH_UNIT.position];
-				if(accu.startsWith("K")) {
-					accu = e[GPVTG.SPEED_KMH.position];
-					if(!accu.equals("")) {
-						double speed = Double.parseDouble(accu);
-						speed /= 3.6; // speed in m/s
-						currentwp.attr.put("speed", Double.toString(speed));
-					}
-				}
-			} else if(e[0].equals("$GPGSA")) {
-				// vdop
-				accu=e[GPGSA.VDOP.position];
-				if(!accu.equals("")) {
-					Double.parseDouble(accu);
-					currentwp.attr.put("vdop", accu);
-				}
-				// hdop
-				accu=e[GPGSA.HDOP.position];
-				if(!accu.equals("")) {
-					Double.parseDouble(accu);
-					currentwp.attr.put("hdop", accu);
-				}
-				// pdop
-				accu=e[GPGSA.PDOP.position];
-				if(!accu.equals("")) {
-					Double.parseDouble(accu);
-					currentwp.attr.put("pdop", accu);
-				}
-			}
-			else if(e[0].equals("$GPRMC")) {
-				// coordinates
-				LatLon latLon = parseLatLon(
-						e[GPRMC.WIDTH_NORTH_NAME.position],
-						e[GPRMC.LENGTH_EAST_NAME.position],
-						e[GPRMC.WIDTH_NORTH.position],
-						e[GPRMC.LENGTH_EAST.position]
-					);
-				if(latLon==null) throw(null);
-				if((latLon.lat()==0.0) && (latLon.lon()==0.0)) {
-					ps.zero_coord++;
-					return false;
-				}
-				// time
-				currentDate = e[GPRMC.DATE.position];
-				String time = e[GPRMC.TIME.position];
-
-				Date d = RMCTIMEFMT.parse(currentDate+time, new ParsePosition(0));
-				if (d == null) throw(null);
-
-				if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(time)) {
-					// this node is newer than the previous, create a new waypoint.
-					ps.p_Time=time;
-					currentwp = new WayPoint(latLon);
-				}
-				// time: this sentence has complete time so always use it.
-				String gpxdate = WayPoint.GPXTIMEFMT.format(d);
-				currentwp.attr.put("time", gpxdate);
-				// speed
-				accu = e[GPRMC.SPEED.position];
-				if(!accu.equals("") && !currentwp.attr.containsKey("speed")) {
-					double speed = Double.parseDouble(accu);
-					speed *= 0.514444444; // to m/s
-					currentwp.attr.put("speed", Double.toString(speed));
-				}
-				// course
-				accu = e[GPRMC.COURSE.position];
-				if(!accu.equals("") && !currentwp.attr.containsKey("course")) {
-					Double.parseDouble(accu);
-					currentwp.attr.put("course", accu);
-				}
-
-				// TODO fix?
-				// * Mode (A = autonom; D = differential; E = estimated; N = not valid; S
-				// * = simulated)
-				// *
-				// * @since NMEA 2.3
-				//
-				//MODE(12);
-			} else {
-				ps.unknown++;
-				return false;
-			}
-			ps.p_Date = currentDate;
-			if(ps.p_Wp != currentwp) {
-				if(ps.p_Wp!=null) {
-					ps.p_Wp.setTime();
-				}
-				ps.p_Wp = currentwp;
-				ps.waypoints.add(currentwp);
-				ps.success++;
-				return true;
-			}
-			return true;
-
-		} catch(Exception x) {
-			// out of bounds and such
-			//System.out.println("Malformed line: "+s.toString().trim());
-			ps.malformed++;
-			ps.p_Wp=null;
-			return false;
-		}
-	}
-
-	private LatLon parseLatLon(String ew, String ns, String dlat, String dlon)
-		throws NumberFormatException {
-		String widthNorth = dlat.trim();
-		String lengthEast = dlon.trim();
-
-		// return a zero latlon instead of null so it is logged as zero coordinate
-		// instead of malformed sentence
-		if(widthNorth.equals("")&&lengthEast.equals("")) return new LatLon(0.0,0.0);
-
-		// The format is xxDDLL.LLLL
-		// xx optional whitespace
-		// DD (int) degres
-		// LL.LLLL (double) latidude
-		int latdegsep = widthNorth.indexOf('.') - 2;
-		if (latdegsep < 0) return null;
-
-		int latdeg = Integer.parseInt(widthNorth.substring(0, latdegsep));
-		double latmin = Double.parseDouble(widthNorth.substring(latdegsep));
-		double lat = latdeg + latmin / 60;
-		if ("S".equals(ns)) {
-			if(!ew.equals("N")) return null;
-			lat = -lat;
-		}
-
-		int londegsep = lengthEast.indexOf('.') - 2;
-		if (londegsep < 0) return null;
-
-		int londeg = Integer.parseInt(lengthEast.substring(0, londegsep));
-		double lonmin = Double.parseDouble(lengthEast.substring(londegsep));
-		double lon = londeg + lonmin / 60;
-		if ("W".equals(ew)) {
-			if(!ew.equals("E")) return null;
-			lon = -lon;
-		}
-		return new LatLon(lat, lon);
-	}
+    private final static SimpleDateFormat RMCTIMEFMT =
+        new SimpleDateFormat("ddMMyyHHmmss.SSS");
+
+    // functons for reading the error stats
+    public NMEAParserState ps;
+
+    public int getParserUnknown() {
+        return ps.unknown;
+    }
+    public int getParserZeroCoordinates() {
+        return ps.zero_coord;
+    }
+    public int getParserChecksumErrors() {
+        return ps.checksum_errors;
+    }
+    public int getParserMalformed() {
+        return ps.malformed;
+    }
+    public int getNumberOfCoordinates() {
+        return ps.success;
+    }
+
+    public NmeaReader(InputStream source, File relativeMarkerPath) {
+
+        // create the data tree
+        data = new GpxData();
+        GpxTrack currentTrack = new GpxTrack();
+        data.tracks.add(currentTrack);
+
+        try {
+            BufferedReader rd =
+                new BufferedReader(new InputStreamReader(source));
+
+            StringBuffer sb = new StringBuffer(1024);
+            int loopstart_char = rd.read();
+            if(loopstart_char == -1) {// zero size file
+                //TODO tell user about the problem?
+                return;
+            }
+            sb.append((char)loopstart_char);
+            ps = new NMEAParserState();
+            ps.p_Date="010100"; // TODO date problem
+            while(true) {
+                // don't load unparsable files completely to memory
+                if(sb.length()>=1020) sb.delete(0, sb.length()-1);
+                int c = rd.read();
+                if(c=='$') {
+                    ParseNMEASentence(sb.toString(), ps);
+                    sb.delete(0, sb.length());
+                    sb.append('$');
+                } else if(c == -1) {
+                    // EOF: add last WayPoint if it works out
+                    ParseNMEASentence(sb.toString(),ps);
+                    break;
+                } else sb.append((char)c);
+            }
+            rd.close();
+            Object[] wparr = ps.waypoints.toArray();
+            currentTrack.trackSegs.add(ps.waypoints);
+            data.recalculateBounds();
+
+        } catch (final IOException e) {
+            // TODO tell user about the problem?
+        }
+    }
+    private class NMEAParserState {
+        protected Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
+        protected String p_Time;
+        protected String p_Date;
+        protected WayPoint p_Wp;
+
+        protected int success = 0; // number of successfully parsend sentences
+        protected int malformed = 0;
+        protected int checksum_errors = 0;
+        protected int unknown = 0;
+        protected int zero_coord = 0;
+    }
+
+    // Parses split up sentences into WayPoints which are stored
+    // in the collection in the NMEAParserState object.
+    // Returns true if the input made sence, false otherwise.
+    private boolean ParseNMEASentence(String s, NMEAParserState ps) {
+        try {
+            if(s.equals("")) throw(null);
+
+            // checksum check:
+            // the bytes between the $ and the * are xored;
+            // if there is no * or other meanities it will throw
+            // and result in a malformed packet.
+            String[] chkstrings = s.split("\\*");
+            byte[] chb = chkstrings[0].getBytes();
+            int chk=0;
+            for(int i = 1; i < chb.length; i++) chk ^= chb[i];
+            if(Integer.parseInt(chkstrings[1].substring(0,2),16) != chk) {
+                //System.out.println("Checksum error");
+                ps.checksum_errors++;
+                ps.p_Wp=null;
+                return false;
+            }
+            // now for the content
+            String[] e = chkstrings[0].split(",");
+            String accu;
+
+            WayPoint currentwp = ps.p_Wp;
+            String currentDate = ps.p_Date;
+
+            // handle the packet content
+            if(e[0].equals("$GPGGA")) {
+                // Position
+                LatLon latLon = parseLatLon(
+                        e[GPGGA.LATITUDE_NAME.position],
+                        e[GPGGA.LONGITUDE_NAME.position],
+                        e[GPGGA.LATITUDE.position],
+                        e[GPGGA.LONGITUDE.position]
+                    );
+                if(latLon==null) throw(null); // malformed
+
+                if((latLon.lat()==0.0) && (latLon.lon()==0.0)) {
+                    ps.zero_coord++;
+                    return false;
+                }
+
+                // time
+                accu = e[GPGGA.TIME.position];
+                Date d = RMCTIMEFMT.parse(currentDate+accu, new ParsePosition(0));
+                if (d == null) throw(null); // malformed
+
+                if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(accu)) {
+                    // this node is newer than the previous, create a new waypoint.
+                    // no matter if previous WayPoint was null, we got something
+                    // better now.
+                    ps.p_Time=accu;
+                    currentwp = new WayPoint(latLon);
+                }
+                if(!currentwp.attr.containsKey("time")) {
+                    // As this sentence has no complete time only use it
+                    // if there is no time so far
+                    String gpxdate = WayPoint.GPXTIMEFMT.format(d);
+                    currentwp.attr.put("time", gpxdate);
+                }
+                // elevation
+                accu=e[GPGGA.HEIGHT_UNTIS.position];
+                if(accu.equals("M")) {
+                        // Ignore heights that are not in meters for now
+                        accu=e[GPGGA.HEIGHT.position];
+                        if(!accu.equals("")) {
+                        Double.parseDouble(accu);
+                        // if it throws it's malformed; this should only happen if the
+                        // device sends nonstandard data.
+                        if(!accu.equals("")) currentwp.attr.put("ele", accu);
+                    }
+                }
+                // number of sattelites
+                accu=e[GPGGA.SATELLITE_COUNT.position];
+                int sat = 0;
+                if(!accu.equals("")) {
+                    sat = Integer.parseInt(accu);
+                    currentwp.attr.put("sat", accu);
+                }
+                // h-dilution
+                accu=e[GPGGA.HDOP.position];
+                if(!accu.equals("")) {
+                    Double.parseDouble(accu);
+                    currentwp.attr.put("hdop", accu);
+                }
+                // fix
+                accu=e[GPGGA.QUALITY.position];
+                if(!accu.equals("")) {
+                    int fixtype = Integer.parseInt(accu);
+                    switch(fixtype) {
+                    case 0:
+                        currentwp.attr.put("fix", "none");
+                        break;
+                    case 1:
+                        if(sat < 4) currentwp.attr.put("fix", "2d");
+                        else currentwp.attr.put("fix", "3d");
+                        break;
+                    case 2:
+                        currentwp.attr.put("fix", "dgps");
+                        break;
+                    default:
+                        break;
+                    }
+                }
+            } else if(e[0].equals("$GPVTG")) {
+                // COURSE
+                accu = e[GPVTG.COURSE_REF.position];
+                if(accu.equals("T")) {
+                    // other values than (T)rue are ignored
+                    accu = e[GPVTG.COURSE.position];
+                    if(!accu.equals("")) {
+                        Double.parseDouble(accu);
+                        currentwp.attr.put("course", accu);
+                    }
+                }
+                // SPEED
+                accu = e[GPVTG.SPEED_KMH_UNIT.position];
+                if(accu.startsWith("K")) {
+                    accu = e[GPVTG.SPEED_KMH.position];
+                    if(!accu.equals("")) {
+                        double speed = Double.parseDouble(accu);
+                        speed /= 3.6; // speed in m/s
+                        currentwp.attr.put("speed", Double.toString(speed));
+                    }
+                }
+            } else if(e[0].equals("$GPGSA")) {
+                // vdop
+                accu=e[GPGSA.VDOP.position];
+                if(!accu.equals("")) {
+                    Double.parseDouble(accu);
+                    currentwp.attr.put("vdop", accu);
+                }
+                // hdop
+                accu=e[GPGSA.HDOP.position];
+                if(!accu.equals("")) {
+                    Double.parseDouble(accu);
+                    currentwp.attr.put("hdop", accu);
+                }
+                // pdop
+                accu=e[GPGSA.PDOP.position];
+                if(!accu.equals("")) {
+                    Double.parseDouble(accu);
+                    currentwp.attr.put("pdop", accu);
+                }
+            }
+            else if(e[0].equals("$GPRMC")) {
+                // coordinates
+                LatLon latLon = parseLatLon(
+                        e[GPRMC.WIDTH_NORTH_NAME.position],
+                        e[GPRMC.LENGTH_EAST_NAME.position],
+                        e[GPRMC.WIDTH_NORTH.position],
+                        e[GPRMC.LENGTH_EAST.position]
+                    );
+                if(latLon==null) throw(null);
+                if((latLon.lat()==0.0) && (latLon.lon()==0.0)) {
+                    ps.zero_coord++;
+                    return false;
+                }
+                // time
+                currentDate = e[GPRMC.DATE.position];
+                String time = e[GPRMC.TIME.position];
+
+                Date d = RMCTIMEFMT.parse(currentDate+time, new ParsePosition(0));
+                if (d == null) throw(null);
+
+                if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(time)) {
+                    // this node is newer than the previous, create a new waypoint.
+                    ps.p_Time=time;
+                    currentwp = new WayPoint(latLon);
+                }
+                // time: this sentence has complete time so always use it.
+                String gpxdate = WayPoint.GPXTIMEFMT.format(d);
+                currentwp.attr.put("time", gpxdate);
+                // speed
+                accu = e[GPRMC.SPEED.position];
+                if(!accu.equals("") && !currentwp.attr.containsKey("speed")) {
+                    double speed = Double.parseDouble(accu);
+                    speed *= 0.514444444; // to m/s
+                    currentwp.attr.put("speed", Double.toString(speed));
+                }
+                // course
+                accu = e[GPRMC.COURSE.position];
+                if(!accu.equals("") && !currentwp.attr.containsKey("course")) {
+                    Double.parseDouble(accu);
+                    currentwp.attr.put("course", accu);
+                }
+
+                // TODO fix?
+                // * Mode (A = autonom; D = differential; E = estimated; N = not valid; S
+                // * = simulated)
+                // *
+                // * @since NMEA 2.3
+                //
+                //MODE(12);
+            } else {
+                ps.unknown++;
+                return false;
+            }
+            ps.p_Date = currentDate;
+            if(ps.p_Wp != currentwp) {
+                if(ps.p_Wp!=null) {
+                    ps.p_Wp.setTime();
+                }
+                ps.p_Wp = currentwp;
+                ps.waypoints.add(currentwp);
+                ps.success++;
+                return true;
+            }
+            return true;
+
+        } catch(Exception x) {
+            // out of bounds and such
+            //System.out.println("Malformed line: "+s.toString().trim());
+            ps.malformed++;
+            ps.p_Wp=null;
+            return false;
+        }
+    }
+
+    private LatLon parseLatLon(String ew, String ns, String dlat, String dlon)
+        throws NumberFormatException {
+        String widthNorth = dlat.trim();
+        String lengthEast = dlon.trim();
+
+        // return a zero latlon instead of null so it is logged as zero coordinate
+        // instead of malformed sentence
+        if(widthNorth.equals("")&&lengthEast.equals("")) return new LatLon(0.0,0.0);
+
+        // The format is xxDDLL.LLLL
+        // xx optional whitespace
+        // DD (int) degres
+        // LL.LLLL (double) latidude
+        int latdegsep = widthNorth.indexOf('.') - 2;
+        if (latdegsep < 0) return null;
+
+        int latdeg = Integer.parseInt(widthNorth.substring(0, latdegsep));
+        double latmin = Double.parseDouble(widthNorth.substring(latdegsep));
+        double lat = latdeg + latmin / 60;
+        if ("S".equals(ns)) {
+            if(!ew.equals("N")) return null;
+            lat = -lat;
+        }
+
+        int londegsep = lengthEast.indexOf('.') - 2;
+        if (londegsep < 0) return null;
+
+        int londeg = Integer.parseInt(lengthEast.substring(0, londegsep));
+        double lonmin = Double.parseDouble(lengthEast.substring(londegsep));
+        double lon = londeg + lonmin / 60;
+        if ("W".equals(ew)) {
+            if(!ew.equals("E")) return null;
+            lon = -lon;
+        }
+        return new LatLon(lat, lon);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmConnection.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmConnection.java	(revision 1169)
@@ -34,112 +34,112 @@
 public class OsmConnection {
 
-	public static class OsmParseException extends Exception {
-		public OsmParseException() {super();}
-		public OsmParseException(String message, Throwable cause) {super(message, cause);}
-		public OsmParseException(String message) {super(message);}
-		public OsmParseException(Throwable cause) {super(cause);}
-	}
+    public static class OsmParseException extends Exception {
+        public OsmParseException() {super();}
+        public OsmParseException(String message, Throwable cause) {super(message, cause);}
+        public OsmParseException(String message) {super(message);}
+        public OsmParseException(Throwable cause) {super(cause);}
+    }
 
-	protected boolean cancel = false;
-	protected HttpURLConnection activeConnection;
+    protected boolean cancel = false;
+    protected HttpURLConnection activeConnection;
 
-	private static OsmAuth authentication = new OsmAuth();
-	/**
-	 * Initialize the http defaults and the authenticator.
-	 */
-	static {
-		//TODO: refactor this crap (maybe just insert the damn auth http-header by yourself)
-		try {
-	        HttpURLConnection.setFollowRedirects(true);
-	        Authenticator.setDefault(authentication);
+    private static OsmAuth authentication = new OsmAuth();
+    /**
+     * Initialize the http defaults and the authenticator.
+     */
+    static {
+        //TODO: refactor this crap (maybe just insert the damn auth http-header by yourself)
+        try {
+            HttpURLConnection.setFollowRedirects(true);
+            Authenticator.setDefault(authentication);
         } catch (SecurityException e) {
         }
-	}
+    }
 
-	/**
-	 * The authentication class handling the login requests.
-	 */
-	private static class OsmAuth extends Authenticator {
-		/**
-		 * Set to true, when the autenticator tried the password once.
-		 */
-		boolean passwordtried = false;
-		/**
-		 * Whether the user cancelled the password dialog
-		 */
-		boolean authCancelled = false;
+    /**
+     * The authentication class handling the login requests.
+     */
+    private static class OsmAuth extends Authenticator {
+        /**
+         * Set to true, when the autenticator tried the password once.
+         */
+        boolean passwordtried = false;
+        /**
+         * Whether the user cancelled the password dialog
+         */
+        boolean authCancelled = false;
 
-		@Override protected PasswordAuthentication getPasswordAuthentication() {
-			String username = Main.pref.get("osm-server.username");
-			String password = Main.pref.get("osm-server.password");
-			if (passwordtried || username.equals("") || password.equals("")) {
-				JPanel p = new JPanel(new GridBagLayout());
-				if (!username.equals("") && !password.equals(""))
-					p.add(new JLabel(tr("Incorrect password or username.")), GBC.eop());
-				p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,10,0));
-				JTextField usernameField = new JTextField(username, 20);
-				p.add(usernameField, GBC.eol());
-				p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,10,0));
-				JPasswordField passwordField = new JPasswordField(password, 20);
-				p.add(passwordField, GBC.eol());
-				JLabel warning = new JLabel(tr("Warning: The password is transferred unencrypted."));
-				warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
-				p.add(warning, GBC.eop());
+        @Override protected PasswordAuthentication getPasswordAuthentication() {
+            String username = Main.pref.get("osm-server.username");
+            String password = Main.pref.get("osm-server.password");
+            if (passwordtried || username.equals("") || password.equals("")) {
+                JPanel p = new JPanel(new GridBagLayout());
+                if (!username.equals("") && !password.equals(""))
+                    p.add(new JLabel(tr("Incorrect password or username.")), GBC.eop());
+                p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,10,0));
+                JTextField usernameField = new JTextField(username, 20);
+                p.add(usernameField, GBC.eol());
+                p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,10,0));
+                JPasswordField passwordField = new JPasswordField(password, 20);
+                p.add(passwordField, GBC.eol());
+                JLabel warning = new JLabel(tr("Warning: The password is transferred unencrypted."));
+                warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
+                p.add(warning, GBC.eop());
 
-				JCheckBox savePassword = new JCheckBox(tr("Save user and password (unencrypted)"), !username.equals("") && !password.equals(""));
-				p.add(savePassword, GBC.eop());
+                JCheckBox savePassword = new JCheckBox(tr("Save user and password (unencrypted)"), !username.equals("") && !password.equals(""));
+                p.add(savePassword, GBC.eop());
 
-				int choice = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter Password"), JOptionPane.OK_CANCEL_OPTION);
-				if (choice == JOptionPane.CANCEL_OPTION) {
-					authCancelled = true;
-					return null;
-				}
-				username = usernameField.getText();
-				password = String.valueOf(passwordField.getPassword());
-				if (savePassword.isSelected()) {
-					Main.pref.put("osm-server.username", username);
-					Main.pref.put("osm-server.password", password);
-				}
-				if (username.equals(""))
-					return null;
-			}
-			passwordtried = true;
-			return new PasswordAuthentication(username, password.toCharArray());
-		}
-	}
+                int choice = JOptionPane.showConfirmDialog(Main.parent, p, tr("Enter Password"), JOptionPane.OK_CANCEL_OPTION);
+                if (choice == JOptionPane.CANCEL_OPTION) {
+                    authCancelled = true;
+                    return null;
+                }
+                username = usernameField.getText();
+                password = String.valueOf(passwordField.getPassword());
+                if (savePassword.isSelected()) {
+                    Main.pref.put("osm-server.username", username);
+                    Main.pref.put("osm-server.password", password);
+                }
+                if (username.equals(""))
+                    return null;
+            }
+            passwordtried = true;
+            return new PasswordAuthentication(username, password.toCharArray());
+        }
+    }
 
-	/**
-	 * Must be called before each connection attemp to initialize the authentication.
-	 */
-	protected final void initAuthentication() {
-		authentication.authCancelled = false;
-		authentication.passwordtried = false;
-	}
+    /**
+     * Must be called before each connection attemp to initialize the authentication.
+     */
+    protected final void initAuthentication() {
+        authentication.authCancelled = false;
+        authentication.passwordtried = false;
+    }
 
-	/**
-	 * @return Whether the connection was cancelled.
-	 */
-	protected final boolean isAuthCancelled() {
-		return authentication.authCancelled;
-	}
+    /**
+     * @return Whether the connection was cancelled.
+     */
+    protected final boolean isAuthCancelled() {
+        return authentication.authCancelled;
+    }
 
-	public void cancel() {
-		Main.pleaseWaitDlg.currentAction.setText(tr("Aborting..."));
-		cancel = true;
-		if (activeConnection != null) {
-			activeConnection.setConnectTimeout(100);
-			activeConnection.setReadTimeout(100);
-			try {
-				Thread.sleep(100);
-			} catch (InterruptedException ex) {}
-			activeConnection.disconnect();
-		}
-	}
+    public void cancel() {
+        Main.pleaseWaitDlg.currentAction.setText(tr("Aborting..."));
+        cancel = true;
+        if (activeConnection != null) {
+            activeConnection.setConnectTimeout(100);
+            activeConnection.setReadTimeout(100);
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {}
+            activeConnection.disconnect();
+        }
+    }
 
-	protected void addAuth(HttpURLConnection con) throws CharacterCodingException {
-		CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
-		String auth = Main.pref.get("osm-server.username") + ":" + Main.pref.get("osm-server.password");
-		ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth));
-		con.addRequestProperty("Authorization", "Basic "+Base64.encode(bytes));
-	}
+    protected void addAuth(HttpURLConnection con) throws CharacterCodingException {
+        CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
+        String auth = Main.pref.get("osm-server.username") + ":" + Main.pref.get("osm-server.password");
+        ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth));
+        con.addRequestProperty("Authorization", "Basic "+Base64.encode(bytes));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmIdReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmIdReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmIdReader.java	(revision 1169)
@@ -21,44 +21,44 @@
 /**
  * Read only the ids and classes of an stream.
- * 
+ *
  * @author Imi
  */
 public class OsmIdReader extends DefaultHandler {
 
-	private boolean cancel;
-	Map<Long, String> entries = new HashMap<Long, String>();
-	private Reader in;
+    private boolean cancel;
+    Map<Long, String> entries = new HashMap<Long, String>();
+    private Reader in;
 
-	@Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-		if (qName.equals("node") || qName.equals("way") || qName.equals("relation")) {
-			try {
-				entries.put(Long.valueOf(atts.getValue("id")), qName);
-			} catch (Exception e) {
-				e.printStackTrace();
-				throw new SAXException(tr("Error during parse."));
-			}
-		}
+    @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+        if (qName.equals("node") || qName.equals("way") || qName.equals("relation")) {
+            try {
+                entries.put(Long.valueOf(atts.getValue("id")), qName);
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new SAXException(tr("Error during parse."));
+            }
+        }
     }
 
-	public Map<Long, String> parseIds(InputStream in) throws IOException, SAXException {
+    public Map<Long, String> parseIds(InputStream in) throws IOException, SAXException {
         this.in = new InputStreamReader(in, "UTF-8");
-		try {
-	        SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(this.in), this);
+        try {
+            SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(this.in), this);
         } catch (ParserConfigurationException e) {
-        	if (!cancel) {
-        		e.printStackTrace(); // broken SAXException chaining
-        		throw new SAXException(e);
-        	}
+            if (!cancel) {
+                e.printStackTrace(); // broken SAXException chaining
+                throw new SAXException(e);
+            }
         } catch (SAXException e) {
-        	if (!cancel)
-        		throw e;
-        }        
-		return entries;
-	}
-	
-	public void cancel() {
-		cancel = true;
-		if (in != null)
+            if (!cancel)
+                throw e;
+        }
+        return entries;
+    }
+
+    public void cancel() {
+        cancel = true;
+        if (in != null)
             try {in.close();} catch (IOException e) {}
-	}
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 1169)
@@ -106,10 +106,10 @@
      private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>();
 
-     /** 
+     /**
       * Data structure for relation objects
       */
      private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>();
 
-     /** 
+     /**
       * List of protocol versions that will be accepted on reading
       */
@@ -133,9 +133,9 @@
                          generator = atts.getValue("generator");
 
-                         
+
                     } else if (qName.equals("bound")) {
                          // old style bounds.
                          // TODO: remove this around 1st October 2008.
-                         // - this is a bit of a hack; since we still write out old style bound objects, 
+                         // - this is a bit of a hack; since we still write out old style bound objects,
                          // we don't want to load them both. so when writing, we add a "note" tag the our
                          // old-style bound, and when reading, ignore those with a "note".
@@ -172,7 +172,7 @@
                               ds.dataSources.add(src);
                          }
-                         
+
                     // ---- PARSING NODES AND WAYS ----
-                         
+
                     } else if (qName.equals("node")) {
                          current = new Node(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon")));
@@ -192,5 +192,5 @@
                          list.add(id);
 
-                    // ---- PARSING RELATIONS ----               
+                    // ---- PARSING RELATIONS ----
 
                     } else if (qName.equals("relation")) {
@@ -207,12 +207,12 @@
                          emd.type=atts.getValue("type");
                          emd.relationMember.role = atts.getValue("role");
-                         
+
                          if (emd.id == 0)
                               throw new SAXException(tr("Incomplete <member> specification with ref=0"));
-                         
+
                          list.add(emd);
-                         
+
                     // ---- PARSING TAGS (applicable to all objects) ----
-                         
+
                     } else if (qName.equals("tag")) {
                          current.put(atts.getValue("k"), atts.getValue("v"));
@@ -231,6 +231,6 @@
           }
      }
-     
-     /** 
+
+     /**
       * Constructor initializes list of allowed protocol versions.
       */
@@ -239,9 +239,9 @@
           allowedVersions.add(Main.pref.get("osm-server.version", "0.5"));
           // now also add all compatible versions
-          String[] additionalVersions = 
+          String[] additionalVersions =
                Main.pref.get("osm-server.additional-versions", "").split("/,/");
           if (additionalVersions.length == 1 && additionalVersions[0].length() == 0)
                additionalVersions = new String[] {};
-          allowedVersions.addAll(Arrays.asList(additionalVersions));     
+          allowedVersions.addAll(Arrays.asList(additionalVersions));
      }
 
@@ -267,5 +267,5 @@
                current.timestamp = time;
           }
-          
+
           // user attribute added in 0.4 API
           String user = atts.getValue("user");
@@ -274,5 +274,5 @@
                current.user = User.get(user);
           }
-          
+
           // visible attribute added in 0.4 API
           String visible = atts.getValue("visible");
@@ -342,5 +342,5 @@
                adder.visit(w);
           }
-          
+
      }
 
@@ -348,5 +348,5 @@
       * Return the Way object with the given id, or null if it doesn't
       * exist yet. This method only looks at ways stored in the data set.
-      * 
+      *
       * @param id
       * @return way object or null
@@ -365,5 +365,5 @@
       * Return the Relation object with the given id, or null if it doesn't
       * exist yet. This method only looks at relations stored in the data set.
-      * 
+      *
       * @param id
       * @return relation object or null
@@ -380,5 +380,5 @@
 
      /**
-      * Create relations. This is slightly different than n/s/w because 
+      * Create relations. This is slightly different than n/s/w because
       * unlike other objects, relations may reference other relations; it
       * is not guaranteed that a referenced relation will have been created
@@ -387,5 +387,5 @@
       */
      private void createRelations() {
-          
+
           // pass 1 - create all relations
           for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) {
@@ -399,5 +399,5 @@
                Relation en = findRelation(e.getKey().id);
                if (en == null) throw new Error("Failed to create relation " + e.getKey().id);
-               
+
                for (RelationMemberData emd : e.getValue()) {
                     RelationMember em = emd.relationMember;
Index: trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 1169)
@@ -12,11 +12,11 @@
 
 public class OsmServerLocationReader extends OsmServerReader {
- 
+
     String url;
-    
+
     public OsmServerLocationReader(String url) {
         this.url = url;
     }
-    
+
     /**
      * Method to download OSM files from somewhere
Index: trunk/src/org/openstreetmap/josm/io/OsmServerObjectReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerObjectReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerObjectReader.java	(revision 1169)
@@ -20,5 +20,5 @@
     String type;
     boolean full;
-    
+
     public OsmServerObjectReader(long id, String type, boolean full) {
         this.id = id;
Index: trunk/src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 1169)
@@ -19,5 +19,5 @@
 /**
  * This DataReader reads directly from the REST API of the osm server.
- * 
+ *
  * It supports plain text transfer as well as gzip or deflate encoded transfers;
  * if compressed transfers are unwanted, set property osm-server.use-compression
@@ -27,52 +27,52 @@
  */
 public abstract class OsmServerReader extends OsmConnection {
-	/**
-	 * Open a connection to the given url and return a reader on the input stream
-	 * from that connection. In case of user cancel, return <code>null</code>.
-	 * @param urlStr The exact url to connect to.
-	 * @param pleaseWaitDlg
-	 * @return An reader reading the input stream (servers answer) or <code>null</code>.
-	 */
-	protected InputStream getInputStream(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws IOException {
-		String version = Main.pref.get("osm-server.version", "0.5");
-		urlStr = Main.pref.get("osm-server.url")+"/"+version+"/" + urlStr;
+    /**
+     * Open a connection to the given url and return a reader on the input stream
+     * from that connection. In case of user cancel, return <code>null</code>.
+     * @param urlStr The exact url to connect to.
+     * @param pleaseWaitDlg
+     * @return An reader reading the input stream (servers answer) or <code>null</code>.
+     */
+    protected InputStream getInputStream(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws IOException {
+        String version = Main.pref.get("osm-server.version", "0.5");
+        urlStr = Main.pref.get("osm-server.url")+"/"+version+"/" + urlStr;
         return getInputStreamRaw(urlStr, pleaseWaitDlg);
     }
-    
+
     protected InputStream getInputStreamRaw(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws IOException {
-        
-		System.out.println("download: "+urlStr);
-		initAuthentication();
-		URL url = new URL(urlStr);
-		activeConnection = (HttpURLConnection)url.openConnection();
-		if (cancel) {
-			activeConnection.disconnect();
-			return null;
-		}
-		
-		if (Boolean.parseBoolean(Main.pref.get("osm-server.use-compression", "true")))
-			activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
 
-		activeConnection.setConnectTimeout(15000);
-		if (isAuthCancelled() && activeConnection.getResponseCode() == 401)
-			return null;
-		if (activeConnection.getResponseCode() == 500)
-		{
-			throw new IOException(tr("Server returned internal error. Try a reduced area or retry after waiting some time."));
-		}
-//		System.out.println("got return: "+activeConnection.getResponseCode());
+        System.out.println("download: "+urlStr);
+        initAuthentication();
+        URL url = new URL(urlStr);
+        activeConnection = (HttpURLConnection)url.openConnection();
+        if (cancel) {
+            activeConnection.disconnect();
+            return null;
+        }
 
-		String encoding = activeConnection.getContentEncoding();
-		InputStream inputStream = new ProgressInputStream(activeConnection, pleaseWaitDlg);
-		if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
-			inputStream = new GZIPInputStream(inputStream);
-		}
-		else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
-			inputStream = new InflaterInputStream(inputStream, new Inflater(true));
-		}
-		return inputStream;
-	}
-    
+        if (Boolean.parseBoolean(Main.pref.get("osm-server.use-compression", "true")))
+            activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
+
+        activeConnection.setConnectTimeout(15000);
+        if (isAuthCancelled() && activeConnection.getResponseCode() == 401)
+            return null;
+        if (activeConnection.getResponseCode() == 500)
+        {
+            throw new IOException(tr("Server returned internal error. Try a reduced area or retry after waiting some time."));
+        }
+//      System.out.println("got return: "+activeConnection.getResponseCode());
+
+        String encoding = activeConnection.getContentEncoding();
+        InputStream inputStream = new ProgressInputStream(activeConnection, pleaseWaitDlg);
+        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+            inputStream = new GZIPInputStream(inputStream);
+        }
+        else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+            inputStream = new InflaterInputStream(inputStream, new Inflater(true));
+        }
+        return inputStream;
+    }
+
     public abstract DataSet parseOsm() throws SAXException, IOException;
-    
+
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 1169)
@@ -79,5 +79,5 @@
 
     long uploadStartTime;
-    
+
     public String timeLeft(int progress, int list_size) {
         long now = System.currentTimeMillis();
@@ -96,5 +96,5 @@
         return time_left_str;
     }
-    
+
     public void uploadOsm(Collection<OsmPrimitive> list) throws SAXException {
         processed = new LinkedList<OsmPrimitive>();
@@ -103,15 +103,15 @@
         Main.pleaseWaitDlg.progress.setMaximum(list.size());
         Main.pleaseWaitDlg.progress.setValue(0);
-        
+
         // controls whether or not we open and close a changeset. API 0.6 requires changesets.
         boolean useChangesets = Main.pref.get("osm-server.version", "0.5").equals("0.6");
-        
+
         // controls whether or not we try and uplaod the whole bunch in one go
-        boolean useDiffUploads = Main.pref.getBoolean("osm-server.atomic-upload", 
+        boolean useDiffUploads = Main.pref.getBoolean("osm-server.atomic-upload",
             Main.pref.get("osm-server.version", "0.5").equals("0.6"));
-        
+
         String comment = null;
         while (useChangesets && comment == null) {
-            comment = JOptionPane.showInputDialog(Main.parent, 
+            comment = JOptionPane.showInputDialog(Main.parent,
                  tr("Provide a brief comment as to the changes to you are uploading:"),
                  tr("Commit comment"), JOptionPane.QUESTION_MESSAGE);
@@ -131,5 +131,5 @@
             return;
         }
-    
+
         try {
             if (useDiffUploads) {
@@ -166,10 +166,10 @@
             }
             catch (OsmTransferException ex) {
-                dealWithTransferException(ex);    
+                dealWithTransferException(ex);
             }
             dealWithTransferException(e);
         }
     }
-    
+
     /* FIXME: This code is terrible, please fix it!!!! */
 
@@ -183,5 +183,5 @@
      * can fix the issue where hitting cancel doesn't do anything while
      * retrying. - Mv0 Apr 2008
-     * 
+     *
      * Cancelling has an effect now, maybe it does not always catch on. Florian Heer, Aug 08
      */
@@ -198,5 +198,5 @@
                     Main.pref.get("osm-server.url") +
                     "/" + version +
-                    "/" + "changeset" + 
+                    "/" + "changeset" +
                     "/" + "create");
             System.out.print("upload to: "+url+ "..." );
@@ -205,10 +205,10 @@
             activeConnection.setRequestMethod("PUT");
             addAuth(activeConnection);
-            
+
             activeConnection.setDoOutput(true);
             OutputStream out = activeConnection.getOutputStream();
             OsmWriter.output(out, changeset);
             out.close();
-            
+
             activeConnection.connect();
             System.out.println("connected");
@@ -224,5 +224,5 @@
             }
             if (retCode != 200 && retCode != 412) {
-                
+
                 if (retries >= 0) {
                     retries--;
@@ -232,5 +232,5 @@
                     return startChangeset(retries, comment);
                 }
-                
+
                 // Look for a detailed error message from the server
                 retMsg += "\n" + readString(activeConnection.getInputStream());
@@ -262,5 +262,5 @@
                 throw new OsmTransferException (e.getMessage()+ " " + e.getClass().getCanonicalName(), e);
         }
-        
+
         catch (Exception e) {
             if (cancel)
@@ -274,7 +274,7 @@
         return true;
     }
-    
+
     private void uploadDiff(int retries, Collection<OsmPrimitive> list) throws OsmTransferException {
-        
+
         CreateOsmChangeVisitor duv = new CreateOsmChangeVisitor(changeset);
 
@@ -290,5 +290,5 @@
         String diff = duv.getDocument();
         System.out.println(diff);
-        
+
         Main.pleaseWaitDlg.currentAction.setText(tr("Uploading..."));
         try {
@@ -299,5 +299,5 @@
                     Main.pref.get("osm-server.url") +
                     "/" + version +
-                    "/" + "changeset" + 
+                    "/" + "changeset" +
                     "/" + changeset.id +
                     "/upload" );
@@ -307,5 +307,5 @@
             activeConnection.setRequestMethod("POST");
             addAuth(activeConnection);
-            
+
             activeConnection.setDoOutput(true);
             PrintWriter out;
@@ -317,5 +317,5 @@
             out.print(diff);
             out.close();
-            
+
             activeConnection.connect();
             System.out.println("connected");
@@ -323,5 +323,5 @@
             int retCode = activeConnection.getResponseCode();
             String retMsg = "";
-            
+
             if (retCode == 200) {
                 DiffResultReader.parseDiffResult(activeConnection.getInputStream(), list, processed, duv.getNewIdMap(), Main.pleaseWaitDlg);
@@ -333,5 +333,5 @@
                     System.out.println("retrying ("+retries+" left)");
                     stopChangeset(retries);
-                } else { 
+                } else {
                     // Look for a detailed error message from the server
                     retMsg += "\n" + readString(activeConnection.getInputStream());
@@ -372,6 +372,6 @@
         }
     }
-    
-    
+
+
     private void stopChangeset(int retries) throws OsmTransferException {
         Main.pleaseWaitDlg.currentAction.setText(tr("Closing changeset..."));
@@ -383,5 +383,5 @@
                     Main.pref.get("osm-server.url") +
                     "/" + version +
-                    "/" + "changeset" + 
+                    "/" + "changeset" +
                     "/" + changeset.id +
                     "/close" );
@@ -391,10 +391,10 @@
             activeConnection.setRequestMethod("PUT");
             addAuth(activeConnection);
-            
+
             activeConnection.setDoOutput(true);
             OutputStream out = activeConnection.getOutputStream();
             OsmWriter.output(out, changeset);
             out.close();
-            
+
             activeConnection.connect();
             System.out.println("connected");
@@ -415,8 +415,8 @@
                     System.out.println("retrying ("+retries+" left)");
                     stopChangeset(retries);
-                } else { 
+                } else {
                     // Look for a detailed error message from the server
                     retMsg += readString(activeConnection.getInputStream());
-                    
+
                     // Report our error
                     ByteArrayOutputStream o = new ByteArrayOutputStream();
@@ -490,5 +490,5 @@
         processed.add(e);
     }
-    
+
     /**
      * Read a long from the input stream and return it.
@@ -540,5 +540,5 @@
                     new URL(Main.pref.get("osm-server.url") +
                     "/" + version + "/"),
-                    urlSuffix + 
+                    urlSuffix +
                     "/" + (osm.id==0 ? "create" : osm.id),
                     new MyHttpHandler());
@@ -622,5 +622,5 @@
         }
     }
-    
+
     private void sendRequest(String requestMethod, String urlSuffix,
             OsmPrimitive osm, boolean addBody)  {
@@ -636,5 +636,5 @@
         }
     }
-    
+
     private void dealWithTransferException (OsmTransferException e) {
         Main.pleaseWaitDlg.currentAction.setText(tr("Transfer aborted due to error (will wait for 5 seconds):") + e.getMessage());
Index: trunk/src/org/openstreetmap/josm/io/OsmTransferException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmTransferException.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmTransferException.java	(revision 1169)
@@ -4,18 +4,18 @@
 public class OsmTransferException extends Exception {
 
-	public OsmTransferException() {
-	}
+    public OsmTransferException() {
+    }
 
-	public OsmTransferException(String message) {
-		super(message);
-	}
+    public OsmTransferException(String message) {
+        super(message);
+    }
 
-	public OsmTransferException(Throwable cause) {
-		super(cause);
-	}
+    public OsmTransferException(Throwable cause) {
+        super(cause);
+    }
 
-	public OsmTransferException(String message, Throwable cause) {
-		super(message, cause);
-	}
+    public OsmTransferException(String message, Throwable cause) {
+        super(message, cause);
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 1169)
@@ -24,200 +24,200 @@
 public class OsmWriter extends XmlWriter implements Visitor {
 
-	/**
-	 * The counter for new created objects. Starting at -1 and goes down.
-	 */
-	private long newIdCounter = -1;
-	/**
-	 * All newly created ids and their primitive that uses it. This is a back reference
-	 * map to allow references to use the correnct primitives.
-	 */
-	public HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
-
-	private final boolean osmConform;
-	private final Changeset changeset;
-
-	public abstract static class Osm implements OsmWriterInterface {
-		public void header(PrintWriter out) {
-			out.print("<osm version='");
-			out.print(Main.pref.get("osm-server.version", "0.5"));
-			out.println("' generator='JOSM'>");
-		}
-		public void footer(PrintWriter out) {
-			out.println("</osm>");
-		}
-	}
-	
-	// simple helper to write the object's class to the out stream
-	private Visitor typeWriteVisitor = new Visitor() {
-		public void visit(Node n) { out.print("node"); }
-		public void visit(Way w) { out.print("way"); }
-		public void visit(Relation e) { out.print("relation"); }
-	};
-	
-	/**
-	 * An output writer for function output that writes everything of the given dataset into
-	 * the xml
-	 */
-	public static final class All extends Osm {
-		private final DataSet ds;
-		private final boolean osmConform;
-
-		/**
-		 * Construct an writer function
-		 * @param osmConform <code>true</code>, if the xml should be 100% osm conform. In this
-		 * 		case, not all information can be retrieved later (as example, modified state
-		 * 		is lost and id's remain 0 instead of decrementing from -1)
-		 */
-		public All(DataSet ds, boolean osmConform) {
-			this.ds = ds;
-			this.osmConform = osmConform;
-		}
-
-		public void write(PrintWriter out) {
-			Visitor writer = new OsmWriter(out, osmConform, null);
-			for (Node n : ds.nodes)
-				if (shouldWrite(n))
-					writer.visit(n);
-			for (Way w : ds.ways)
-				if (shouldWrite(w))
-					writer.visit(w);
-			for (Relation e : ds.relations)
-				if (shouldWrite(e))
-					writer.visit(e);
-        }
-
-		private boolean shouldWrite(OsmPrimitive osm) {
-	        return osm.id != 0 || !osm.deleted;
-        }
-
-		@Override public void header(PrintWriter out) {
-	        super.header(out);
-			for (DataSource s : ds.dataSources) {
+    /**
+     * The counter for new created objects. Starting at -1 and goes down.
+     */
+    private long newIdCounter = -1;
+    /**
+     * All newly created ids and their primitive that uses it. This is a back reference
+     * map to allow references to use the correnct primitives.
+     */
+    public HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
+
+    private final boolean osmConform;
+    private final Changeset changeset;
+
+    public abstract static class Osm implements OsmWriterInterface {
+        public void header(PrintWriter out) {
+            out.print("<osm version='");
+            out.print(Main.pref.get("osm-server.version", "0.5"));
+            out.println("' generator='JOSM'>");
+        }
+        public void footer(PrintWriter out) {
+            out.println("</osm>");
+        }
+    }
+
+    // simple helper to write the object's class to the out stream
+    private Visitor typeWriteVisitor = new Visitor() {
+        public void visit(Node n) { out.print("node"); }
+        public void visit(Way w) { out.print("way"); }
+        public void visit(Relation e) { out.print("relation"); }
+    };
+
+    /**
+     * An output writer for function output that writes everything of the given dataset into
+     * the xml
+     */
+    public static final class All extends Osm {
+        private final DataSet ds;
+        private final boolean osmConform;
+
+        /**
+         * Construct an writer function
+         * @param osmConform <code>true</code>, if the xml should be 100% osm conform. In this
+         *      case, not all information can be retrieved later (as example, modified state
+         *      is lost and id's remain 0 instead of decrementing from -1)
+         */
+        public All(DataSet ds, boolean osmConform) {
+            this.ds = ds;
+            this.osmConform = osmConform;
+        }
+
+        public void write(PrintWriter out) {
+            Visitor writer = new OsmWriter(out, osmConform, null);
+            for (Node n : ds.nodes)
+                if (shouldWrite(n))
+                    writer.visit(n);
+            for (Way w : ds.ways)
+                if (shouldWrite(w))
+                    writer.visit(w);
+            for (Relation e : ds.relations)
+                if (shouldWrite(e))
+                    writer.visit(e);
+        }
+
+        private boolean shouldWrite(OsmPrimitive osm) {
+            return osm.id != 0 || !osm.deleted;
+        }
+
+        @Override public void header(PrintWriter out) {
+            super.header(out);
+            for (DataSource s : ds.dataSources) {
                 // TODO: remove <bound> output after a grace period (1st October 08)
-				out.print("  <bound note='this tag is deprecated and only provided for backward compatiblity' box='"+
-						s.bounds.min.lat()+","+
-						s.bounds.min.lon()+","+
-						s.bounds.max.lat()+","+
-						s.bounds.max.lon()+"' ");
-				out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
-				out.print("  <bounds minlat='" + 
-						s.bounds.min.lat()+"' minlon='"+
-						s.bounds.min.lon()+"' maxlat='"+
-						s.bounds.max.lat()+"' maxlon='"+
-						s.bounds.max.lon()+"' ");
-				out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
-			}
-        }
-	}
-
-	/**
-	 * An output writer for functino output that writes only one specific primitive into
-	 * the xml
-	 */
-	public static final class Single extends Osm {
-		private final OsmPrimitive osm;
-		private final boolean osmConform;
-		private final Changeset changeset;
-
-		public Single(OsmPrimitive osm, boolean osmConform, Changeset changeset) {
-			this.osm = osm;
-			this.osmConform = osmConform;
-			this.changeset = changeset;
-		}
-
-		public void write(PrintWriter out) {
-			osm.visit(new OsmWriter(out, osmConform, changeset));
-        }
-	}
-
-	public OsmWriter(PrintWriter out, boolean osmConform, Changeset changeset) {
-		super(out);
-		this.osmConform = osmConform;
-		this.changeset = changeset;
-	}
-
-	public void visit(Node n) {
-		if (n.incomplete) return;
-		addCommon(n, "node");
-		out.print(" lat='"+n.coor.lat()+"' lon='"+n.coor.lon()+"'");
-		addTags(n, "node", true);
-	}
-
-	public void visit(Way w) {
-		if (w.incomplete) return;
-		addCommon(w, "way");
-		out.println(">");
-		for (Node n : w.nodes)
-			out.println("    <nd ref='"+getUsedId(n)+"' />");
-		addTags(w, "way", false);
-	}
-
-	public void visit(Relation e) {
-		if (e.incomplete) return;
-		addCommon(e, "relation");
-		out.println(">");
-		for (RelationMember em : e.members) {
-			out.print("    <member type='");
-			em.member.visit(typeWriteVisitor);
-			out.println("' ref='"+getUsedId(em.member)+"' role='" + 
-				XmlWriter.encode(em.role) + "' />");
-		}
-		addTags(e, "relation", false);
-	}
-	
-
-	/**
-	 * Return the id for the given osm primitive (may access the usedId map)
-	 */
-	private long getUsedId(OsmPrimitive osm) {
-		if (osm.id != 0)
-			return osm.id;
-		if (usedNewIds.containsKey(osm))
-			return usedNewIds.get(osm);
-		usedNewIds.put(osm, newIdCounter);
-		return osmConform ? 0 : newIdCounter--;
-	}
-
-	private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
-		if (osm.keys != null) {
-			if (tagOpen)
-				out.println(">");
-			for (Entry<String, String> e : osm.keys.entrySet())
-				out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
-						"' v='"+XmlWriter.encode(e.getValue())+ "' />");
-			out.println("  </" + tagname + ">");
-		} else if (tagOpen)
-			out.println(" />");
-		else
-			out.println("  </" + tagname + ">");
-	}
-
-	/**
-	 * Add the common part as the form of the tag as well as the XML attributes
-	 * id, action, user, and visible.
-	 */
-	private void addCommon(OsmPrimitive osm, String tagname) {
-		out.print("  <"+tagname+" id='"+getUsedId(osm)+"'");
-		if (!osmConform) {
-			String action = null;
-			if (osm.deleted)
-				action = "delete";
-			else if (osm.modified)
-				action = "modify";
-			if (action != null)
-				out.print(" action='"+action+"'");
-		}
-		if (osm.timestamp != null) {
-			out.print(" timestamp='"+osm.timestamp+"'");
-		}
-		// user and visible added with 0.4 API
-		if (osm.user != null) {
-			out.print(" user='"+XmlWriter.encode(osm.user.name)+"'");
-		}
-		out.print(" visible='"+osm.visible+"'");
-		if (osm.version != -1)
-			out.print(" version='"+osm.version+"'");
-		if (this.changeset != null && this.changeset.id != 0)
-			out.print(" changeset='"+this.changeset.id+"'" );
-	}
+                out.print("  <bound note='this tag is deprecated and only provided for backward compatiblity' box='"+
+                        s.bounds.min.lat()+","+
+                        s.bounds.min.lon()+","+
+                        s.bounds.max.lat()+","+
+                        s.bounds.max.lon()+"' ");
+                out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
+                out.print("  <bounds minlat='" +
+                        s.bounds.min.lat()+"' minlon='"+
+                        s.bounds.min.lon()+"' maxlat='"+
+                        s.bounds.max.lat()+"' maxlon='"+
+                        s.bounds.max.lon()+"' ");
+                out.println("origin='"+XmlWriter.encode(s.origin)+"' />");
+            }
+        }
+    }
+
+    /**
+     * An output writer for functino output that writes only one specific primitive into
+     * the xml
+     */
+    public static final class Single extends Osm {
+        private final OsmPrimitive osm;
+        private final boolean osmConform;
+        private final Changeset changeset;
+
+        public Single(OsmPrimitive osm, boolean osmConform, Changeset changeset) {
+            this.osm = osm;
+            this.osmConform = osmConform;
+            this.changeset = changeset;
+        }
+
+        public void write(PrintWriter out) {
+            osm.visit(new OsmWriter(out, osmConform, changeset));
+        }
+    }
+
+    public OsmWriter(PrintWriter out, boolean osmConform, Changeset changeset) {
+        super(out);
+        this.osmConform = osmConform;
+        this.changeset = changeset;
+    }
+
+    public void visit(Node n) {
+        if (n.incomplete) return;
+        addCommon(n, "node");
+        out.print(" lat='"+n.coor.lat()+"' lon='"+n.coor.lon()+"'");
+        addTags(n, "node", true);
+    }
+
+    public void visit(Way w) {
+        if (w.incomplete) return;
+        addCommon(w, "way");
+        out.println(">");
+        for (Node n : w.nodes)
+            out.println("    <nd ref='"+getUsedId(n)+"' />");
+        addTags(w, "way", false);
+    }
+
+    public void visit(Relation e) {
+        if (e.incomplete) return;
+        addCommon(e, "relation");
+        out.println(">");
+        for (RelationMember em : e.members) {
+            out.print("    <member type='");
+            em.member.visit(typeWriteVisitor);
+            out.println("' ref='"+getUsedId(em.member)+"' role='" +
+                XmlWriter.encode(em.role) + "' />");
+        }
+        addTags(e, "relation", false);
+    }
+
+
+    /**
+     * Return the id for the given osm primitive (may access the usedId map)
+     */
+    private long getUsedId(OsmPrimitive osm) {
+        if (osm.id != 0)
+            return osm.id;
+        if (usedNewIds.containsKey(osm))
+            return usedNewIds.get(osm);
+        usedNewIds.put(osm, newIdCounter);
+        return osmConform ? 0 : newIdCounter--;
+    }
+
+    private void addTags(OsmPrimitive osm, String tagname, boolean tagOpen) {
+        if (osm.keys != null) {
+            if (tagOpen)
+                out.println(">");
+            for (Entry<String, String> e : osm.keys.entrySet())
+                out.println("    <tag k='"+ XmlWriter.encode(e.getKey()) +
+                        "' v='"+XmlWriter.encode(e.getValue())+ "' />");
+            out.println("  </" + tagname + ">");
+        } else if (tagOpen)
+            out.println(" />");
+        else
+            out.println("  </" + tagname + ">");
+    }
+
+    /**
+     * Add the common part as the form of the tag as well as the XML attributes
+     * id, action, user, and visible.
+     */
+    private void addCommon(OsmPrimitive osm, String tagname) {
+        out.print("  <"+tagname+" id='"+getUsedId(osm)+"'");
+        if (!osmConform) {
+            String action = null;
+            if (osm.deleted)
+                action = "delete";
+            else if (osm.modified)
+                action = "modify";
+            if (action != null)
+                out.print(" action='"+action+"'");
+        }
+        if (osm.timestamp != null) {
+            out.print(" timestamp='"+osm.timestamp+"'");
+        }
+        // user and visible added with 0.4 API
+        if (osm.user != null) {
+            out.print(" user='"+XmlWriter.encode(osm.user.name)+"'");
+        }
+        out.print(" visible='"+osm.visible+"'");
+        if (osm.version != -1)
+            out.print(" version='"+osm.version+"'");
+        if (this.changeset != null && this.changeset.id != 0)
+            out.print(" changeset='"+this.changeset.id+"'" );
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/ProgressInputStream.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/ProgressInputStream.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/ProgressInputStream.java	(revision 1169)
@@ -16,83 +16,83 @@
 public class ProgressInputStream extends InputStream {
 
-	private final InputStream in;
-	private int readSoFar = 0;
-	private int lastDialogUpdate = 0;
-	private final URLConnection connection;
-	private PleaseWaitDialog pleaseWaitDlg;
+    private final InputStream in;
+    private int readSoFar = 0;
+    private int lastDialogUpdate = 0;
+    private final URLConnection connection;
+    private PleaseWaitDialog pleaseWaitDlg;
 
-	public class OsmServerException extends IOException {
-		private OsmServerException(String e) {
-			super(e);
-		}
-	}
+    public class OsmServerException extends IOException {
+        private OsmServerException(String e) {
+            super(e);
+        }
+    }
 
-	public ProgressInputStream(URLConnection con, PleaseWaitDialog pleaseWaitDlg) throws IOException, OsmServerException {
-		this.connection = con;
+    public ProgressInputStream(URLConnection con, PleaseWaitDialog pleaseWaitDlg) throws IOException, OsmServerException {
+        this.connection = con;
 
-		try {
-			this.in = con.getInputStream();
-		} catch (IOException e) {
-			if (con.getHeaderField("Error") != null)
-				throw new OsmServerException(tr(con.getHeaderField("Error")));
-			throw e;
-		}
+        try {
+            this.in = con.getInputStream();
+        } catch (IOException e) {
+            if (con.getHeaderField("Error") != null)
+                throw new OsmServerException(tr(con.getHeaderField("Error")));
+            throw e;
+        }
 
-		int contentLength = con.getContentLength();
-		this.pleaseWaitDlg = pleaseWaitDlg;
-		if (pleaseWaitDlg == null)
-			return;
-		if (contentLength > 0)
-			pleaseWaitDlg.progress.setMaximum(contentLength);
-		else
-			pleaseWaitDlg.progress.setMaximum(0);
-		pleaseWaitDlg.progress.setValue(0);
-	}
+        int contentLength = con.getContentLength();
+        this.pleaseWaitDlg = pleaseWaitDlg;
+        if (pleaseWaitDlg == null)
+            return;
+        if (contentLength > 0)
+            pleaseWaitDlg.progress.setMaximum(contentLength);
+        else
+            pleaseWaitDlg.progress.setMaximum(0);
+        pleaseWaitDlg.progress.setValue(0);
+    }
 
-	@Override public void close() throws IOException {
-		in.close();
-	}
+    @Override public void close() throws IOException {
+        in.close();
+    }
 
-	@Override public int read(byte[] b, int off, int len) throws IOException {
-		int read = in.read(b, off, len);
-		if (read != -1)
-			advanceTicker(read);
-		return read;
-	}
+    @Override public int read(byte[] b, int off, int len) throws IOException {
+        int read = in.read(b, off, len);
+        if (read != -1)
+            advanceTicker(read);
+        return read;
+    }
 
-	@Override public int read() throws IOException {
-		int read = in.read();
-		if (read != -1)
-			advanceTicker(1);
-		return read;
-	}
+    @Override public int read() throws IOException {
+        int read = in.read();
+        if (read != -1)
+            advanceTicker(1);
+        return read;
+    }
 
-	/**
-	 * Increase ticker (progress counter and displayed text) by the given amount.
-	 * @param amount
-	 */
-	private void advanceTicker(int amount) {
-		if (pleaseWaitDlg == null)
-			return;
+    /**
+     * Increase ticker (progress counter and displayed text) by the given amount.
+     * @param amount
+     */
+    private void advanceTicker(int amount) {
+        if (pleaseWaitDlg == null)
+            return;
 
-		if (pleaseWaitDlg.progress.getMaximum() == 0 && connection.getContentLength() != -1)
-			pleaseWaitDlg.progress.setMaximum(connection.getContentLength());
+        if (pleaseWaitDlg.progress.getMaximum() == 0 && connection.getContentLength() != -1)
+            pleaseWaitDlg.progress.setMaximum(connection.getContentLength());
 
-		readSoFar += amount;
+        readSoFar += amount;
 
-		if (readSoFar / 1024 != lastDialogUpdate) {
-			lastDialogUpdate++;
-			String progStr = " "+readSoFar/1024+"/";
-			progStr += (pleaseWaitDlg.progress.getMaximum()==0) ? "??? KB" : (pleaseWaitDlg.progress.getMaximum()/1024)+" KB";
-			pleaseWaitDlg.progress.setValue(readSoFar);
+        if (readSoFar / 1024 != lastDialogUpdate) {
+            lastDialogUpdate++;
+            String progStr = " "+readSoFar/1024+"/";
+            progStr += (pleaseWaitDlg.progress.getMaximum()==0) ? "??? KB" : (pleaseWaitDlg.progress.getMaximum()/1024)+" KB";
+            pleaseWaitDlg.progress.setValue(readSoFar);
 
-			String cur = pleaseWaitDlg.currentAction.getText();
-			int i = cur.indexOf(' ');
-			if (i != -1)
-				cur = cur.substring(0, i) + progStr;
-			else
-				cur += progStr;
-			pleaseWaitDlg.currentAction.setText(cur);
-		}
-	}
+            String cur = pleaseWaitDlg.currentAction.getText();
+            int i = cur.indexOf(' ');
+            if (i != -1)
+                cur = cur.substring(0, i) + progStr;
+            else
+                cur += progStr;
+            pleaseWaitDlg.currentAction.setText(cur);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/XmlWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/XmlWriter.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/io/XmlWriter.java	(revision 1169)
@@ -10,75 +10,75 @@
 /**
  * Helper class to use for xml outputting classes.
- * 
+ *
  * @author imi
  */
 public class XmlWriter {
 
-	/**
-	 * The interface to write the data into an Osm stream
-	 * @author immanuel.scholz
-	 */
-	public static interface OsmWriterInterface {
-		void header(PrintWriter out);
-		void write(PrintWriter out);
-		void footer(PrintWriter out);
-	}
+    /**
+     * The interface to write the data into an Osm stream
+     * @author immanuel.scholz
+     */
+    public static interface OsmWriterInterface {
+        void header(PrintWriter out);
+        void write(PrintWriter out);
+        void footer(PrintWriter out);
+    }
 
 
-	protected XmlWriter(PrintWriter out) {
-		this.out = out;
-	}
+    protected XmlWriter(PrintWriter out) {
+        this.out = out;
+    }
 
-	/**
-	 * Encode the given string in XML1.0 format.
-	 * Optimized to fast pass strings that don't need encoding (normal case).
-	 */
-	public static String encode(String unencoded) {
-		StringBuilder buffer = null;
-		for (int i = 0; i < unencoded.length(); ++i) {
-			String encS = XmlWriter.encoding.get(unencoded.charAt(i));
-			if (encS != null) {
-				if (buffer == null)
-					buffer = new StringBuilder(unencoded.substring(0,i));
-				buffer.append(encS);
-			} else if (buffer != null)
-				buffer.append(unencoded.charAt(i));
-		}
-		return (buffer == null) ? unencoded : buffer.toString();
-	}
+    /**
+     * Encode the given string in XML1.0 format.
+     * Optimized to fast pass strings that don't need encoding (normal case).
+     */
+    public static String encode(String unencoded) {
+        StringBuilder buffer = null;
+        for (int i = 0; i < unencoded.length(); ++i) {
+            String encS = XmlWriter.encoding.get(unencoded.charAt(i));
+            if (encS != null) {
+                if (buffer == null)
+                    buffer = new StringBuilder(unencoded.substring(0,i));
+                buffer.append(encS);
+            } else if (buffer != null)
+                buffer.append(unencoded.charAt(i));
+        }
+        return (buffer == null) ? unencoded : buffer.toString();
+    }
 
-	/**
-	 * Write the header and start tag, then call the runnable to add all real tags and finally
-	 * "closes" the xml by writing the footer.
-	 */
-	public static void output(OutputStream outStream, OsmWriterInterface outputWriter) {
-		PrintWriter out;
-		try {
-			out = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8"));
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
-		out.println("<?xml version='1.0' encoding='UTF-8'?>");
-		outputWriter.header(out);
-		outputWriter.write(out);
-		outputWriter.footer(out);
-		out.flush();
-		out.close();
-	}
+    /**
+     * Write the header and start tag, then call the runnable to add all real tags and finally
+     * "closes" the xml by writing the footer.
+     */
+    public static void output(OutputStream outStream, OsmWriterInterface outputWriter) {
+        PrintWriter out;
+        try {
+            out = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        out.println("<?xml version='1.0' encoding='UTF-8'?>");
+        outputWriter.header(out);
+        outputWriter.write(out);
+        outputWriter.footer(out);
+        out.flush();
+        out.close();
+    }
 
-	/**
-	 * The output writer to save the values to.
-	 */
-	protected final PrintWriter out;
-	final private static HashMap<Character, String> encoding = new HashMap<Character, String>();
-	static {
-		encoding.put('<', "&lt;");
-		encoding.put('>', "&gt;");
-		encoding.put('"', "&quot;");
-		encoding.put('\'', "&apos;");
-		encoding.put('&', "&amp;");
-		encoding.put('\n', "&#xA;");
-		encoding.put('\r', "&#xD;");
-		encoding.put('\t', "&#x9;");
-	}
+    /**
+     * The output writer to save the values to.
+     */
+    protected final PrintWriter out;
+    final private static HashMap<Character, String> encoding = new HashMap<Character, String>();
+    static {
+        encoding.put('<', "&lt;");
+        encoding.put('>', "&gt;");
+        encoding.put('"', "&quot;");
+        encoding.put('\'', "&apos;");
+        encoding.put('&', "&amp;");
+        encoding.put('\n', "&#xA;");
+        encoding.put('\r', "&#xD;");
+        encoding.put('\t', "&#x9;");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/plugins/Plugin.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/Plugin.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/plugins/Plugin.java	(revision 1169)
@@ -24,5 +24,5 @@
  *
  * The actual implementation of this class is optional, as all functions will be called
- * via reflection. This is to be able to change this interface without the need of 
+ * via reflection. This is to be able to change this interface without the need of
  * recompiling or even breaking the plugins. If your class does not provide a
  * function here (or does provide a function with a mismatching signature), it will not
@@ -32,5 +32,5 @@
  * are provided (you can register yourself to more callbacks in your plugin class
  * constructor).
- * 
+ *
  * Subclassing Plugin and overriding some functions makes it easy for you to keep sync
  * with the correct actual plugin architecture of JOSM.
@@ -40,52 +40,52 @@
 public abstract class Plugin {
 
-	/**
-	 * This is the info available for this plugin. You can access this from your
-	 * constructor.
-	 *
-	 * (The actual implementation to request the info from a static variable
-	 * is a bit hacky, but it works).
-	 */
-	public final PluginInformation info = PluginInformation.currentPluginInitialization;
+    /**
+     * This is the info available for this plugin. You can access this from your
+     * constructor.
+     *
+     * (The actual implementation to request the info from a static variable
+     * is a bit hacky, but it works).
+     */
+    public final PluginInformation info = PluginInformation.currentPluginInitialization;
 
-	/**
-	 * @return The directory for the plugin to store all kind of stuff.
-	 */
-	public final String getPluginDir() {
-		return new File(Main.pref.getPluginsDirFile(), info.name).getPath();
-	}
+    /**
+     * @return The directory for the plugin to store all kind of stuff.
+     */
+    public final String getPluginDir() {
+        return new File(Main.pref.getPluginsDirFile(), info.name).getPath();
+    }
 
-	/**
-	 * Called after Main.mapFrame is initalized. (After the first data is loaded).
-	 * You can use this callback to tweak the newFrame to your needs, as example install
-	 * an alternative Painter.
-	 */
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {}
+    /**
+     * Called after Main.mapFrame is initalized. (After the first data is loaded).
+     * You can use this callback to tweak the newFrame to your needs, as example install
+     * an alternative Painter.
+     */
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {}
 
-	/**
-	 * Called in the preferences dialog to create a preferences page for the plugin,
-	 * if any available.
-	 */
-	public PreferenceSetting getPreferenceSetting() { return null; }
-	
-	/**
-	 * Called in the download dialog to give the plugin a chance to modify the list
-	 * of bounding box selectors.
-	 */
-	public void addDownloadSelection(List<DownloadSelection> list) {}
-	
-	/**
-	 * Copies the ressource 'from' to the file in the plugin directory named 'to'.
-	 */
-	public void copy(String from, String to) throws FileNotFoundException, IOException {
-		String pluginDirName = Main.pref.getPreferencesDir()+"plugins/"+info.name+"/";
+    /**
+     * Called in the preferences dialog to create a preferences page for the plugin,
+     * if any available.
+     */
+    public PreferenceSetting getPreferenceSetting() { return null; }
+
+    /**
+     * Called in the download dialog to give the plugin a chance to modify the list
+     * of bounding box selectors.
+     */
+    public void addDownloadSelection(List<DownloadSelection> list) {}
+
+    /**
+     * Copies the ressource 'from' to the file in the plugin directory named 'to'.
+     */
+    public void copy(String from, String to) throws FileNotFoundException, IOException {
+        String pluginDirName = Main.pref.getPreferencesDir()+"plugins/"+info.name+"/";
         File pluginDir = new File(pluginDirName);
         if (!pluginDir.exists())
-        	pluginDir.mkdirs();
+            pluginDir.mkdirs();
         FileOutputStream out = new FileOutputStream(pluginDirName+to);
         InputStream in = getClass().getResourceAsStream(from);
         byte[] buffer = new byte[8192];
         for(int len = in.read(buffer); len > 0; len = in.read(buffer))
-        	out.write(buffer, 0, len);
+            out.write(buffer, 0, len);
         in.close();
         out.close();
Index: trunk/src/org/openstreetmap/josm/plugins/PluginDownloader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginDownloader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginDownloader.java	(revision 1169)
@@ -1,5 +1,5 @@
 //License: GPL. Copyright 2007 by Immanuel Scholz and others
 /**
- * 
+ *
  */
 package org.openstreetmap.josm.plugins;
@@ -34,158 +34,158 @@
 public class PluginDownloader {
 
-	private static final class UpdateTask extends PleaseWaitRunnable {
-		private final Collection<PluginDescription> toUpdate;
-		private String errors = "";
-		private int count = 0;
+    private static final class UpdateTask extends PleaseWaitRunnable {
+        private final Collection<PluginDescription> toUpdate;
+        private String errors = "";
+        private int count = 0;
 
-		private UpdateTask(Collection<PluginDescription> toUpdate) {
-			super(tr("Update Plugins"));
-			this.toUpdate = toUpdate;
-		}
+        private UpdateTask(Collection<PluginDescription> toUpdate) {
+            super(tr("Update Plugins"));
+            this.toUpdate = toUpdate;
+        }
 
-		@Override protected void cancel() {
-			finish();
-		}
+        @Override protected void cancel() {
+            finish();
+        }
 
-		@Override protected void finish() {
-			if (errors.length() > 0)
-				JOptionPane.showMessageDialog(Main.parent, tr("There were problems with the following plugins:\n\n {0}",errors));
-			else
-				JOptionPane.showMessageDialog(Main.parent, trn("{0} Plugin successfully updated. Please restart JOSM.", "{0} Plugins successfully updated. Please restart JOSM.", count, count));
-		}
+        @Override protected void finish() {
+            if (errors.length() > 0)
+                JOptionPane.showMessageDialog(Main.parent, tr("There were problems with the following plugins:\n\n {0}",errors));
+            else
+                JOptionPane.showMessageDialog(Main.parent, trn("{0} Plugin successfully updated. Please restart JOSM.", "{0} Plugins successfully updated. Please restart JOSM.", count, count));
+        }
 
-		@Override protected void realRun() throws SAXException, IOException {
-			File pluginDir = Main.pref.getPluginsDirFile();
-			if (!pluginDir.exists())
-				pluginDir.mkdirs();
-			for (PluginDescription d : toUpdate) {
-				File pluginFile = new File(pluginDir, d.name + ".jar.new");
-				if (download(d.resource, pluginFile))
-					count++;
-				else
-					errors += d.name + "\n";
-			}
-			PluginDownloader.moveUpdatedPlugins();
-		}
-	}
+        @Override protected void realRun() throws SAXException, IOException {
+            File pluginDir = Main.pref.getPluginsDirFile();
+            if (!pluginDir.exists())
+                pluginDir.mkdirs();
+            for (PluginDescription d : toUpdate) {
+                File pluginFile = new File(pluginDir, d.name + ".jar.new");
+                if (download(d.resource, pluginFile))
+                    count++;
+                else
+                    errors += d.name + "\n";
+            }
+            PluginDownloader.moveUpdatedPlugins();
+        }
+    }
 
-	private static final Pattern wiki = Pattern.compile("^</td></tr><tr><td><a class=\"ext-link\" href=\"([^\"]*)\"><span class=\"icon\">([^<]*)</span></a></td><td>([^<]*)</td><td>([^<].*)</td><td>(.*)");
+    private static final Pattern wiki = Pattern.compile("^</td></tr><tr><td><a class=\"ext-link\" href=\"([^\"]*)\"><span class=\"icon\">([^<]*)</span></a></td><td>([^<]*)</td><td>([^<].*)</td><td>(.*)");
 
-	private final static String[] pluginSites = {"http://josm.openstreetmap.de/wiki/Plugins"};
+    private final static String[] pluginSites = {"http://josm.openstreetmap.de/wiki/Plugins"};
 
-	public static Collection<String> getSites() {
-		return Main.pref.getCollection("pluginmanager.sites", Arrays.asList(pluginSites));
-	}
+    public static Collection<String> getSites() {
+        return Main.pref.getCollection("pluginmanager.sites", Arrays.asList(pluginSites));
+    }
 
-	public static int downloadDescription() {
-		int count = 0;
-		for (String site : getSites()) {
-			try {
-				BufferedReader r = new BufferedReader(new InputStreamReader(new URL(site).openStream()));
-				CharSequence txt;
-				if (site.toLowerCase().endsWith(".xml"))
-					txt = readXml(r);
-				else
-					txt = readWiki(r);
-				r.close();
-				new File(Main.pref.getPreferencesDir()+"plugins").mkdir();
-				FileWriter out = new FileWriter(new File(Main.pref
-				        .getPluginsDirFile(), count + "-site-"
-				        + site.replaceAll("[/:\\\\ <>|]", "_") + ".xml"));
-				out.append(txt);
-				out.close();
-				count++;
-			} catch (IOException x) {
-			}
-		}
-		return count;
-	}
+    public static int downloadDescription() {
+        int count = 0;
+        for (String site : getSites()) {
+            try {
+                BufferedReader r = new BufferedReader(new InputStreamReader(new URL(site).openStream()));
+                CharSequence txt;
+                if (site.toLowerCase().endsWith(".xml"))
+                    txt = readXml(r);
+                else
+                    txt = readWiki(r);
+                r.close();
+                new File(Main.pref.getPreferencesDir()+"plugins").mkdir();
+                FileWriter out = new FileWriter(new File(Main.pref
+                        .getPluginsDirFile(), count + "-site-"
+                        + site.replaceAll("[/:\\\\ <>|]", "_") + ".xml"));
+                out.append(txt);
+                out.close();
+                count++;
+            } catch (IOException x) {
+            }
+        }
+        return count;
+    }
 
-	private static CharSequence readXml(BufferedReader r) throws IOException {
-		StringBuilder b = new StringBuilder();
-		for (String line = r.readLine(); line != null; line = r.readLine())
-			b.append(line+"\n");
-		return b;
-	}
+    private static CharSequence readXml(BufferedReader r) throws IOException {
+        StringBuilder b = new StringBuilder();
+        for (String line = r.readLine(); line != null; line = r.readLine())
+            b.append(line+"\n");
+        return b;
+    }
 
-	private static CharSequence readWiki(BufferedReader r) throws IOException {
-		StringBuilder b = new StringBuilder("<plugins>\n");
-		for (String line = r.readLine(); line != null; line = r.readLine()) {
-			Matcher m = wiki.matcher(line);
-			if (!m.matches())
-				continue;
-			b.append("  <plugin>\n");
-			b.append("    <name>"+escape(m.group(2))+"</name>\n");
-			b.append("    <resource>"+escape(m.group(1))+"</resource>\n");
-			b.append("    <author>"+escape(m.group(3))+"</author>\n");
-			b.append("    <description>"+escape(m.group(4))+"</description>\n");
-			b.append("    <version>"+escape(m.group(5))+"</version>\n");
-			b.append("  </plugin>\n");
-		}
-		b.append("</plugins>\n");
-		return b;
-	}
+    private static CharSequence readWiki(BufferedReader r) throws IOException {
+        StringBuilder b = new StringBuilder("<plugins>\n");
+        for (String line = r.readLine(); line != null; line = r.readLine()) {
+            Matcher m = wiki.matcher(line);
+            if (!m.matches())
+                continue;
+            b.append("  <plugin>\n");
+            b.append("    <name>"+escape(m.group(2))+"</name>\n");
+            b.append("    <resource>"+escape(m.group(1))+"</resource>\n");
+            b.append("    <author>"+escape(m.group(3))+"</author>\n");
+            b.append("    <description>"+escape(m.group(4))+"</description>\n");
+            b.append("    <version>"+escape(m.group(5))+"</version>\n");
+            b.append("  </plugin>\n");
+        }
+        b.append("</plugins>\n");
+        return b;
+    }
 
-	private static String escape(String s) {
-		return s.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
-	}
+    private static String escape(String s) {
+        return s.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+    }
 
-	public static boolean downloadPlugin(PluginDescription pd) {
-		File file = new File(Main.pref.getPluginsDirFile(), pd.name + ".jar");
-		if (!download(pd.resource, file)) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not download plugin: {0} from {1}", pd.name, pd.resource));
-		} else {
-			try {
-				PluginInformation.findPlugin(pd.name);
-				return true;
-			} catch (Exception e) {
-				e.printStackTrace();
-				JOptionPane.showMessageDialog(Main.parent, tr("The plugin {0} seem to be broken or could not be downloaded automatically.", pd.name));
-			}
-		}
-		if (file.exists())
-			file.delete();
-		return false;
-	}
+    public static boolean downloadPlugin(PluginDescription pd) {
+        File file = new File(Main.pref.getPluginsDirFile(), pd.name + ".jar");
+        if (!download(pd.resource, file)) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Could not download plugin: {0} from {1}", pd.name, pd.resource));
+        } else {
+            try {
+                PluginInformation.findPlugin(pd.name);
+                return true;
+            } catch (Exception e) {
+                e.printStackTrace();
+                JOptionPane.showMessageDialog(Main.parent, tr("The plugin {0} seem to be broken or could not be downloaded automatically.", pd.name));
+            }
+        }
+        if (file.exists())
+            file.delete();
+        return false;
+    }
 
-	private static boolean download(String url, File file) {
-		try {
-			InputStream in = new URL(url).openStream();
-			OutputStream out = new FileOutputStream(file);
-			byte[] buffer = new byte[8192];
-			for (int read = in.read(buffer); read != -1; read = in.read(buffer))
-				out.write(buffer, 0, read);
-			out.close();
-			in.close();
-			return true;
-		} catch (MalformedURLException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return false;
-	}
+    private static boolean download(String url, File file) {
+        try {
+            InputStream in = new URL(url).openStream();
+            OutputStream out = new FileOutputStream(file);
+            byte[] buffer = new byte[8192];
+            for (int read = in.read(buffer); read != -1; read = in.read(buffer))
+                out.write(buffer, 0, read);
+            out.close();
+            in.close();
+            return true;
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
 
-	public static void update(Collection<PluginDescription> update) {
-		Main.worker.execute(new UpdateTask(update));
-	}
-	
-	public static boolean moveUpdatedPlugins() {
-		File pluginDir = Main.pref.getPluginsDirFile();
-		boolean ok = true; 		
-		if (pluginDir.exists() && pluginDir.isDirectory() && pluginDir.canWrite()) {
-			final File[] files = pluginDir.listFiles(new FilenameFilter() {
-				public boolean accept(File dir, String name) {
-	                return name.endsWith(".new");
+    public static void update(Collection<PluginDescription> update) {
+        Main.worker.execute(new UpdateTask(update));
+    }
+
+    public static boolean moveUpdatedPlugins() {
+        File pluginDir = Main.pref.getPluginsDirFile();
+        boolean ok = true;
+        if (pluginDir.exists() && pluginDir.isDirectory() && pluginDir.canWrite()) {
+            final File[] files = pluginDir.listFiles(new FilenameFilter() {
+                public boolean accept(File dir, String name) {
+                    return name.endsWith(".new");
                 }});
-			for (File updatedPlugin : files) {
-				final String filePath = updatedPlugin.getPath();
-				File plugin = new File(filePath.substring(0, filePath.length() - 4));
-				ok = (plugin.delete() || !plugin.exists()) && updatedPlugin.renameTo(plugin) && ok;
-			}
-		}
-		return ok;
-	}
+            for (File updatedPlugin : files) {
+                final String filePath = updatedPlugin.getPath();
+                File plugin = new File(filePath.substring(0, filePath.length() - 4));
+                ok = (plugin.delete() || !plugin.exists()) && updatedPlugin.renameTo(plugin) && ok;
+            }
+        }
+        return ok;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/plugins/PluginException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginException.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginException.java	(revision 1169)
@@ -8,15 +8,15 @@
  * and there is no particular reason to use this within the plugin itself (although there
  * is also no reason against this.. ;)
- * 
+ *
  * @author Immanuel.Scholz
  */
 public class PluginException extends RuntimeException {
-	public final PluginProxy plugin;
-	public final String name;
+    public final PluginProxy plugin;
+    public final String name;
 
-	public PluginException(PluginProxy plugin, String name, Throwable cause) {
-	    super(tr("An error occured in plugin {0}", name), cause);
-		this.plugin = plugin;
-		this.name = name;
+    public PluginException(PluginProxy plugin, String name, Throwable cause) {
+        super(tr("An error occured in plugin {0}", name), cause);
+        this.plugin = plugin;
+        this.name = name;
     }
 }
Index: trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 1169)
@@ -29,207 +29,207 @@
  */
 public class PluginInformation {
-	
-	public final File file;
-	public final String name;
-	public final String mainversion;
-	public final String className;
-	public final String description;
-	public final boolean early;
-	public final String author;
-	public final int stage;
-	public final String version;
-	public final List<URL> libraries = new LinkedList<URL>();
-
-	public final Map<String, String> attr = new TreeMap<String, String>();
-
-	/**
-	 * Used in the Plugin constructor to make the information of the plugin
-	 * that is currently initializing available.
-	 * 
-	 * If you think this is hacky, you are probably right. But it is 
-	 * convinient anyway ;-) 
-	 */
-	static PluginInformation currentPluginInitialization = null;
-
-	/**
-	 * @param file the plugin jar file.
-	 */
-	public PluginInformation(File file) {
-		this(file, file.getName().substring(0, file.getName().length()-4), null);
-	}
-
-	public PluginInformation(File file, String name, InputStream manifestStream) {
-		this.name = name;
-		this.file = file;
-		try {
-			Manifest manifest;
-			JarInputStream jar = null;
-			if (file != null) {
-				jar = new JarInputStream(new FileInputStream(file));
-				manifest = jar.getManifest();
-				if (manifest == null)
-					throw new IOException(file+" contains no manifest.");
-			} else {
-				manifest = new Manifest();
-		        manifest.read(manifestStream);
-			}
-			if (manifest != null) {
-				Attributes attr = manifest.getMainAttributes();
-				className = attr.getValue("Plugin-Class");
-				description = attr.getValue("Plugin-Description");
-				early = Boolean.parseBoolean(attr.getValue("Plugin-Early"));
-				String stageStr = attr.getValue("Plugin-Stage");
-				stage = stageStr == null ? 50 : Integer.parseInt(stageStr);
-				version = attr.getValue("Plugin-Version");
-				mainversion = attr.getValue("Plugin-Mainversion");
-				author = attr.getValue("Author");
-
-				String classPath = attr.getValue(Attributes.Name.CLASS_PATH);
-				if (classPath != null) {
-					for (String entry : classPath.split(" ")) {
-						File entryFile;
-						if (new File(entry).isAbsolute()) {
-							entryFile = new File(entry);
-						} else {
-							entryFile = new File(file.getParent(), entry);
-						}
-
-						libraries.add(fileToURL(entryFile));
-					}
-				}
-				for (Object o : attr.keySet())
-					this.attr.put(o.toString(), attr.getValue(o.toString()));
-			} else {
-				// resource-only plugin
-				className = null;
-				mainversion = null;
-				description = tr("unknown");
-				early = false;
-				stage = 50;
-				version = null;
-				author = null;
-			}
-			if (file != null)
-				libraries.add(0, fileToURL(file));
-
-			if (jar != null)
-				jar.close();
-		} catch (IOException e) {
-			throw new PluginException(null, name, e);
-		}
-	}
-
-	/**
-	 * Load and instantiate the plugin
-	 */
-	public PluginProxy load(Class<?> klass) {
-		try {
-			currentPluginInitialization = this;
-			return new PluginProxy(klass.newInstance(), this);
-		} catch (Exception e) {
-			throw new PluginException(null, name, e);
-		}
-	}
-
-	/**
-	 * Load the class of the plugin
-	 */
-	public Class<?> loadClass(ClassLoader classLoader) {
-		if (className == null)
-			return null;
-		try {
-			Class<?> realClass = Class.forName(className, true, classLoader);
-			return realClass;
-		} catch (Exception e) {
-			throw new PluginException(null, name, e);
-		}
-	}
-
-	public static URL fileToURL(File f) {
-		try {
-			return f.toURI().toURL();
-		} catch (MalformedURLException ex) {
-			return null;
-		}
-	}
-
-	/**
-	 * Try to find a plugin after some criterias. Extract the plugin-information
-	 * from the plugin and return it. The plugin is searched in the following way:
-	 * 
-	 *<li>first look after an MANIFEST.MF in the package org.openstreetmap.josm.plugins.<plugin name>
-	 *    (After removing all fancy characters from the plugin name).
-	 *    If found, the plugin is loaded using the bootstrap classloader.
-	 *<li>If not found, look for a jar file in the user specific plugin directory
-	 *    (~/.josm/plugins/<plugin name>.jar)
-	 *<li>If not found and the environment variable JOSM_RESSOURCES + "/plugins/" exist, look there.
-	 *<li>Try for the java property josm.ressources + "/plugins/" (set via java -Djosm.plugins.path=...)
-	 *<li>If the environment variable ALLUSERSPROFILE and APPDATA exist, look in 
-	 *    ALLUSERSPROFILE/<the last stuff from APPDATA>/JOSM/plugins. 
-	 *    (*sic* There is no easy way under Windows to get the All User's application 
-	 *    directory)
-	 *<li>Finally, look in some typical unix paths:<ul> 
-	 *    <li>/usr/local/share/josm/plugins/
-	 *    <li>/usr/local/lib/josm/plugins/
-	 *    <li>/usr/share/josm/plugins/
-	 *    <li>/usr/lib/josm/plugins/
-	 * 
-	 * If a plugin class or jar file is found earlier in the list but seem not to
-	 * be working, an PluginException is thrown rather than continuing the search.
-	 * This is so JOSM can detect broken user-provided plugins and do not go silently
-	 * ignore them. 
-	 * 
-	 * The plugin is not initialized. If the plugin is a .jar file, it is not loaded
-	 * (only the manifest is extracted). In the classloader-case, the class is 
-	 * bootstraped (e.g. static {} - declarations will run. However, nothing else is done.
-	 *
-	 * @param pluginName The name of the plugin (in all lowercase). E.g. "lang-de"
-	 * @return Information about the plugin or <code>null</code>, if the plugin
-	 * 	       was nowhere to be found.
-	 * @throws PluginException In case of broken plugins.
-	 */
-	public static PluginInformation findPlugin(String pluginName) throws PluginException {
-    	String name = pluginName;
-    	name = name.replaceAll("[-. ]", "");
-    	InputStream manifestStream = PluginInformation.class.getResourceAsStream("/org/openstreetmap/josm/plugins/"+name+"/MANIFEST.MF");
-    	if (manifestStream != null)
-	        return new PluginInformation(null, pluginName, manifestStream);
+
+    public final File file;
+    public final String name;
+    public final String mainversion;
+    public final String className;
+    public final String description;
+    public final boolean early;
+    public final String author;
+    public final int stage;
+    public final String version;
+    public final List<URL> libraries = new LinkedList<URL>();
+
+    public final Map<String, String> attr = new TreeMap<String, String>();
+
+    /**
+     * Used in the Plugin constructor to make the information of the plugin
+     * that is currently initializing available.
+     *
+     * If you think this is hacky, you are probably right. But it is
+     * convinient anyway ;-)
+     */
+    static PluginInformation currentPluginInitialization = null;
+
+    /**
+     * @param file the plugin jar file.
+     */
+    public PluginInformation(File file) {
+        this(file, file.getName().substring(0, file.getName().length()-4), null);
+    }
+
+    public PluginInformation(File file, String name, InputStream manifestStream) {
+        this.name = name;
+        this.file = file;
+        try {
+            Manifest manifest;
+            JarInputStream jar = null;
+            if (file != null) {
+                jar = new JarInputStream(new FileInputStream(file));
+                manifest = jar.getManifest();
+                if (manifest == null)
+                    throw new IOException(file+" contains no manifest.");
+            } else {
+                manifest = new Manifest();
+                manifest.read(manifestStream);
+            }
+            if (manifest != null) {
+                Attributes attr = manifest.getMainAttributes();
+                className = attr.getValue("Plugin-Class");
+                description = attr.getValue("Plugin-Description");
+                early = Boolean.parseBoolean(attr.getValue("Plugin-Early"));
+                String stageStr = attr.getValue("Plugin-Stage");
+                stage = stageStr == null ? 50 : Integer.parseInt(stageStr);
+                version = attr.getValue("Plugin-Version");
+                mainversion = attr.getValue("Plugin-Mainversion");
+                author = attr.getValue("Author");
+
+                String classPath = attr.getValue(Attributes.Name.CLASS_PATH);
+                if (classPath != null) {
+                    for (String entry : classPath.split(" ")) {
+                        File entryFile;
+                        if (new File(entry).isAbsolute()) {
+                            entryFile = new File(entry);
+                        } else {
+                            entryFile = new File(file.getParent(), entry);
+                        }
+
+                        libraries.add(fileToURL(entryFile));
+                    }
+                }
+                for (Object o : attr.keySet())
+                    this.attr.put(o.toString(), attr.getValue(o.toString()));
+            } else {
+                // resource-only plugin
+                className = null;
+                mainversion = null;
+                description = tr("unknown");
+                early = false;
+                stage = 50;
+                version = null;
+                author = null;
+            }
+            if (file != null)
+                libraries.add(0, fileToURL(file));
+
+            if (jar != null)
+                jar.close();
+        } catch (IOException e) {
+            throw new PluginException(null, name, e);
+        }
+    }
+
+    /**
+     * Load and instantiate the plugin
+     */
+    public PluginProxy load(Class<?> klass) {
+        try {
+            currentPluginInitialization = this;
+            return new PluginProxy(klass.newInstance(), this);
+        } catch (Exception e) {
+            throw new PluginException(null, name, e);
+        }
+    }
+
+    /**
+     * Load the class of the plugin
+     */
+    public Class<?> loadClass(ClassLoader classLoader) {
+        if (className == null)
+            return null;
+        try {
+            Class<?> realClass = Class.forName(className, true, classLoader);
+            return realClass;
+        } catch (Exception e) {
+            throw new PluginException(null, name, e);
+        }
+    }
+
+    public static URL fileToURL(File f) {
+        try {
+            return f.toURI().toURL();
+        } catch (MalformedURLException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Try to find a plugin after some criterias. Extract the plugin-information
+     * from the plugin and return it. The plugin is searched in the following way:
+     *
+     *<li>first look after an MANIFEST.MF in the package org.openstreetmap.josm.plugins.<plugin name>
+     *    (After removing all fancy characters from the plugin name).
+     *    If found, the plugin is loaded using the bootstrap classloader.
+     *<li>If not found, look for a jar file in the user specific plugin directory
+     *    (~/.josm/plugins/<plugin name>.jar)
+     *<li>If not found and the environment variable JOSM_RESSOURCES + "/plugins/" exist, look there.
+     *<li>Try for the java property josm.ressources + "/plugins/" (set via java -Djosm.plugins.path=...)
+     *<li>If the environment variable ALLUSERSPROFILE and APPDATA exist, look in
+     *    ALLUSERSPROFILE/<the last stuff from APPDATA>/JOSM/plugins.
+     *    (*sic* There is no easy way under Windows to get the All User's application
+     *    directory)
+     *<li>Finally, look in some typical unix paths:<ul>
+     *    <li>/usr/local/share/josm/plugins/
+     *    <li>/usr/local/lib/josm/plugins/
+     *    <li>/usr/share/josm/plugins/
+     *    <li>/usr/lib/josm/plugins/
+     *
+     * If a plugin class or jar file is found earlier in the list but seem not to
+     * be working, an PluginException is thrown rather than continuing the search.
+     * This is so JOSM can detect broken user-provided plugins and do not go silently
+     * ignore them.
+     *
+     * The plugin is not initialized. If the plugin is a .jar file, it is not loaded
+     * (only the manifest is extracted). In the classloader-case, the class is
+     * bootstraped (e.g. static {} - declarations will run. However, nothing else is done.
+     *
+     * @param pluginName The name of the plugin (in all lowercase). E.g. "lang-de"
+     * @return Information about the plugin or <code>null</code>, if the plugin
+     *         was nowhere to be found.
+     * @throws PluginException In case of broken plugins.
+     */
+    public static PluginInformation findPlugin(String pluginName) throws PluginException {
+        String name = pluginName;
+        name = name.replaceAll("[-. ]", "");
+        InputStream manifestStream = PluginInformation.class.getResourceAsStream("/org/openstreetmap/josm/plugins/"+name+"/MANIFEST.MF");
+        if (manifestStream != null)
+            return new PluginInformation(null, pluginName, manifestStream);
 
         Collection<String> locations = getPluginLocations();
 
-       	for (String s : locations) {
-       		File pluginFile = new File(s, pluginName + ".jar");
-       		if (pluginFile.exists()) {
-				PluginInformation info = new PluginInformation(pluginFile);
-				return info;
-       		}
-       	}
-       	return null;
-	}
-
-	public static Collection<String> getPluginLocations() {
-	    Collection<String> locations = Main.pref.getAllPossiblePreferenceDirs();
-	    Collection<String> all = new ArrayList<String>(locations.size());
-	    for (String s : locations)
-	    	all.add(s+"plugins");
-	    return all;
-    }
-	
-	
-	/**
-	 * Return information about a loaded plugin.
-	 * 
-	 * Note that if you call this in your plugins bootstrap, you may get <code>null</code> if
-	 * the plugin requested is not loaded yet.
-	 * 
-	 * @return The PluginInformation to a specific plugin, but only if the plugin is loaded.
-	 * If it is not loaded, <code>null</code> is returned.
-	 */
-	public static PluginInformation getLoaded(String pluginName) {
-		for (PluginProxy p : Main.plugins)
-			if (p.info.name.equals(pluginName))
-				return p.info;
-		return null;
-	}
+        for (String s : locations) {
+            File pluginFile = new File(s, pluginName + ".jar");
+            if (pluginFile.exists()) {
+                PluginInformation info = new PluginInformation(pluginFile);
+                return info;
+            }
+        }
+        return null;
+    }
+
+    public static Collection<String> getPluginLocations() {
+        Collection<String> locations = Main.pref.getAllPossiblePreferenceDirs();
+        Collection<String> all = new ArrayList<String>(locations.size());
+        for (String s : locations)
+            all.add(s+"plugins");
+        return all;
+    }
+
+
+    /**
+     * Return information about a loaded plugin.
+     *
+     * Note that if you call this in your plugins bootstrap, you may get <code>null</code> if
+     * the plugin requested is not loaded yet.
+     *
+     * @return The PluginInformation to a specific plugin, but only if the plugin is loaded.
+     * If it is not loaded, <code>null</code> is returned.
+     */
+    public static PluginInformation getLoaded(String pluginName) {
+        for (PluginProxy p : Main.plugins)
+            if (p.info.name.equals(pluginName))
+                return p.info;
+        return null;
+    }
 }
 
Index: trunk/src/org/openstreetmap/josm/plugins/PluginProxy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 1169)
@@ -18,39 +18,39 @@
 public class PluginProxy extends Plugin {
 
-	public final Object plugin;
-	public final PluginInformation info;
+    public final Object plugin;
+    public final PluginInformation info;
 
-	public PluginProxy(Object plugin, PluginInformation info) {
-		this.plugin = plugin;
-		this.info = info;
+    public PluginProxy(Object plugin, PluginInformation info) {
+        this.plugin = plugin;
+        this.info = info;
     }
 
-	@Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
-		try {
-	        plugin.getClass().getMethod("mapFrameInitialized", MapFrame.class, MapFrame.class).invoke(plugin, oldFrame, newFrame);
+    @Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+        try {
+            plugin.getClass().getMethod("mapFrameInitialized", MapFrame.class, MapFrame.class).invoke(plugin, oldFrame, newFrame);
         } catch (NoSuchMethodException e) {
         } catch (Exception e) {
-        	throw new PluginException(this, info.name, e);
+            throw new PluginException(this, info.name, e);
         }
     }
 
-	@Override public PreferenceSetting getPreferenceSetting() {
-		try {
-			return (PreferenceSetting)plugin.getClass().getMethod("getPreferenceSetting").invoke(plugin);
-		} catch (NoSuchMethodException e) {
-			return null;
-		} catch (Exception e) {
-			throw new PluginException(this, info.name, e);
-		}
+    @Override public PreferenceSetting getPreferenceSetting() {
+        try {
+            return (PreferenceSetting)plugin.getClass().getMethod("getPreferenceSetting").invoke(plugin);
+        } catch (NoSuchMethodException e) {
+            return null;
+        } catch (Exception e) {
+            throw new PluginException(this, info.name, e);
+        }
     }
-	
-	@Override public void addDownloadSelection(List<DownloadSelection> list) {
-		try {
-			plugin.getClass().getMethod("addDownloadSelection", List.class).invoke(plugin, list);
-		} catch (NoSuchMethodException e) {
-			// ignore
-		} catch (Exception e) {
-			throw new PluginException(this, info.name, e);
-		}
-	}
+
+    @Override public void addDownloadSelection(List<DownloadSelection> list) {
+        try {
+            plugin.getClass().getMethod("addDownloadSelection", List.class).invoke(plugin, list);
+        } catch (NoSuchMethodException e) {
+            // ignore
+        } catch (Exception e) {
+            throw new PluginException(this, info.name, e);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java	(revision 1169)
@@ -18,5 +18,5 @@
 /**
  * Creates and controls a separate audio player thread.
- * 
+ *
  * @author David Earl <david@frankieandshadow.com>
  *
@@ -24,8 +24,8 @@
 public class AudioPlayer extends Thread {
 
-	private static AudioPlayer audioPlayer = null;
-
-	private enum State { INITIALIZING, NOTPLAYING, PLAYING, PAUSED, INTERRUPTED } 
-	private State state;
+    private static AudioPlayer audioPlayer = null;
+
+    private enum State { INITIALIZING, NOTPLAYING, PLAYING, PAUSED, INTERRUPTED }
+    private State state;
     private enum Command { PLAY, PAUSE }
     private enum Result { WAITING, OK, FAILED }
@@ -33,307 +33,307 @@
     private double leadIn; // seconds
     private double calibration; // ratio of purported duration of samples to true duration
-	private double position; // seconds
-	private double bytesPerSecond; 
-	private static long chunk = 4000; /* bytes */
-	private double speed = 1.0;
-
-	/**
-	 * Passes information from the control thread to the playing thread 
-	 */
-	private class Execute {
-		private Command command;
-		private Result result;
-		private Exception exception;
-		private URL url;
-		private double offset; // seconds
-		private double speed; // ratio
-		
-		/*
-		 * Called to execute the commands in the other thread 
-		 */
-		protected void play(URL url, double offset, double speed) throws Exception {
-			this.url = url;
-			this.offset = offset;
-			this.speed = speed; 
-			command = Command.PLAY;
-			result = Result.WAITING;
-			send();
-		}
-		protected void pause() throws Exception {
-			command = Command.PAUSE;
-			send();
-		}
-		private void send() throws Exception {
-			result = Result.WAITING;
-			interrupt();
-			while (result == Result.WAITING) { sleep(10); /* yield(); */ }
-			if (result == Result.FAILED) { throw exception; }
-		}
-		private void possiblyInterrupt() throws InterruptedException {
-			if (interrupted() || result == Result.WAITING)
-				throw new InterruptedException();
-		}
-		protected void failed (Exception e) {
-			exception = e;
-			result = Result.FAILED;
-			state = State.NOTPLAYING;
-		}
-		protected void ok (State newState) {
-			result = Result.OK;
-			state = newState;
-		}
-		protected double offset() {
-			return offset;
-		}
-		protected double speed() {
-			return speed;
-		}
-		protected URL url() {
-			return url;
-		}
-		protected Command command() {
-			return command;
-		}
-	}
-	
-	private Execute command;
-
-	/**
-	 * Plays a WAV audio file from the beginning. See also the variant which doesn't 
-	 * start at the beginning of the stream
-	 * @param url The resource to play, which must be a WAV file or stream
-	 * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
-	 */
-	public static void play(URL url) throws Exception {
-		AudioPlayer.get().command.play(url, 0.0, 1.0);
-	}
-	
-	/**
-	 * Plays a WAV audio file from a specified position.
-	 * @param url The resource to play, which must be a WAV file or stream
-	 * @param seconds The number of seconds into the audio to start playing
-	 * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
-	 */
-	public static void play(URL url, double seconds) throws Exception {
-		AudioPlayer.get().command.play(url, seconds, 1.0);
-	}
-	
-	/**
-	 * Plays a WAV audio file from a specified position at variable speed.
-	 * @param url The resource to play, which must be a WAV file or stream
-	 * @param seconds The number of seconds into the audio to start playing
-	 * @param speed Rate at which audio playes (1.0 = real time, > 1 is faster)
-	 * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
-	 */
-	public static void play(URL url, double seconds, double speed) throws Exception {
-		AudioPlayer.get().command.play(url, seconds, speed);
-	}
-	
-	/**
-	 * Pauses the currently playing audio stream. Does nothing if nothing playing.
-	 * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
-	 */
-	public static void pause() throws Exception {
-		AudioPlayer.get().command.pause();
-	}
-	
-	/**
-	 * To get the Url of the playing or recently played audio.
-	 * @return url - could be null
-	 */
-	public static URL url() {
-		return AudioPlayer.get().playingUrl;
-	}
-	
-	/**
-	 * Whether or not we are paused.
-	 * @return boolean whether or not paused
-	 */
-	public static boolean paused() {
-		return AudioPlayer.get().state == State.PAUSED;
-	}
-
-	/**
-	 * Whether or not we are playing.
-	 * @return boolean whether or not playing
-	 */
-	public static boolean playing() {
-		return AudioPlayer.get().state == State.PLAYING;
-	}
-
-	/**
-	 * How far we are through playing, in seconds.
-	 * @return double seconds
-	 */
-	public static double position() {
-		return AudioPlayer.get().position;
-	}
-	
-	/**
-	 * Speed at which we will play.
-	 * @return double, speed multiplier
-	 */
-	public static double speed() {
-		return AudioPlayer.get().speed;
-	}
-
-	/**
-	 *  gets the singleton object, and if this is the first time, creates it along with 
-	 *  the thread to support audio
-	 */
-	private static AudioPlayer get() {
-		if (audioPlayer != null)
-			return audioPlayer;
-		try {
-			audioPlayer = new AudioPlayer();
-			return audioPlayer;
-		} catch (Exception ex) {
-			return null;
-		}
-	}
-
-	private AudioPlayer() {
-		state = State.INITIALIZING;
-		command = new Execute();
-		playingUrl = null;
-		try {
-			leadIn = Double.parseDouble(Main.pref.get("audio.leadin", "1.0" /* default, seconds */));
-		} catch (NumberFormatException e) {
-			leadIn = 1.0; // failed to parse
-		}
-		try {
-			calibration = Double.parseDouble(Main.pref.get("audio.calibration", "1.0" /* default, ratio */));
-		} catch (NumberFormatException e) {
-			calibration = 1.0; // failed to parse
-		}
-		start();
-		while (state == State.INITIALIZING) { yield(); }
-	}
-
-	/**
-	 * Starts the thread to actually play the audio, per Thread interface
-	 * Not to be used as public, though Thread interface doesn't allow it to be made private
-	 */
-	@Override public void run() {
-		/* code running in separate thread */
-
-		playingUrl = null;
-		AudioInputStream audioInputStream = null;
-		SourceDataLine audioOutputLine = null;
-		AudioFormat	audioFormat = null;
-		byte[] abData = new byte[(int)chunk];
-		
-		for (;;) {
-			try {
-				switch (state) {
-				case INITIALIZING:
-					// we're ready to take interrupts
-					state = State.NOTPLAYING;
-					break;
-				case NOTPLAYING:
-				case PAUSED:
-					sleep(200);
-					break;
-				case PLAYING:
-					command.possiblyInterrupt();
-					for(;;) {
-						int nBytesRead = 0;
-						nBytesRead = audioInputStream.read(abData, 0, abData.length);
-						position += nBytesRead / bytesPerSecond;
-						command.possiblyInterrupt();
-						if (nBytesRead < 0) { break; }
-						audioOutputLine.write(abData, 0, nBytesRead); // => int nBytesWritten
-						command.possiblyInterrupt();
-					}
-					// end of audio, clean up
-					audioOutputLine.drain();
-					audioOutputLine.close();
-					audioOutputLine = null;
-					audioInputStream.close();
-					audioInputStream = null;
-					playingUrl = null;
-					state = State.NOTPLAYING;
-					command.possiblyInterrupt();
-					break;
-				}
-			} catch (InterruptedException e) {
-				interrupted(); // just in case we get an interrupt
-				State stateChange = state;
-				state = State.INTERRUPTED;
-				try {
-					switch (command.command()) {
-					case PLAY:	
-						double offset = command.offset();
-						speed = command.speed();
-						if (playingUrl != command.url() || 
-							stateChange != State.PAUSED || 
-							offset != 0.0) 
-						{
-							if (audioInputStream != null) {
-								audioInputStream.close();
-								audioInputStream = null;
-							}
-							playingUrl = command.url();
-							audioInputStream = AudioSystem.getAudioInputStream(playingUrl);
-							audioFormat = audioInputStream.getFormat();
-							long nBytesRead = 0;
-							position = 0.0;
-							offset -= leadIn;
-							double calibratedOffset = offset * calibration;
-							bytesPerSecond = audioFormat.getFrameRate() /* frames per second */
-								* audioFormat.getFrameSize() /* bytes per frame */;
-							if (speed * bytesPerSecond > 256000.0)
-								speed = 256000 / bytesPerSecond;
-							if (calibratedOffset > 0.0) {
-								long bytesToSkip = (long)(
-										calibratedOffset /* seconds (double) */ * bytesPerSecond);
-								/* skip doesn't seem to want to skip big chunks, so 
-								 * reduce it to smaller ones 
-								 */
-								// audioInputStream.skip(bytesToSkip);
-								while (bytesToSkip > chunk) {
-									nBytesRead = audioInputStream.skip(chunk);
-									if (nBytesRead <= 0)
-										throw new IOException(tr("This is after the end of the recording"));
-									bytesToSkip -= nBytesRead;
-								}
-								if (bytesToSkip > 0)
-									audioInputStream.skip(bytesToSkip);
-								position = offset;
-							}
-							if (audioOutputLine != null)
-								audioOutputLine.close();
-							audioFormat = new AudioFormat(audioFormat.getEncoding(), 
-										audioFormat.getSampleRate() * (float) (speed * calibration), 
-										audioFormat.getSampleSizeInBits(), 
-										audioFormat.getChannels(), 
-										audioFormat.getFrameSize(), 
-										audioFormat.getFrameRate() * (float) (speed * calibration), 
-										audioFormat.isBigEndian());
-							DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
-							audioOutputLine = (SourceDataLine) AudioSystem.getLine(info);
-							audioOutputLine.open(audioFormat);
-							audioOutputLine.start();
-						}
-						stateChange = State.PLAYING;
-						break;
-					case PAUSE:
-						stateChange = State.PAUSED;
-						break;
-					}
-					command.ok(stateChange);
-				} catch (Exception startPlayingException) {
-					command.failed(startPlayingException); // sets state
-				}
-			} catch (Exception e) {
-				state = State.NOTPLAYING;
-			}
-		}
-	}
-
-	public static void audioMalfunction(Exception ex) {
-		JOptionPane.showMessageDialog(Main.parent, 
-				"<html><p>" + tr(ex.getMessage()) + "</p></html>",
-				tr("Error playing sound"), JOptionPane.ERROR_MESSAGE);
-	}
+    private double position; // seconds
+    private double bytesPerSecond;
+    private static long chunk = 4000; /* bytes */
+    private double speed = 1.0;
+
+    /**
+     * Passes information from the control thread to the playing thread
+     */
+    private class Execute {
+        private Command command;
+        private Result result;
+        private Exception exception;
+        private URL url;
+        private double offset; // seconds
+        private double speed; // ratio
+
+        /*
+         * Called to execute the commands in the other thread
+         */
+        protected void play(URL url, double offset, double speed) throws Exception {
+            this.url = url;
+            this.offset = offset;
+            this.speed = speed;
+            command = Command.PLAY;
+            result = Result.WAITING;
+            send();
+        }
+        protected void pause() throws Exception {
+            command = Command.PAUSE;
+            send();
+        }
+        private void send() throws Exception {
+            result = Result.WAITING;
+            interrupt();
+            while (result == Result.WAITING) { sleep(10); /* yield(); */ }
+            if (result == Result.FAILED) { throw exception; }
+        }
+        private void possiblyInterrupt() throws InterruptedException {
+            if (interrupted() || result == Result.WAITING)
+                throw new InterruptedException();
+        }
+        protected void failed (Exception e) {
+            exception = e;
+            result = Result.FAILED;
+            state = State.NOTPLAYING;
+        }
+        protected void ok (State newState) {
+            result = Result.OK;
+            state = newState;
+        }
+        protected double offset() {
+            return offset;
+        }
+        protected double speed() {
+            return speed;
+        }
+        protected URL url() {
+            return url;
+        }
+        protected Command command() {
+            return command;
+        }
+    }
+
+    private Execute command;
+
+    /**
+     * Plays a WAV audio file from the beginning. See also the variant which doesn't
+     * start at the beginning of the stream
+     * @param url The resource to play, which must be a WAV file or stream
+     * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
+     */
+    public static void play(URL url) throws Exception {
+        AudioPlayer.get().command.play(url, 0.0, 1.0);
+    }
+
+    /**
+     * Plays a WAV audio file from a specified position.
+     * @param url The resource to play, which must be a WAV file or stream
+     * @param seconds The number of seconds into the audio to start playing
+     * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
+     */
+    public static void play(URL url, double seconds) throws Exception {
+        AudioPlayer.get().command.play(url, seconds, 1.0);
+    }
+
+    /**
+     * Plays a WAV audio file from a specified position at variable speed.
+     * @param url The resource to play, which must be a WAV file or stream
+     * @param seconds The number of seconds into the audio to start playing
+     * @param speed Rate at which audio playes (1.0 = real time, > 1 is faster)
+     * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
+     */
+    public static void play(URL url, double seconds, double speed) throws Exception {
+        AudioPlayer.get().command.play(url, seconds, speed);
+    }
+
+    /**
+     * Pauses the currently playing audio stream. Does nothing if nothing playing.
+     * @throws audio fault exception, e.g. can't open stream,  unhandleable audio format
+     */
+    public static void pause() throws Exception {
+        AudioPlayer.get().command.pause();
+    }
+
+    /**
+     * To get the Url of the playing or recently played audio.
+     * @return url - could be null
+     */
+    public static URL url() {
+        return AudioPlayer.get().playingUrl;
+    }
+
+    /**
+     * Whether or not we are paused.
+     * @return boolean whether or not paused
+     */
+    public static boolean paused() {
+        return AudioPlayer.get().state == State.PAUSED;
+    }
+
+    /**
+     * Whether or not we are playing.
+     * @return boolean whether or not playing
+     */
+    public static boolean playing() {
+        return AudioPlayer.get().state == State.PLAYING;
+    }
+
+    /**
+     * How far we are through playing, in seconds.
+     * @return double seconds
+     */
+    public static double position() {
+        return AudioPlayer.get().position;
+    }
+
+    /**
+     * Speed at which we will play.
+     * @return double, speed multiplier
+     */
+    public static double speed() {
+        return AudioPlayer.get().speed;
+    }
+
+    /**
+     *  gets the singleton object, and if this is the first time, creates it along with
+     *  the thread to support audio
+     */
+    private static AudioPlayer get() {
+        if (audioPlayer != null)
+            return audioPlayer;
+        try {
+            audioPlayer = new AudioPlayer();
+            return audioPlayer;
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    private AudioPlayer() {
+        state = State.INITIALIZING;
+        command = new Execute();
+        playingUrl = null;
+        try {
+            leadIn = Double.parseDouble(Main.pref.get("audio.leadin", "1.0" /* default, seconds */));
+        } catch (NumberFormatException e) {
+            leadIn = 1.0; // failed to parse
+        }
+        try {
+            calibration = Double.parseDouble(Main.pref.get("audio.calibration", "1.0" /* default, ratio */));
+        } catch (NumberFormatException e) {
+            calibration = 1.0; // failed to parse
+        }
+        start();
+        while (state == State.INITIALIZING) { yield(); }
+    }
+
+    /**
+     * Starts the thread to actually play the audio, per Thread interface
+     * Not to be used as public, though Thread interface doesn't allow it to be made private
+     */
+    @Override public void run() {
+        /* code running in separate thread */
+
+        playingUrl = null;
+        AudioInputStream audioInputStream = null;
+        SourceDataLine audioOutputLine = null;
+        AudioFormat audioFormat = null;
+        byte[] abData = new byte[(int)chunk];
+
+        for (;;) {
+            try {
+                switch (state) {
+                case INITIALIZING:
+                    // we're ready to take interrupts
+                    state = State.NOTPLAYING;
+                    break;
+                case NOTPLAYING:
+                case PAUSED:
+                    sleep(200);
+                    break;
+                case PLAYING:
+                    command.possiblyInterrupt();
+                    for(;;) {
+                        int nBytesRead = 0;
+                        nBytesRead = audioInputStream.read(abData, 0, abData.length);
+                        position += nBytesRead / bytesPerSecond;
+                        command.possiblyInterrupt();
+                        if (nBytesRead < 0) { break; }
+                        audioOutputLine.write(abData, 0, nBytesRead); // => int nBytesWritten
+                        command.possiblyInterrupt();
+                    }
+                    // end of audio, clean up
+                    audioOutputLine.drain();
+                    audioOutputLine.close();
+                    audioOutputLine = null;
+                    audioInputStream.close();
+                    audioInputStream = null;
+                    playingUrl = null;
+                    state = State.NOTPLAYING;
+                    command.possiblyInterrupt();
+                    break;
+                }
+            } catch (InterruptedException e) {
+                interrupted(); // just in case we get an interrupt
+                State stateChange = state;
+                state = State.INTERRUPTED;
+                try {
+                    switch (command.command()) {
+                    case PLAY:
+                        double offset = command.offset();
+                        speed = command.speed();
+                        if (playingUrl != command.url() ||
+                            stateChange != State.PAUSED ||
+                            offset != 0.0)
+                        {
+                            if (audioInputStream != null) {
+                                audioInputStream.close();
+                                audioInputStream = null;
+                            }
+                            playingUrl = command.url();
+                            audioInputStream = AudioSystem.getAudioInputStream(playingUrl);
+                            audioFormat = audioInputStream.getFormat();
+                            long nBytesRead = 0;
+                            position = 0.0;
+                            offset -= leadIn;
+                            double calibratedOffset = offset * calibration;
+                            bytesPerSecond = audioFormat.getFrameRate() /* frames per second */
+                                * audioFormat.getFrameSize() /* bytes per frame */;
+                            if (speed * bytesPerSecond > 256000.0)
+                                speed = 256000 / bytesPerSecond;
+                            if (calibratedOffset > 0.0) {
+                                long bytesToSkip = (long)(
+                                        calibratedOffset /* seconds (double) */ * bytesPerSecond);
+                                /* skip doesn't seem to want to skip big chunks, so
+                                 * reduce it to smaller ones
+                                 */
+                                // audioInputStream.skip(bytesToSkip);
+                                while (bytesToSkip > chunk) {
+                                    nBytesRead = audioInputStream.skip(chunk);
+                                    if (nBytesRead <= 0)
+                                        throw new IOException(tr("This is after the end of the recording"));
+                                    bytesToSkip -= nBytesRead;
+                                }
+                                if (bytesToSkip > 0)
+                                    audioInputStream.skip(bytesToSkip);
+                                position = offset;
+                            }
+                            if (audioOutputLine != null)
+                                audioOutputLine.close();
+                            audioFormat = new AudioFormat(audioFormat.getEncoding(),
+                                        audioFormat.getSampleRate() * (float) (speed * calibration),
+                                        audioFormat.getSampleSizeInBits(),
+                                        audioFormat.getChannels(),
+                                        audioFormat.getFrameSize(),
+                                        audioFormat.getFrameRate() * (float) (speed * calibration),
+                                        audioFormat.isBigEndian());
+                            DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
+                            audioOutputLine = (SourceDataLine) AudioSystem.getLine(info);
+                            audioOutputLine.open(audioFormat);
+                            audioOutputLine.start();
+                        }
+                        stateChange = State.PLAYING;
+                        break;
+                    case PAUSE:
+                        stateChange = State.PAUSED;
+                        break;
+                    }
+                    command.ok(stateChange);
+                } catch (Exception startPlayingException) {
+                    command.failed(startPlayingException); // sets state
+                }
+            } catch (Exception e) {
+                state = State.NOTPLAYING;
+            }
+        }
+    }
+
+    public static void audioMalfunction(Exception ex) {
+        JOptionPane.showMessageDialog(Main.parent,
+                "<html><p>" + tr(ex.getMessage()) + "</p></html>",
+                tr("Error playing sound"), JOptionPane.ERROR_MESSAGE);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/AutoCompleteComboBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/AutoCompleteComboBox.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/AutoCompleteComboBox.java	(revision 1169)
@@ -17,89 +17,89 @@
 public class AutoCompleteComboBox extends JComboBox {
 
-	/**
-	 * Auto-complete a JComboBox.
-	 *
-	 * Inspired by http://www.orbital-computer.de/JComboBox/
-	 */
-	private class AutoCompleteComboBoxDocument extends PlainDocument {
-		private JComboBox comboBox;
-		private boolean selecting = false;
+    /**
+     * Auto-complete a JComboBox.
+     *
+     * Inspired by http://www.orbital-computer.de/JComboBox/
+     */
+    private class AutoCompleteComboBoxDocument extends PlainDocument {
+        private JComboBox comboBox;
+        private boolean selecting = false;
 
-		public AutoCompleteComboBoxDocument(final JComboBox comboBox) {
-			this.comboBox = comboBox;
-		}
+        public AutoCompleteComboBoxDocument(final JComboBox comboBox) {
+            this.comboBox = comboBox;
+        }
 
-		@Override public void remove(int offs, int len) throws BadLocationException {
-			if (selecting)
-				return;
-			super.remove(offs, len);
-		}
+        @Override public void remove(int offs, int len) throws BadLocationException {
+            if (selecting)
+                return;
+            super.remove(offs, len);
+        }
 
-		@Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
-			if(selecting || (offs == 0 && str.equals(getText(0, getLength()))))
-				return;
-			boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
-			super.insertString(offs, str, a);
+        @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+            if(selecting || (offs == 0 && str.equals(getText(0, getLength()))))
+                return;
+            boolean initial = (offs == 0 && getLength() == 0 && str.length() > 1);
+            super.insertString(offs, str, a);
 
-			// return immediately when selecting an item
-			// Note: this is done after calling super method because we need
-			// ActionListener informed
-			if (selecting)
-				return;
+            // return immediately when selecting an item
+            // Note: this is done after calling super method because we need
+            // ActionListener informed
+            if (selecting)
+                return;
 
-			int size = getLength();
-			int start = offs+str.length();
-			int end = start;
-			String curText = getText(0, size);
-			// lookup and select a matching item
-			Object item = lookupItem(curText);
-			setSelectedItem(item);
-			if(initial)
-				start = 0;
-			if (item != null) {
-				String newText = item.toString();
-				if(!newText.equals(curText))
-				{
-					selecting = true;
-					super.remove(0, size);
-					super.insertString(0, newText, a);
-					selecting = false;
-					start = size;
-					end = getLength();
-				}
-			}
-			JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent();
-			editor.setSelectionStart(start);
-			editor.setSelectionEnd(end);
-		}
+            int size = getLength();
+            int start = offs+str.length();
+            int end = start;
+            String curText = getText(0, size);
+            // lookup and select a matching item
+            Object item = lookupItem(curText);
+            setSelectedItem(item);
+            if(initial)
+                start = 0;
+            if (item != null) {
+                String newText = item.toString();
+                if(!newText.equals(curText))
+                {
+                    selecting = true;
+                    super.remove(0, size);
+                    super.insertString(0, newText, a);
+                    selecting = false;
+                    start = size;
+                    end = getLength();
+                }
+            }
+            JTextComponent editor = (JTextComponent)comboBox.getEditor().getEditorComponent();
+            editor.setSelectionStart(start);
+            editor.setSelectionEnd(end);
+        }
 
-		private void setSelectedItem(Object item) {
-			selecting = true;
-			comboBox.setSelectedItem(item);
-			selecting = false;
-		}
+        private void setSelectedItem(Object item) {
+            selecting = true;
+            comboBox.setSelectedItem(item);
+            selecting = false;
+        }
 
-		private Object lookupItem(String pattern) {
-			ComboBoxModel model = comboBox.getModel();
-			for (int i = 0, n = model.getSize(); i < n; i++) {
-				Object currentItem = model.getElementAt(i);
-				if (currentItem.toString().startsWith(pattern))
-					return currentItem;
-			}
-			return null;
-		}
-	}
+        private Object lookupItem(String pattern) {
+            ComboBoxModel model = comboBox.getModel();
+            for (int i = 0, n = model.getSize(); i < n; i++) {
+                Object currentItem = model.getElementAt(i);
+                if (currentItem.toString().startsWith(pattern))
+                    return currentItem;
+            }
+            return null;
+        }
+    }
 
-	public AutoCompleteComboBox() {
-		JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
-		editor.setDocument(new AutoCompleteComboBoxDocument(this));
-	}
+    public AutoCompleteComboBox() {
+        JTextComponent editor = (JTextComponent) this.getEditor().getEditorComponent();
+        editor.setDocument(new AutoCompleteComboBoxDocument(this));
+    }
 
-	public void setPossibleItems(Collection<String> elems) {
-		DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
-		Object oldValue = this.getEditor().getItem();
-		model.removeAllElements();
-		for (String elem : elems) model.addElement(elem);
-		this.getEditor().setItem(oldValue);
-	}
+    public void setPossibleItems(Collection<String> elems) {
+        DefaultComboBoxModel model = (DefaultComboBoxModel)this.getModel();
+        Object oldValue = this.getEditor().getItem();
+        model.removeAllElements();
+        for (String elem : elems) model.addElement(elem);
+        this.getEditor().setItem(oldValue);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java	(revision 1169)
@@ -39,158 +39,158 @@
 public final class BugReportExceptionHandler implements Thread.UncaughtExceptionHandler {
 
-	public void uncaughtException(Thread t, Throwable e) {
-		e.printStackTrace();
-		if (Main.parent != null) {
-			if (e instanceof OutOfMemoryError) {
-				// do not translate the string, as translation may raise an exception
-				JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
-						"Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
-						"where ### is the the number of MB assigned to JOSM (e.g. 256).\n" +
-						"Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.");
-				return;
-			}
+    public void uncaughtException(Thread t, Throwable e) {
+        e.printStackTrace();
+        if (Main.parent != null) {
+            if (e instanceof OutOfMemoryError) {
+                // do not translate the string, as translation may raise an exception
+                JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
+                        "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
+                        "where ### is the the number of MB assigned to JOSM (e.g. 256).\n" +
+                        "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.");
+                return;
+            }
 
-			PluginProxy plugin = null;
+            PluginProxy plugin = null;
 
-			// Check for an explicit problem when calling a plugin function
-			if (e instanceof PluginException)
-				plugin = ((PluginException)e).plugin;
+            // Check for an explicit problem when calling a plugin function
+            if (e instanceof PluginException)
+                plugin = ((PluginException)e).plugin;
 
-			if (plugin == null)
-				plugin = guessPlugin(e);
+            if (plugin == null)
+                plugin = guessPlugin(e);
 
-			if (plugin != null) {
-				int answer = JOptionPane.showConfirmDialog(
-						Main.parent, tr("An unexpected exception occurred that may have come from the ''{0}'' plugin.",
-						plugin.info.name) + "\n"+ (plugin.info.author != null ?
-						tr("According to the information within the plugin, the author is {0}.",
-						plugin.info.author) : "") + "\n" +
-						tr("Try updating to the newest version of this plugin before reporting a bug.") + "\n" +
-						tr("Should the plugin be disabled?"),
-						tr("Disable plugin"),
-						JOptionPane.YES_NO_OPTION);
-				if (answer == JOptionPane.OK_OPTION) {
-					LinkedList<String> plugins = new LinkedList<String>(Arrays.asList(Main.pref.get("plugins").split(",")));
-					if (plugins.contains(plugin.info.name)) {
-						while (plugins.remove(plugin.info.name)) {}
-						String p = "";
-						for (String s : plugins)
-							p += ","+s;
-						if (p.length() > 0)
-							p = p.substring(1);
-						Main.pref.put("plugins", p);
-						JOptionPane.showMessageDialog(Main.parent,
-						tr("The plugin has been removed from the configuration. Please restart JOSM to unload the plugin."));
-					} else {
-						JOptionPane.showMessageDialog(Main.parent,
-						tr("The plugin could not be removed. Please tell the people you got JOSM from about the problem."));
-					}
-					return;
-				}
-			}
+            if (plugin != null) {
+                int answer = JOptionPane.showConfirmDialog(
+                        Main.parent, tr("An unexpected exception occurred that may have come from the ''{0}'' plugin.",
+                        plugin.info.name) + "\n"+ (plugin.info.author != null ?
+                        tr("According to the information within the plugin, the author is {0}.",
+                        plugin.info.author) : "") + "\n" +
+                        tr("Try updating to the newest version of this plugin before reporting a bug.") + "\n" +
+                        tr("Should the plugin be disabled?"),
+                        tr("Disable plugin"),
+                        JOptionPane.YES_NO_OPTION);
+                if (answer == JOptionPane.OK_OPTION) {
+                    LinkedList<String> plugins = new LinkedList<String>(Arrays.asList(Main.pref.get("plugins").split(",")));
+                    if (plugins.contains(plugin.info.name)) {
+                        while (plugins.remove(plugin.info.name)) {}
+                        String p = "";
+                        for (String s : plugins)
+                            p += ","+s;
+                        if (p.length() > 0)
+                            p = p.substring(1);
+                        Main.pref.put("plugins", p);
+                        JOptionPane.showMessageDialog(Main.parent,
+                        tr("The plugin has been removed from the configuration. Please restart JOSM to unload the plugin."));
+                    } else {
+                        JOptionPane.showMessageDialog(Main.parent,
+                        tr("The plugin could not be removed. Please tell the people you got JOSM from about the problem."));
+                    }
+                    return;
+                }
+            }
 
-			Object[] options = new String[]{tr("Do nothing"), tr("Report Bug")};
-			int answer = JOptionPane.showOptionDialog(Main.parent, tr("An unexpected exception occurred.\n\n" +
-			"This is always a coding error. If you are running the latest\n" +
-			"version of JOSM, please consider being kind and file a bug report."),
-			tr("Unexpected Exception"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
-			null, options, options[0]);
-			if (answer == 1) {
-				try {
-					StringWriter stack = new StringWriter();
-					e.printStackTrace(new PrintWriter(stack));
+            Object[] options = new String[]{tr("Do nothing"), tr("Report Bug")};
+            int answer = JOptionPane.showOptionDialog(Main.parent, tr("An unexpected exception occurred.\n\n" +
+            "This is always a coding error. If you are running the latest\n" +
+            "version of JOSM, please consider being kind and file a bug report."),
+            tr("Unexpected Exception"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
+            null, options, options[0]);
+            if (answer == 1) {
+                try {
+                    StringWriter stack = new StringWriter();
+                    e.printStackTrace(new PrintWriter(stack));
 
-					URL revUrl = Main.class.getResource("/REVISION");
-					StringBuilder sb = new StringBuilder();
-					if (revUrl == null) {
-						sb.append(tr("Development version. Unknown revision."));
-						File f = new File("org/openstreetmap/josm/Main.class");
-						if (!f.exists())
-							f = new File("bin/org/openstreetmap/josm/Main.class");
-						if (!f.exists())
-							f = new File("build/org/openstreetmap/josm/Main.class");
-						if (f.exists()) {
-							DateFormat sdf = SimpleDateFormat.getDateTimeInstance();
-							sb.append("\nMain.class build on "+sdf.format(new Date(f.lastModified())));
-							sb.append("\n");
-						}
-					} else {
-						BufferedReader in = new BufferedReader(new InputStreamReader(revUrl.openStream()));
-						for (String line = in.readLine(); line != null; line = in.readLine()) {
-							sb.append(line);
-							sb.append('\n');
-						}
-					}
-					sb.append("\n"+stack.getBuffer().toString());
+                    URL revUrl = Main.class.getResource("/REVISION");
+                    StringBuilder sb = new StringBuilder();
+                    if (revUrl == null) {
+                        sb.append(tr("Development version. Unknown revision."));
+                        File f = new File("org/openstreetmap/josm/Main.class");
+                        if (!f.exists())
+                            f = new File("bin/org/openstreetmap/josm/Main.class");
+                        if (!f.exists())
+                            f = new File("build/org/openstreetmap/josm/Main.class");
+                        if (f.exists()) {
+                            DateFormat sdf = SimpleDateFormat.getDateTimeInstance();
+                            sb.append("\nMain.class build on "+sdf.format(new Date(f.lastModified())));
+                            sb.append("\n");
+                        }
+                    } else {
+                        BufferedReader in = new BufferedReader(new InputStreamReader(revUrl.openStream()));
+                        for (String line = in.readLine(); line != null; line = in.readLine()) {
+                            sb.append(line);
+                            sb.append('\n');
+                        }
+                    }
+                    sb.append("\n"+stack.getBuffer().toString());
 
-					JPanel p = new JPanel(new GridBagLayout());
-					p.add(new JLabel(tr("<html>Please report a ticket at {0}<br>" +
-					"Include your steps to get to the error (as detailed as possible)!<br>" +
-					"Be sure to include the following information:</html>", "http://josm.openstreetmap.de/newticket")), GBC.eol());
-					try {
-						Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(sb.toString()), new ClipboardOwner(){
-							public void lostOwnership(Clipboard clipboard, Transferable contents) {}
-						});
-						p.add(new JLabel(tr("(The text has already been copied to your clipboard.)")), GBC.eop());
-					}
-					catch (RuntimeException x) {}
+                    JPanel p = new JPanel(new GridBagLayout());
+                    p.add(new JLabel(tr("<html>Please report a ticket at {0}<br>" +
+                    "Include your steps to get to the error (as detailed as possible)!<br>" +
+                    "Be sure to include the following information:</html>", "http://josm.openstreetmap.de/newticket")), GBC.eol());
+                    try {
+                        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(sb.toString()), new ClipboardOwner(){
+                            public void lostOwnership(Clipboard clipboard, Transferable contents) {}
+                        });
+                        p.add(new JLabel(tr("(The text has already been copied to your clipboard.)")), GBC.eop());
+                    }
+                    catch (RuntimeException x) {}
 
-					JTextArea info = new JTextArea(sb.toString(), 20, 60);
-					info.setCaretPosition(0);
-					info.setEditable(false);
-					p.add(new JScrollPane(info), GBC.eop());
+                    JTextArea info = new JTextArea(sb.toString(), 20, 60);
+                    info.setCaretPosition(0);
+                    info.setEditable(false);
+                    p.add(new JScrollPane(info), GBC.eop());
 
-					JOptionPane.showMessageDialog(Main.parent, p);
-				} catch (Exception e1) {
-					e1.printStackTrace();
-				}
-			}
-		}
-	}
+                    JOptionPane.showMessageDialog(Main.parent, p);
+                } catch (Exception e1) {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
 
-	private PluginProxy guessPlugin(Throwable e) {
-		String name = guessPluginName(e);
-		for (PluginProxy p : Main.plugins)
-			if (p.info.name.equals(name))
-				return p;
-		return null;
-	}
+    private PluginProxy guessPlugin(Throwable e) {
+        String name = guessPluginName(e);
+        for (PluginProxy p : Main.plugins)
+            if (p.info.name.equals(name))
+                return p;
+        return null;
+    }
 
-	/**
-	 * Analyze the stack of the argument and return a name of a plugin, if
-	 * some known problem pattern has been found or <code>null</code>, if
-	 * the stack does not contain plugin-code.
-	 *
-	 * Note: This heuristic is not meant as discrimination against specific
-	 * plugins, but only to stop the flood of similar bug reports about plugins.
-	 * Of course, plugin writers are free to install their own version of
-	 * an exception handler with their email address listed to receive
-	 * bug reports ;-).
-	 */
-	private String guessPluginName(Throwable e) {
-		for (StackTraceElement element : e.getStackTrace()) {
-			String c = element.getClassName();
+    /**
+     * Analyze the stack of the argument and return a name of a plugin, if
+     * some known problem pattern has been found or <code>null</code>, if
+     * the stack does not contain plugin-code.
+     *
+     * Note: This heuristic is not meant as discrimination against specific
+     * plugins, but only to stop the flood of similar bug reports about plugins.
+     * Of course, plugin writers are free to install their own version of
+     * an exception handler with their email address listed to receive
+     * bug reports ;-).
+     */
+    private String guessPluginName(Throwable e) {
+        for (StackTraceElement element : e.getStackTrace()) {
+            String c = element.getClassName();
 
-			if (c.contains("wmsplugin.") || c.contains(".WMSLayer"))
-				return "wmsplugin";
-			if (c.contains("landsat.") || c.contains(".LandsatLayer"))
-				return "landsat";
-			if (c.contains("livegps."))
-				return "livegps";
-			if (c.contains("mappaint."))
-				return "mappaint";
-			if (c.contains("annotationtester."))
-				return "annotation-tester";
-			if (c.startsWith("UtilsPlugin."))
-				return "UtilsPlugin";
+            if (c.contains("wmsplugin.") || c.contains(".WMSLayer"))
+                return "wmsplugin";
+            if (c.contains("landsat.") || c.contains(".LandsatLayer"))
+                return "landsat";
+            if (c.contains("livegps."))
+                return "livegps";
+            if (c.contains("mappaint."))
+                return "mappaint";
+            if (c.contains("annotationtester."))
+                return "annotation-tester";
+            if (c.startsWith("UtilsPlugin."))
+                return "UtilsPlugin";
 
-			if (c.startsWith("org.openstreetmap.josm.plugins.")) {
-				String p = c.substring("org.openstreetmap.josm.plugins.".length());
-				if (p.indexOf('.') != -1 && p.matches("[a-z].*")) {
-					return p.substring(0,p.indexOf('.'));
-				}
-			}
-		}
-		return null;
-	}
+            if (c.startsWith("org.openstreetmap.josm.plugins.")) {
+                String p = c.substring("org.openstreetmap.josm.plugins.".length());
+                if (p.indexOf('.') != -1 && p.matches("[a-z].*")) {
+                    return p.substring(0,p.indexOf('.'));
+                }
+            }
+        }
+        return null;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/ColorHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ColorHelper.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/ColorHelper.java	(revision 1169)
@@ -8,28 +8,28 @@
  */
 public class ColorHelper {
-	
-	public static Color html2color(String html) {
-		if (html.length() > 0 && html.charAt(0) == '#')
-			html = html.substring(1);
-		else if (html.length() != 6 && html.length() != 8)
-			return null;
-		try {
-			return new Color(
-					Integer.parseInt(html.substring(0,2),16),
-					Integer.parseInt(html.substring(2,4),16),
-					Integer.parseInt(html.substring(4,6),16),
-					(html.length() == 8 ? Integer.parseInt(html.substring(6,8),16) : 255));
-		} catch (NumberFormatException e) {
-			return null;
-		}		
-	}
 
-	private static String int2hex(int i) {
-		String s = Integer.toHexString(i / 16) + Integer.toHexString(i % 16);
-		return s.toUpperCase();
-	}
-	
-	public static String color2html(Color col) {
-		return "#"+int2hex(col.getRed())+int2hex(col.getGreen())+int2hex(col.getBlue());
-	}
+    public static Color html2color(String html) {
+        if (html.length() > 0 && html.charAt(0) == '#')
+            html = html.substring(1);
+        else if (html.length() != 6 && html.length() != 8)
+            return null;
+        try {
+            return new Color(
+                    Integer.parseInt(html.substring(0,2),16),
+                    Integer.parseInt(html.substring(2,4),16),
+                    Integer.parseInt(html.substring(4,6),16),
+                    (html.length() == 8 ? Integer.parseInt(html.substring(6,8),16) : 255));
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    private static String int2hex(int i) {
+        String s = Integer.toHexString(i / 16) + Integer.toHexString(i % 16);
+        return s.toUpperCase();
+    }
+
+    public static String color2html(Color col) {
+        return "#"+int2hex(col.getRed())+int2hex(col.getGreen())+int2hex(col.getBlue());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/DateParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/DateParser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/DateParser.java	(revision 1169)
@@ -8,10 +8,10 @@
 /**
  * Tries to parse a date as good as it can.
- * 
+ *
  * @author Immanuel.Scholz
  */
 public class DateParser {
-	public static Date parse(String d) throws ParseException {
-		return new PrimaryDateParser().parse(d);
-	}
+    public static Date parse(String d) throws ParseException {
+        return new PrimaryDateParser().parse(d);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/Destroyable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Destroyable.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/Destroyable.java	(revision 1169)
@@ -6,12 +6,12 @@
  * been removed) have an definite set of actions to execute. This is the "destructor" interface called
  * on those objects.
- * 
+ *
  * @author immanuel.scholz
  */
 public interface Destroyable {
 
-	/**
-	 * Called when the object has been destroyed.
-	 */
-	public void destroy();
+    /**
+     * Called when the object has been destroyed.
+     */
+    public void destroy();
 }
Index: trunk/src/org/openstreetmap/josm/tools/DontShowAgainInfo.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/DontShowAgainInfo.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/DontShowAgainInfo.java	(revision 1169)
@@ -16,29 +16,29 @@
 public class DontShowAgainInfo {
 
-	public static boolean show(String prefKey, String msg) {
-		return show(prefKey, new JLabel(msg), true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
-	}
+    public static boolean show(String prefKey, String msg) {
+        return show(prefKey, new JLabel(msg), true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
+    }
 
-	public static boolean show(String prefKey, String msg, Boolean state) {
-		return show(prefKey, new JLabel(msg), state, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
-	}
+    public static boolean show(String prefKey, String msg, Boolean state) {
+        return show(prefKey, new JLabel(msg), state, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
+    }
 
-	public static boolean show(String prefKey, Container msg) {
-		return show(prefKey, msg, true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
-	}
+    public static boolean show(String prefKey, Container msg) {
+        return show(prefKey, msg, true, JOptionPane.OK_CANCEL_OPTION, JOptionPane.OK_OPTION);
+    }
 
-	public static boolean show(String prefKey, Container msg, Boolean state, int options, int true_option) {
-		if (!Main.pref.getBoolean("message."+prefKey)) {
-			JCheckBox dontshowagain = new JCheckBox(tr("Do not show again"));
-			dontshowagain.setSelected(Main.pref.getBoolean("message."+prefKey, state));
-			JPanel all = new JPanel(new GridBagLayout());
-			all.add(msg, GBC.eop());
-			all.add(dontshowagain, GBC.eol());
-			int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Information"), options);
-			if (answer != true_option)
-				return false;
-			Main.pref.put("message."+prefKey, dontshowagain.isSelected());
-		}
-		return true;
-	}
+    public static boolean show(String prefKey, Container msg, Boolean state, int options, int true_option) {
+        if (!Main.pref.getBoolean("message."+prefKey)) {
+            JCheckBox dontshowagain = new JCheckBox(tr("Do not show again"));
+            dontshowagain.setSelected(Main.pref.getBoolean("message."+prefKey, state));
+            JPanel all = new JPanel(new GridBagLayout());
+            all.add(msg, GBC.eop());
+            all.add(dontshowagain, GBC.eol());
+            int answer = JOptionPane.showConfirmDialog(Main.parent, all, tr("Information"), options);
+            if (answer != true_option)
+                return false;
+            Main.pref.put("message."+prefKey, dontshowagain.isSelected());
+        }
+        return true;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/ExifReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 1169)
@@ -18,23 +18,23 @@
 public class ExifReader {
 
-	@SuppressWarnings("unchecked") public static Date readTime(File filename) throws ParseException {
-		Date date = null;
-		try {
-	        Metadata metadata = JpegMetadataReader.readMetadata(filename);
-	        for (Iterator<Directory> dirIt = metadata.getDirectoryIterator(); dirIt.hasNext();) {
-	            for (Iterator<Tag> tagIt = dirIt.next().getTagIterator(); tagIt.hasNext();) {
-	                Tag tag = tagIt.next();
-	                if (tag.getTagType() == 0x9003)
-	                	return DateParser.parse(tag.getDescription());
-	                if (tag.getTagType() == 0x132 || tag.getTagType() == 0x9004)
-	                	date = DateParser.parse(tag.getDescription());
-	            }
-	        }
-		} catch (ParseException e) {
-			throw e;
+    @SuppressWarnings("unchecked") public static Date readTime(File filename) throws ParseException {
+        Date date = null;
+        try {
+            Metadata metadata = JpegMetadataReader.readMetadata(filename);
+            for (Iterator<Directory> dirIt = metadata.getDirectoryIterator(); dirIt.hasNext();) {
+                for (Iterator<Tag> tagIt = dirIt.next().getTagIterator(); tagIt.hasNext();) {
+                    Tag tag = tagIt.next();
+                    if (tag.getTagType() == 0x9003)
+                        return DateParser.parse(tag.getDescription());
+                    if (tag.getTagType() == 0x132 || tag.getTagType() == 0x9004)
+                        date = DateParser.parse(tag.getDescription());
+                }
+            }
+        } catch (ParseException e) {
+            throw e;
         } catch (Exception e) {
-	        e.printStackTrace();
+            e.printStackTrace();
         }
-		return date;
-	}
+        return date;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/FallbackDateParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/FallbackDateParser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/FallbackDateParser.java	(revision 1169)
@@ -13,99 +13,99 @@
  * based on similar code in JOSM. This class is not threadsafe, a separate
  * instance must be created per thread.
- * 
+ *
  * @author Brett Henderson
  */
 public class FallbackDateParser {
-	
-	private static final String[] formats = {
-	    "yyyy-MM-dd'T'HH:mm:ss'Z'",
-		"yyyy-MM-dd'T'HH:mm:ssZ",
-		"yyyy-MM-dd'T'HH:mm:ss",
-		"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
-		"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
-		"yyyy-MM-dd HH:mm:ss",
-		"MM/dd/yyyy HH:mm:ss",
-		"MM/dd/yyyy'T'HH:mm:ss.SSS'Z'",
-		"MM/dd/yyyy'T'HH:mm:ss.SSSZ",
-		"MM/dd/yyyy'T'HH:mm:ss.SSS",
-		"MM/dd/yyyy'T'HH:mm:ssZ",
-		"MM/dd/yyyy'T'HH:mm:ss",
-		"yyyy:MM:dd HH:mm:ss"
-	};
-	
-	
-	private List<DateFormat> dateParsers;
-	private int activeDateParser;
-	
-	
-	/**
-	 * Creates a new instance.
-	 */
-	public FallbackDateParser() {
-		// Build a list of candidate date parsers.
-		dateParsers = new ArrayList<DateFormat>(formats.length);
-		for (int i = 0; i < formats.length; i++) {
-			dateParsers.add(new SimpleDateFormat(formats[i]));
-		}
-		
-		// We haven't selected a date parser yet.
-		activeDateParser = -1;
-	}
-	
-	
-	/**
-	 * Attempts to parse the specified date.
-	 * 
-	 * @param date
-	 *            The date to parse.
-	 * @return The date.
-	 * @throws ParseException
-	 *             Occurs if the date does not match any of the supported date
-	 *             formats.
-	 */
-	public Date parse(String date) throws ParseException {
-		String correctedDate;
-		
-		// Try to fix ruby's broken xmlschema - format
-		// Replace this:
-		// 2007-02-12T18:43:01+00:00
-		// With this:
-		// 2007-02-12T18:43:01+0000
-		if (date.length() == 25 && date.charAt(22) == ':') {
-			correctedDate = date.substring(0, 22) + date.substring(23, 25);
-		} else {
-			correctedDate = date;
-		}
-		
-		// If we have previously successfully used a date parser, we'll try it
-		// first.
-		if (activeDateParser >= 0) {
-			try {
-				return dateParsers.get(activeDateParser).parse(correctedDate);
-			} catch (ParseException e) {
-				// The currently active parser didn't work, so we must clear it
-				// and find a new appropriate parser.
-				activeDateParser = -1;
-			}
-		}
-		
-		// Try the date parsers one by one until a suitable format is found.
-		for (int i = 0; i < dateParsers.size(); i++) {
-			try {
-				Date result;
-				
-				// Attempt to parse with the current parser, if successful we
-				// store its index for next time.
-				result = dateParsers.get(i).parse(correctedDate);
-				activeDateParser = i;
-				
-				return result;
-				
-			} catch (ParseException pe) {
-				// Ignore parsing errors and try the next pattern.
-			}
-		}
-		
-		throw new ParseException("The date string (" + date + ") could not be parsed.", 0);
-	}
+
+    private static final String[] formats = {
+        "yyyy-MM-dd'T'HH:mm:ss'Z'",
+        "yyyy-MM-dd'T'HH:mm:ssZ",
+        "yyyy-MM-dd'T'HH:mm:ss",
+        "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
+        "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
+        "yyyy-MM-dd HH:mm:ss",
+        "MM/dd/yyyy HH:mm:ss",
+        "MM/dd/yyyy'T'HH:mm:ss.SSS'Z'",
+        "MM/dd/yyyy'T'HH:mm:ss.SSSZ",
+        "MM/dd/yyyy'T'HH:mm:ss.SSS",
+        "MM/dd/yyyy'T'HH:mm:ssZ",
+        "MM/dd/yyyy'T'HH:mm:ss",
+        "yyyy:MM:dd HH:mm:ss"
+    };
+
+
+    private List<DateFormat> dateParsers;
+    private int activeDateParser;
+
+
+    /**
+     * Creates a new instance.
+     */
+    public FallbackDateParser() {
+        // Build a list of candidate date parsers.
+        dateParsers = new ArrayList<DateFormat>(formats.length);
+        for (int i = 0; i < formats.length; i++) {
+            dateParsers.add(new SimpleDateFormat(formats[i]));
+        }
+
+        // We haven't selected a date parser yet.
+        activeDateParser = -1;
+    }
+
+
+    /**
+     * Attempts to parse the specified date.
+     *
+     * @param date
+     *            The date to parse.
+     * @return The date.
+     * @throws ParseException
+     *             Occurs if the date does not match any of the supported date
+     *             formats.
+     */
+    public Date parse(String date) throws ParseException {
+        String correctedDate;
+
+        // Try to fix ruby's broken xmlschema - format
+        // Replace this:
+        // 2007-02-12T18:43:01+00:00
+        // With this:
+        // 2007-02-12T18:43:01+0000
+        if (date.length() == 25 && date.charAt(22) == ':') {
+            correctedDate = date.substring(0, 22) + date.substring(23, 25);
+        } else {
+            correctedDate = date;
+        }
+
+        // If we have previously successfully used a date parser, we'll try it
+        // first.
+        if (activeDateParser >= 0) {
+            try {
+                return dateParsers.get(activeDateParser).parse(correctedDate);
+            } catch (ParseException e) {
+                // The currently active parser didn't work, so we must clear it
+                // and find a new appropriate parser.
+                activeDateParser = -1;
+            }
+        }
+
+        // Try the date parsers one by one until a suitable format is found.
+        for (int i = 0; i < dateParsers.size(); i++) {
+            try {
+                Date result;
+
+                // Attempt to parse with the current parser, if successful we
+                // store its index for next time.
+                result = dateParsers.get(i).parse(correctedDate);
+                activeDateParser = i;
+
+                return result;
+
+            } catch (ParseException pe) {
+                // Ignore parsing errors and try the next pattern.
+            }
+        }
+
+        throw new ParseException("The date string (" + date + ") could not be parsed.", 0);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/GBC.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/GBC.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/GBC.java	(revision 1169)
@@ -12,99 +12,99 @@
  * A wrapper for GridBagConstraints which has sane default static creators and
  * member functions to chain calling.
- * 
+ *
  * @author imi
  */
 public class GBC extends GridBagConstraints {
 
-	/**
-	 * Use public static creator functions to create an GBC.
-	 */
-	private GBC() {}
+    /**
+     * Use public static creator functions to create an GBC.
+     */
+    private GBC() {}
 
-	/**
-	 * Create a standard constraint (which is not the last).
-	 * @return A standard constraint with no filling.
-	 */
-	public static GBC std() {
-		GBC c = new GBC();
-		c.anchor = WEST;
-		return c;
-	}
+    /**
+     * Create a standard constraint (which is not the last).
+     * @return A standard constraint with no filling.
+     */
+    public static GBC std() {
+        GBC c = new GBC();
+        c.anchor = WEST;
+        return c;
+    }
 
-	/**
-	 * Create the constraint for the last elements on a line.
-	 * @return A constraint which indicates the last item on a line.
-	 */
-	public static GBC eol() {
-		GBC c = std();
-		c.gridwidth = REMAINDER;
-		return c;
-	}
+    /**
+     * Create the constraint for the last elements on a line.
+     * @return A constraint which indicates the last item on a line.
+     */
+    public static GBC eol() {
+        GBC c = std();
+        c.gridwidth = REMAINDER;
+        return c;
+    }
 
-	/**
-	 * Create the constraint for the last elements on a line and on a paragraph.
-	 * This is merely a shortcut for eol().insets(0,0,0,10)
-	 * @return A constraint which indicates the last item on a line.
-	 */
-	public static GBC eop() {
-		return eol().insets(0,0,0,10);
-	}
+    /**
+     * Create the constraint for the last elements on a line and on a paragraph.
+     * This is merely a shortcut for eol().insets(0,0,0,10)
+     * @return A constraint which indicates the last item on a line.
+     */
+    public static GBC eop() {
+        return eol().insets(0,0,0,10);
+    }
 
-	/**
-	 * Try to fill both, horizontal and vertical
-	 * @return This constraint for chaining.
-	 */
-	public GBC fill() {
-		return fill(BOTH);
-	}
+    /**
+     * Try to fill both, horizontal and vertical
+     * @return This constraint for chaining.
+     */
+    public GBC fill() {
+        return fill(BOTH);
+    }
 
-	/**
-	 * Set fill to the given value
-	 * @param value The filling value, either NONE, HORIZONTAL, VERTICAL or BOTH
-	 * @return This constraint for chaining.
-	 */
-	public GBC fill(int value) {
-		fill = value;
-		if (value == HORIZONTAL || value == BOTH)
-			weightx = 1.0;
-		if (value == VERTICAL || value == BOTH)
-			weighty = 1.0;
-		return this;
-	}
+    /**
+     * Set fill to the given value
+     * @param value The filling value, either NONE, HORIZONTAL, VERTICAL or BOTH
+     * @return This constraint for chaining.
+     */
+    public GBC fill(int value) {
+        fill = value;
+        if (value == HORIZONTAL || value == BOTH)
+            weightx = 1.0;
+        if (value == VERTICAL || value == BOTH)
+            weighty = 1.0;
+        return this;
+    }
 
-	/**
-	 * Set the anchor of this GBC to a.
-	 * @param a The new anchor, e.g. GBC.CENTER or GBC.EAST.
-	 * @return This constraint for chaining.
-	 */
-	public GBC anchor(int a) {
-		anchor = a;
-		return this;
-	}
+    /**
+     * Set the anchor of this GBC to a.
+     * @param a The new anchor, e.g. GBC.CENTER or GBC.EAST.
+     * @return This constraint for chaining.
+     */
+    public GBC anchor(int a) {
+        anchor = a;
+        return this;
+    }
 
-	/**
-	 * Adds insets to this GBC.
-	 * @param left		The left space of the insets
-	 * @param top		The top space of the insets
-	 * @param right		The right space of the insets
-	 * @param bottom	The bottom space of the insets
-	 * @return This constraint for chaining.
-	 */
-	public GBC insets(int left, int top, int right, int bottom) {
-		insets = new Insets(top, left, bottom, right);
-		return this;
-	}
+    /**
+     * Adds insets to this GBC.
+     * @param left      The left space of the insets
+     * @param top       The top space of the insets
+     * @param right     The right space of the insets
+     * @param bottom    The bottom space of the insets
+     * @return This constraint for chaining.
+     */
+    public GBC insets(int left, int top, int right, int bottom) {
+        insets = new Insets(top, left, bottom, right);
+        return this;
+    }
 
-	/**
-	 * This is a helper to easily create a glue with a minimum default value.
-	 * @param x If higher than 0, this will be a horizontal glue with x as minimum
-	 * 		horizontal strut.
-	 * @param y If higher than 0, this will be a vertical glue with y as minimum
-	 * 		vertical strut.
-	 */
-	public static Component glue(int x, int y) {
-		short maxx = x > 0 ? Short.MAX_VALUE : 0;
-		short maxy = y > 0 ? Short.MAX_VALUE : 0;
-		return new Box.Filler(new Dimension(x,y), new Dimension(x,y), new Dimension(maxx,maxy));
-	}
+    /**
+     * This is a helper to easily create a glue with a minimum default value.
+     * @param x If higher than 0, this will be a horizontal glue with x as minimum
+     *      horizontal strut.
+     * @param y If higher than 0, this will be a vertical glue with y as minimum
+     *      vertical strut.
+     */
+    public static Component glue(int x, int y) {
+        short maxx = x > 0 ? Short.MAX_VALUE : 0;
+        short maxy = y > 0 ? Short.MAX_VALUE : 0;
+        return new Box.Filler(new Dimension(x,y), new Dimension(x,y), new Dimension(maxx,maxy));
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/I18n.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 1169)
@@ -10,69 +10,69 @@
 /**
  * Internationalisation support.
- * 
+ *
  * @author Immanuel.Scholz
  */
 public class I18n {
 
-	/* Base name for translation data. Used for detecting available translations */
-	private static final String TR_BASE = "org.openstreetmap.josm.i18n.Translation_";
+    /* Base name for translation data. Used for detecting available translations */
+    private static final String TR_BASE = "org.openstreetmap.josm.i18n.Translation_";
 
-	/**
-	 * Set by MainApplication. Changes here later will probably mess up everything, because
-	 * many strings are already loaded.
-	 */
-	public static org.xnap.commons.i18n.I18n i18n;
+    /**
+     * Set by MainApplication. Changes here later will probably mess up everything, because
+     * many strings are already loaded.
+     */
+    public static org.xnap.commons.i18n.I18n i18n;
 
-	public static final String tr(String text, Object... objects) {
-		if (i18n == null)
-			return MessageFormat.format(text, objects);
-		return i18n.tr(text, objects);
-	}
+    public static final String tr(String text, Object... objects) {
+        if (i18n == null)
+            return MessageFormat.format(text, objects);
+        return i18n.tr(text, objects);
+    }
 
-	public static final String tr(String text) {
-		if (i18n == null)
-			return text;
-		return i18n.tr(text);
-	}
+    public static final String tr(String text) {
+        if (i18n == null)
+            return text;
+        return i18n.tr(text);
+    }
 
-	public static final String marktr(String text) {
-		return text;
-	}
+    public static final String marktr(String text) {
+        return text;
+    }
 
-	public static final String trn(String text, String pluralText, long n, Object... objects) {
-		if (i18n == null)
-			return n == 1 ? tr(text, objects) : tr(pluralText, objects);
-		return i18n.trn(text, pluralText, n, objects);
-	}
+    public static final String trn(String text, String pluralText, long n, Object... objects) {
+        if (i18n == null)
+            return n == 1 ? tr(text, objects) : tr(pluralText, objects);
+        return i18n.trn(text, pluralText, n, objects);
+    }
 
-	public static final String trn(String text, String pluralText, long n) {
-		if (i18n == null)
-			return n == 1 ? tr(text) : tr(pluralText);
-		return i18n.trn(text, pluralText, n);
-	}
+    public static final String trn(String text, String pluralText, long n) {
+        if (i18n == null)
+            return n == 1 ? tr(text) : tr(pluralText);
+        return i18n.trn(text, pluralText, n);
+    }
 
-	/**
-	 * Get a list of all available JOSM Translations.
-	 * @return an array of locale objects.
-	 */
-	public static final Locale[] getAvailableTranslations() {
-		Vector<Locale> v = new Vector<Locale>();
-		Locale[] l = Locale.getAvailableLocales();
-		for (int i = 0; i < l.length; i++) {
-			String cn = TR_BASE + l[i];
-			try {
-				Class.forName(cn);
-				v.add(l[i]);
-			} catch (ClassNotFoundException e) {
-			}
-		}
-		l = new Locale[v.size()];
-		l = v.toArray(l);
-		Arrays.sort(l, new Comparator<Locale>() {
-			public int compare(Locale o1, Locale o2) {
-				return o1.toString().compareTo(o2.toString());
-			}
-		});
-		return l;
-	}
+    /**
+     * Get a list of all available JOSM Translations.
+     * @return an array of locale objects.
+     */
+    public static final Locale[] getAvailableTranslations() {
+        Vector<Locale> v = new Vector<Locale>();
+        Locale[] l = Locale.getAvailableLocales();
+        for (int i = 0; i < l.length; i++) {
+            String cn = TR_BASE + l[i];
+            try {
+                Class.forName(cn);
+                v.add(l[i]);
+            } catch (ClassNotFoundException e) {
+            }
+        }
+        l = new Locale[v.size()];
+        l = v.toArray(l);
+        Arrays.sort(l, new Comparator<Locale>() {
+            public int compare(Locale o1, Locale o2) {
+                return o1.toString().compareTo(o2.toString());
+            }
+        });
+        return l;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 1169)
@@ -32,195 +32,195 @@
 public class ImageProvider {
 
-	/**
-	 * Position of an overlay icon
-	 * @author imi
-	 */
-	public static enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
-
-	/**
-	 * The icon cache
-	 */
-	private static Map<String, Image> cache = new HashMap<String, Image>();
-
-	/**
-	 * Add here all ClassLoader whose ressource should be searched.
-	 * Plugin's class loaders are added by main.
-	 */
-	public static final List<ClassLoader> sources = new LinkedList<ClassLoader>();
-
-	/**
-	 * Return an image from the specified location.
-	 *
-	 * @param subdir	The position of the directory, e.g. "layer"
-	 * @param name		The icons name (without the ending of ".png")
-	 * @return The requested Image.
-	 */
-	public static ImageIcon get(String subdir, String name) {
-		ImageIcon icon = getIfAvailable(subdir, name);
-		if (icon == null) {
-			String ext = name.indexOf('.') != -1 ? "" : ".png";
-			throw new NullPointerException("/images/"+subdir+name+ext+" not found");
-		}
-		return icon;
-	}
-
-	public static ImageIcon getIfAvailable(String subdir, String name)
-	{
-		return getIfAvailable((Collection<String>)null, null, subdir, name);
-	}
-	public static final ImageIcon getIfAvailable(String[] dirs, String id, String subdir, String name)
-	{
-		return getIfAvailable(Arrays.asList(dirs), id, subdir, name);
-	}
-
-	/**
-	 * Like {@link #get(String)}, but does not throw and return <code>null</code>
-	 * in case of nothing is found. Use this, if the image to retrieve is optional.
-	 */
-	public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name)
-	{
-		if (name == null)
-			return null;
-		if (subdir == null)
-			subdir = "";
-		else if (!subdir.equals(""))
-			subdir += "/";
-		String ext = name.indexOf('.') != -1 ? "" : ".png";
-		String full_name = subdir+name+ext;
-		String cache_name = full_name;
-		/* cache separately */
-		if(dirs != null && dirs.size() > 0)
-			cache_name = "id:"+id+":"+full_name;
-
-		Image img = cache.get(cache_name);
-		if (img == null) {
-			// getImageUrl() does a ton of "stat()" calls and gets expensive
-			// and redundant when you have a whole ton of objects.  So,
-			// index the cache by the name of the icon we're looking for
-			// and don't bother to create a URL unless we're actually
-			// creating the image.
-			URL path = getImageUrl(full_name, dirs);
-			if (path == null)
-				return null;
-			img = Toolkit.getDefaultToolkit().createImage(path);
-			cache.put(cache_name, img);
-		}
-	
-		return new ImageIcon(img);
-	}
-
-	private static URL getImageUrl(String path, String name)
-	{
-		if(path.startsWith("resource://"))
-		{
-			String p = path.substring("resource://".length());
-			for (ClassLoader source : sources)
-			{
-				URL res;
-				if ((res = source.getResource(p+name)) != null)
-					return res;
-			}
-		}
-		else
-		{
-			try {
-				File f = new File(path, name);
-				if(f.exists())
-					return f.toURI().toURL();
-			} catch (MalformedURLException e) {}
-		}
-		return null;
-	}
-
-	private static URL getImageUrl(String imageName, Collection<String> dirs)
-	{
-		URL u;
-		// Try passed directories first
-		if(dirs != null)
-		{
-			for (String name : dirs)
-			{
-				u = getImageUrl(name, imageName);
-				if(u != null) return u;
-			}
-		}
-		// Try user-preference directory
-		u = getImageUrl(Main.pref.getPreferencesDir()+"images", imageName);
-		if(u != null) return u;
-
-		// Try plugins and josm classloader
-		u = getImageUrl("resource://images/", imageName);
-		if(u != null) return u;
-
-		// Try all other ressource directories
-		for (String location : Main.pref.getAllPossiblePreferenceDirs())
-		{
-			u = getImageUrl(location+"images", imageName);
-			if(u != null) return u;
-			u = getImageUrl(location, imageName);
-			if(u != null) return u;
-		}
-		return null;
-	}
-
-	/**
-	 * Shortcut for get("", name);
-	 */
-	public static ImageIcon get(String name) {
-		return get("", name);
-	}
-
-	public static Cursor getCursor(String name, String overlay) {
-		ImageIcon img = get("cursor",name);
-		if (overlay != null)
-			img = overlay(img, "cursor/modifier/"+overlay, OverlayPosition.SOUTHEAST);
-		Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(img.getImage(),
-				name.equals("crosshair") ? new Point(10,10) : new Point(3,2), "Cursor");
-		return c;
-	}
-
-	/**
-	 * @return an icon that represent the overlay of the two given icons. The
-	 * second icon is layed on the first relative to the given position.
-	 */
-	public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) {
-		GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
-		int w = ground.getIconWidth();
-		int h = ground.getIconHeight();
-		ImageIcon overlay = ImageProvider.get(overlayImage);
-		int wo = overlay.getIconWidth();
-		int ho = overlay.getIconHeight();
-		BufferedImage img = conf.createCompatibleImage(w,h, Transparency.TRANSLUCENT);
-		Graphics g = img.createGraphics();
-		ground.paintIcon(null, g, 0, 0);
-		int x = 0, y = 0;
-		switch (pos) {
-		case NORTHWEST:
-			x = 0;
-			y = 0;
-			break;
-		case NORTHEAST:
-			x = w-wo;
-			y = 0;
-			break;
-		case SOUTHWEST:
-			x = 0;
-			y = h-ho;
-			break;
-		case SOUTHEAST:
-			x = w-wo;
-			y = h-ho;
-			break;
-		}
-		overlay.paintIcon(null, g, x, y);
-		return new ImageIcon(img);
-	}
-
-	static {
-		try {
-			sources.add(ClassLoader.getSystemClassLoader());
-		} catch (SecurityException ex) {
-			sources.add(ImageProvider.class.getClassLoader());
-		}
-	}
+    /**
+     * Position of an overlay icon
+     * @author imi
+     */
+    public static enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
+
+    /**
+     * The icon cache
+     */
+    private static Map<String, Image> cache = new HashMap<String, Image>();
+
+    /**
+     * Add here all ClassLoader whose ressource should be searched.
+     * Plugin's class loaders are added by main.
+     */
+    public static final List<ClassLoader> sources = new LinkedList<ClassLoader>();
+
+    /**
+     * Return an image from the specified location.
+     *
+     * @param subdir    The position of the directory, e.g. "layer"
+     * @param name      The icons name (without the ending of ".png")
+     * @return The requested Image.
+     */
+    public static ImageIcon get(String subdir, String name) {
+        ImageIcon icon = getIfAvailable(subdir, name);
+        if (icon == null) {
+            String ext = name.indexOf('.') != -1 ? "" : ".png";
+            throw new NullPointerException("/images/"+subdir+name+ext+" not found");
+        }
+        return icon;
+    }
+
+    public static ImageIcon getIfAvailable(String subdir, String name)
+    {
+        return getIfAvailable((Collection<String>)null, null, subdir, name);
+    }
+    public static final ImageIcon getIfAvailable(String[] dirs, String id, String subdir, String name)
+    {
+        return getIfAvailable(Arrays.asList(dirs), id, subdir, name);
+    }
+
+    /**
+     * Like {@link #get(String)}, but does not throw and return <code>null</code>
+     * in case of nothing is found. Use this, if the image to retrieve is optional.
+     */
+    public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name)
+    {
+        if (name == null)
+            return null;
+        if (subdir == null)
+            subdir = "";
+        else if (!subdir.equals(""))
+            subdir += "/";
+        String ext = name.indexOf('.') != -1 ? "" : ".png";
+        String full_name = subdir+name+ext;
+        String cache_name = full_name;
+        /* cache separately */
+        if(dirs != null && dirs.size() > 0)
+            cache_name = "id:"+id+":"+full_name;
+
+        Image img = cache.get(cache_name);
+        if (img == null) {
+            // getImageUrl() does a ton of "stat()" calls and gets expensive
+            // and redundant when you have a whole ton of objects.  So,
+            // index the cache by the name of the icon we're looking for
+            // and don't bother to create a URL unless we're actually
+            // creating the image.
+            URL path = getImageUrl(full_name, dirs);
+            if (path == null)
+                return null;
+            img = Toolkit.getDefaultToolkit().createImage(path);
+            cache.put(cache_name, img);
+        }
+
+        return new ImageIcon(img);
+    }
+
+    private static URL getImageUrl(String path, String name)
+    {
+        if(path.startsWith("resource://"))
+        {
+            String p = path.substring("resource://".length());
+            for (ClassLoader source : sources)
+            {
+                URL res;
+                if ((res = source.getResource(p+name)) != null)
+                    return res;
+            }
+        }
+        else
+        {
+            try {
+                File f = new File(path, name);
+                if(f.exists())
+                    return f.toURI().toURL();
+            } catch (MalformedURLException e) {}
+        }
+        return null;
+    }
+
+    private static URL getImageUrl(String imageName, Collection<String> dirs)
+    {
+        URL u;
+        // Try passed directories first
+        if(dirs != null)
+        {
+            for (String name : dirs)
+            {
+                u = getImageUrl(name, imageName);
+                if(u != null) return u;
+            }
+        }
+        // Try user-preference directory
+        u = getImageUrl(Main.pref.getPreferencesDir()+"images", imageName);
+        if(u != null) return u;
+
+        // Try plugins and josm classloader
+        u = getImageUrl("resource://images/", imageName);
+        if(u != null) return u;
+
+        // Try all other ressource directories
+        for (String location : Main.pref.getAllPossiblePreferenceDirs())
+        {
+            u = getImageUrl(location+"images", imageName);
+            if(u != null) return u;
+            u = getImageUrl(location, imageName);
+            if(u != null) return u;
+        }
+        return null;
+    }
+
+    /**
+     * Shortcut for get("", name);
+     */
+    public static ImageIcon get(String name) {
+        return get("", name);
+    }
+
+    public static Cursor getCursor(String name, String overlay) {
+        ImageIcon img = get("cursor",name);
+        if (overlay != null)
+            img = overlay(img, "cursor/modifier/"+overlay, OverlayPosition.SOUTHEAST);
+        Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(img.getImage(),
+                name.equals("crosshair") ? new Point(10,10) : new Point(3,2), "Cursor");
+        return c;
+    }
+
+    /**
+     * @return an icon that represent the overlay of the two given icons. The
+     * second icon is layed on the first relative to the given position.
+     */
+    public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) {
+        GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+        int w = ground.getIconWidth();
+        int h = ground.getIconHeight();
+        ImageIcon overlay = ImageProvider.get(overlayImage);
+        int wo = overlay.getIconWidth();
+        int ho = overlay.getIconHeight();
+        BufferedImage img = conf.createCompatibleImage(w,h, Transparency.TRANSLUCENT);
+        Graphics g = img.createGraphics();
+        ground.paintIcon(null, g, 0, 0);
+        int x = 0, y = 0;
+        switch (pos) {
+        case NORTHWEST:
+            x = 0;
+            y = 0;
+            break;
+        case NORTHEAST:
+            x = w-wo;
+            y = 0;
+            break;
+        case SOUTHWEST:
+            x = 0;
+            y = h-ho;
+            break;
+        case SOUTHEAST:
+            x = w-wo;
+            y = h-ho;
+            break;
+        }
+        overlay.paintIcon(null, g, x, y);
+        return new ImageIcon(img);
+    }
+
+    static {
+        try {
+            sources.add(ClassLoader.getSystemClassLoader());
+        } catch (SecurityException ex) {
+            sources.add(ImageProvider.class.getClassLoader());
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/OpenBrowser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 1169)
@@ -19,25 +19,25 @@
 public class OpenBrowser {
 
-	/**
-	 * @return <code>null</code> for success or a string in case of an error.
-	 */
-	public static String displayUrl(String url) {
-		if (Main.applet) {
-			try {
-				JApplet applet = (JApplet) Main.parent;
-				applet.getAppletContext().showDocument(new URL(url));
-				return null;
-			} catch (MalformedURLException mue) {
-				return mue.getMessage();
-			}
-		}
+    /**
+     * @return <code>null</code> for success or a string in case of an error.
+     */
+    public static String displayUrl(String url) {
+        if (Main.applet) {
+            try {
+                JApplet applet = (JApplet) Main.parent;
+                applet.getAppletContext().showDocument(new URL(url));
+                return null;
+            } catch (MalformedURLException mue) {
+                return mue.getMessage();
+            }
+        }
 
-		try {
-			Main.platform.openUrl(url);
-		} catch (IOException e) {
-			return e.getMessage();
-		}
-		return null;
-	}
+        try {
+            Main.platform.openUrl(url);
+        } catch (IOException e) {
+            return e.getMessage();
+        }
+        return null;
+    }
 
 }
Index: trunk/src/org/openstreetmap/josm/tools/Pair.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Pair.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/Pair.java	(revision 1169)
@@ -6,35 +6,35 @@
  */
 public final class Pair<A,B> {
-	public A a;
-	public B b;
+    public A a;
+    public B b;
 
-	public Pair(A a, B b) {
-		this.a = a;
-		this.b = b;
-	}
+    public Pair(A a, B b) {
+        this.a = a;
+        this.b = b;
+    }
 
-	@Override public int hashCode() {
-		return a.hashCode() ^ b.hashCode();
-	}
+    @Override public int hashCode() {
+        return a.hashCode() ^ b.hashCode();
+    }
 
-	@Override public boolean equals(Object o) {
-		return o == null ? o == null : o instanceof Pair
-			&& a.equals(((Pair<?,?>) o).a) && b.equals(((Pair<?,?>) o).b);
-	}
+    @Override public boolean equals(Object o) {
+        return o == null ? o == null : o instanceof Pair
+            && a.equals(((Pair<?,?>) o).a) && b.equals(((Pair<?,?>) o).b);
+    }
 
-	public static <T> ArrayList<T> toArrayList(Pair<T, T> p) {
-		ArrayList<T> l = new ArrayList<T>(2);
-		l.add(p.a);
-		l.add(p.b);
-		return l;
-	}
+    public static <T> ArrayList<T> toArrayList(Pair<T, T> p) {
+        ArrayList<T> l = new ArrayList<T>(2);
+        l.add(p.a);
+        l.add(p.b);
+        return l;
+    }
 
-	public static <T> Pair<T,T> sort(Pair<T,T> p) {
-		if (p.b.hashCode() < p.a.hashCode()) {
-			T tmp = p.a;
-			p.a = p.b;
-			p.b = tmp;
-		}
-		return p;
-	}
+    public static <T> Pair<T,T> sort(Pair<T,T> p) {
+        if (p.b.hashCode() < p.a.hashCode()) {
+            T tmp = p.a;
+            p.a = p.b;
+            p.b = tmp;
+        }
+        return p;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 1169)
@@ -29,77 +29,77 @@
  */
 public interface PlatformHook {
-	/**
-	  * The preStartupHook will be called extremly early. It is
-	  * guaranteed to be called before the GUI setup has started.
-	  *
-	  * Reason: On OSX we need to inform the Swing libraries
-	  * that we want to be integrated with the OS before we setup
-	  * our GUI.
-	  */
-	public void preStartupHook();
+    /**
+      * The preStartupHook will be called extremly early. It is
+      * guaranteed to be called before the GUI setup has started.
+      *
+      * Reason: On OSX we need to inform the Swing libraries
+      * that we want to be integrated with the OS before we setup
+      * our GUI.
+      */
+    public void preStartupHook();
 
-	/**
-	  * The startupHook will be called early, but after the GUI
-	  * setup has started.
-	  *
-	  * Reason: On OSX we need to register some callbacks with the
-	  * OS, so we'll receive events from the system menu.
-	  */
-	public void startupHook();
+    /**
+      * The startupHook will be called early, but after the GUI
+      * setup has started.
+      *
+      * Reason: On OSX we need to register some callbacks with the
+      * OS, so we'll receive events from the system menu.
+      */
+    public void startupHook();
 
-	/**
-	  * The openURL hook will be used to open an URL in the
-	  * default webbrowser.
-	  */
-	public void openUrl(String url) throws IOException;
+    /**
+      * The openURL hook will be used to open an URL in the
+      * default webbrowser.
+      */
+    public void openUrl(String url) throws IOException;
 
-	/**
-	  * The initShortcutGroups hook will be called by the
-	  * Shortcut class if it detects that there are no
-	  * groups in teh config file. So that will happen
-	  * once on each JOSM installation only.
-	  *
-	  * Please note that ShorCut will load its config on demand,
-	  * that is, at the moment the first shortcut is registered.
-	  *
-	  * In this hook, you have to fill the preferences with
-	  * data, not the internal structures! Also, do not try
-	  * to register any shortcuts from within.
-	  */
-	public void initShortcutGroups();
+    /**
+      * The initShortcutGroups hook will be called by the
+      * Shortcut class if it detects that there are no
+      * groups in teh config file. So that will happen
+      * once on each JOSM installation only.
+      *
+      * Please note that ShorCut will load its config on demand,
+      * that is, at the moment the first shortcut is registered.
+      *
+      * In this hook, you have to fill the preferences with
+      * data, not the internal structures! Also, do not try
+      * to register any shortcuts from within.
+      */
+    public void initShortcutGroups();
 
-	/**
-	  * The initSystemShortcuts hook will be called by the
-	  * Shortcut class after the modifier groups have been read
-	  * from the config, but before any shortcuts are read from
-	  * it or registered from within the application.
-	  *
-	  * Plese note that you are not allowed to register any
-	  * shortuts from this hook, but only "systemCuts"!
-	  *
-	  * BTW: SystemCuts should be named "system:<whatever>",
-	  * and it'd be best if sou'd recycle the names already used
-	  * by the Windows and OSX hooks. Especially the later has
-	  * really many of them.
-	  *
-	  * You should also register any and all shortcuts that the
-	  * operation system handles itself to block JOSM from trying
-	  * to use them---as that would just not work. Call setAutomatic
-	  * on them to prevent the keyboard preferences from allowing the
-	  * user to change them.
-	  */
-	public void initSystemShortcuts();
+    /**
+      * The initSystemShortcuts hook will be called by the
+      * Shortcut class after the modifier groups have been read
+      * from the config, but before any shortcuts are read from
+      * it or registered from within the application.
+      *
+      * Plese note that you are not allowed to register any
+      * shortuts from this hook, but only "systemCuts"!
+      *
+      * BTW: SystemCuts should be named "system:<whatever>",
+      * and it'd be best if sou'd recycle the names already used
+      * by the Windows and OSX hooks. Especially the later has
+      * really many of them.
+      *
+      * You should also register any and all shortcuts that the
+      * operation system handles itself to block JOSM from trying
+      * to use them---as that would just not work. Call setAutomatic
+      * on them to prevent the keyboard preferences from allowing the
+      * user to change them.
+      */
+    public void initSystemShortcuts();
 
-	/**
-	  * The makeTooltip hook will be called whenever a tooltip for
-	  * a menu or button is created.
-	  *
-	  * Tooltips are usually not system dependent, unless the
-	  * JVM is to dumb to provide correct names for all the keys.
-	  *
-	  * Another reason not to use the implementation in the *nix
-	  * hook are LAFs that don't understand HTML, such as the OSX
-	  * LAFs.
-	  */
-	public String makeTooltip(String name, Shortcut sc);
+    /**
+      * The makeTooltip hook will be called whenever a tooltip for
+      * a menu or button is created.
+      *
+      * Tooltips are usually not system dependent, unless the
+      * JVM is to dumb to provide correct names for all the keys.
+      *
+      * Another reason not to use the implementation in the *nix
+      * hook are LAFs that don't understand HTML, such as the OSX
+      * LAFs.
+      */
+    public String makeTooltip(String name, Shortcut sc);
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 1169)
@@ -16,233 +16,233 @@
   */
 public class PlatformHookOsx extends PlatformHookUnixoid implements PlatformHook, InvocationHandler {
-	private static PlatformHookOsx ivhandler = new PlatformHookOsx();
-	public void preStartupHook(){
-		// This will merge our MenuBar into the system menu.
-		// MUST be set before Swing is initialized!
-		// And will not work when one of the system independet LAFs is used.
-		// They just insist on painting themselves...
-		System.setProperty("apple.laf.useScreenMenuBar", "true");
-	}
-	public void startupHook() {
-		// Here we register callbacks for the menu entries in the system menu
-		try {
-			Class Ccom_apple_eawt_Application = Class.forName("com.apple.eawt.Application");
-			Object Ocom_apple_eawt_Application = Ccom_apple_eawt_Application.getConstructor((Class[])null).newInstance((Object[])null);
-			Class Ccom_apple_eawt_ApplicationListener = Class.forName("com.apple.eawt.ApplicationListener");
-			Method MaddApplicationListener = Ccom_apple_eawt_Application.getDeclaredMethod("addApplicationListener", new Class[] { Ccom_apple_eawt_ApplicationListener });
-			Object Oproxy = Proxy.newProxyInstance(PlatformHookOsx.class.getClassLoader(), new Class[] { Ccom_apple_eawt_ApplicationListener }, ivhandler);
-			MaddApplicationListener.invoke(Ocom_apple_eawt_Application, new Object[] { Oproxy });
-			Method MsetEnabledPreferencesMenu = Ccom_apple_eawt_Application.getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
-			MsetEnabledPreferencesMenu.invoke(Ocom_apple_eawt_Application, new Object[] { Boolean.TRUE });
-		} catch (Exception ex) {
-			// Oops, what now?
-			// We'll just ignore this for now. The user will still be able to close JOSM
-			// by closing all its windows.
-			System.out.println("Failed to register with OSX: " + ex);
-		}
-	}
-	public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
-		Boolean handled = Boolean.TRUE;
-		//System.out.println("Going to handle method "+method+" (short: "+method.getName()+") with event "+args[0]);
-		if (method.getName().equals("handleQuit")) {
-			handled = !Main.main.breakBecauseUnsavedChanges();
-		} else if (method.getName().equals("handleAbout")) {
-			Main.main.menu.about.actionPerformed(null);
-		} else if (method.getName().equals("handlePreferences")) {
-			Main.main.menu.preferences.actionPerformed(null);
-		} else {
-			return null;
-		}
-		if (args[0] != null) {
-			try {
-				args[0].getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class }).invoke(args[0], new Object[] { handled });
-			} catch (Exception ex) {
-				System.out.println("Failed to report handled event: " + ex);
-			}
-		}
-		return null;
-	}
-	public void openUrl(String url) throws IOException {
-		// Ain't that KISS?
-		Runtime.getRuntime().exec("open " + url);
-	}
-	public void initShortcutGroups() {
-		// Everything but Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU is guesswork.
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.META_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
-
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-	}
-	public void initSystemShortcuts() {
-		// Yeah, it's a long, long list. And people always complain that OSX has no shortcuts.
-		Shortcut.registerSystemShortcut("apple-reserved-01", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Show or hide the Spotlight search field (when multiple languages are installed, may rotate through enabled script systems).
-		Shortcut.registerSystemShortcut("apple-reserved-02", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Apple reserved.
-		Shortcut.registerSystemShortcut("apple-reserved-03", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show the Spotlight search results window (when multiple languages are installed, may rotate through keyboard layouts and input methods within a script).
-		Shortcut.registerSystemShortcut("apple-reserved-04", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); //  | Apple reserved.
-		Shortcut.registerSystemShortcut("apple-reserved-05", "reserved", KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Navigate through controls in a reverse direction. See "Keyboard Focus and Navigation."
-		Shortcut.registerSystemShortcut("apple-reserved-06", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK).setAutomatic(); // Move forward to the next most recently used application in a list of open applications.
-		Shortcut.registerSystemShortcut("apple-reserved-07", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move backward through a list of open applications (sorted by recent use).
-		Shortcut.registerSystemShortcut("apple-reserved-08", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the next grouping of controls in a dialog or the next table (when Tab moves to the next cell). See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-09", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous grouping of controls. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-10", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open Front Row.
-		Shortcut.registerSystemShortcut("apple-reserved-11", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Open the Force Quit dialog.
-		Shortcut.registerSystemShortcut("apple-reserved-12", "reserved", KeyEvent.VK_F1, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Toggle full keyboard access on or off. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-13", "reserved", KeyEvent.VK_F2, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the menu bar. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-14", "reserved", KeyEvent.VK_F3, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the Dock. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-15", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the active (or next) window. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-16", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previously active window. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-17", "reserved", KeyEvent.VK_F5, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the toolbar. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-18", "reserved", KeyEvent.VK_F5, KeyEvent.META_DOWN_MASK).setAutomatic(); // Turn VoiceOver on or off. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-19", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the first (or next) panel. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-20", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous panel. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-21", "reserved", KeyEvent.VK_F7, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Temporarily override the current keyboard access mode in windows and dialogs. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-22", "reserved", KeyEvent.VK_F9, 0).setAutomatic(); // Tile or untile all open windows.
-		Shortcut.registerSystemShortcut("apple-reserved-23", "reserved", KeyEvent.VK_F10, 0).setAutomatic(); // Tile or untile all open windows in the currently active application.
-		Shortcut.registerSystemShortcut("apple-reserved-24", "reserved", KeyEvent.VK_F11, 0).setAutomatic(); // Hide or show all open windows.
-		Shortcut.registerSystemShortcut("apple-reserved-25", "reserved", KeyEvent.VK_F12, 0).setAutomatic(); // Hide or display Dashboard.
-		Shortcut.registerSystemShortcut("apple-reserved-26", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Activate the next open window in the frontmost application. See "Window Layering."
-		Shortcut.registerSystemShortcut("apple-reserved-27", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Activate the previous open window in the frontmost application. See "Window Layering."
-		Shortcut.registerSystemShortcut("apple-reserved-28", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Move focus to the window drawer.
-		Shortcut.registerSystemShortcut("apple-reserved-29", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK).setAutomatic(); // Decrease the size of the selected item (equivalent to the Smaller command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("apple-reserved-30", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom out when screen zooming is on. See Accessibility Overview.
-
-		Shortcut.registerSystemShortcut("system:align-left", "reserved", KeyEvent.VK_OPEN_BRACKET, KeyEvent.META_DOWN_MASK); // Left-align a selection (equivalent to the Align Left command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:align-right","reserved", KeyEvent.VK_CLOSE_BRACKET, KeyEvent.META_DOWN_MASK); // Right-align a selection (equivalent to the Align Right command). See "The Format Menu."
-		// I found no KeyEvent for |
-		//Shortcut.registerSystemCut("system:align-center", "reserved", '|', KeyEvent.META_DOWN_MASK); // Center-align a selection (equivalent to the Align Center command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:spelling", "reserved", KeyEvent.VK_COLON, KeyEvent.META_DOWN_MASK); // Display the Spelling window (equivalent to the Spelling command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:spellcheck", "reserved", KeyEvent.VK_SEMICOLON, KeyEvent.META_DOWN_MASK); // Find misspelled words in the document (equivalent to the Check Spelling command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:preferences", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's preferences window (equivalent to the Preferences command). See "The Application Menu."
-
-		Shortcut.registerSystemShortcut("apple-reserved-31", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Decrease screen contrast. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-32", "reserved", KeyEvent.VK_PERIOD, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Increase screen contrast. See Accessibility Overview.
-
-		// I found no KeyEvent for ?
-		//Shortcut.registerSystemCut("system:help", "reserved", '?', KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's help in Help Viewer. See "The Help Menu."
-
-		Shortcut.registerSystemShortcut("apple-reserved-33", "reserved", KeyEvent.VK_SLASH, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn font smoothing on or off.
-		Shortcut.registerSystemShortcut("apple-reserved-34", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Increase the size of the selected item (equivalent to the Bigger command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("apple-reserved-35", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom in when screen zooming is on. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-36", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture the screen to a file.
-		Shortcut.registerSystemShortcut("apple-reserved-37", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture the screen to the Clipboard.
-		Shortcut.registerSystemShortcut("apple-reserved-38", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture a selection to a file.
-		Shortcut.registerSystemShortcut("apple-reserved-39", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture a selection to the Clipboard.
-		Shortcut.registerSystemShortcut("apple-reserved-40", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn screen zooming on or off. See Accessibility Overview.
-		Shortcut.registerSystemShortcut("apple-reserved-41", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Invert the screen colors. See Accessibility Overview.
-
-		Shortcut.registerSystemShortcut("system:selectall", "reserved", KeyEvent.VK_A, KeyEvent.META_DOWN_MASK); // Highlight every item in a document or window, or all characters in a text field (equivalent to the Select All command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:bold", "reserved", KeyEvent.VK_B, KeyEvent.META_DOWN_MASK); // Boldface the selected text or toggle boldfaced text on and off (equivalent to the Bold command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:copy", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK); // Duplicate the selected data and store on the Clipboard (equivalent to the Copy command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:colors", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Colors window (equivalent to the Show Colors command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:copystyle", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Copy the style of the selected text (equivalent to the Copy Style command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:copyformat", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Copy the formatting settings of the selected item and store on the Clipboard (equivalent to the Copy Ruler command). See "The Format Menu."
-
-		Shortcut.registerSystemShortcut("apple-reserved-42", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show or hide the Dock. See "The Dock."
-
-		Shortcut.registerSystemShortcut("system:dictionarylookup", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Display the definition of the selected word in the Dictionary application.
-		Shortcut.registerSystemShortcut("system:findselected", "reserved", KeyEvent.VK_E, KeyEvent.META_DOWN_MASK); // Use the selection for a find operation. See "Find Windows."
-		Shortcut.registerSystemShortcut("system:find", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK); // Open a Find window (equivalent to the Find command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:search", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Jump to the search field control. See "Search Fields."
-		Shortcut.registerSystemShortcut("system:findnext", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK); // Find the next occurrence of the selection (equivalent to the Find Next command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:findprev", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Find the previous occurrence of the selection (equivalent to the Find Previous command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:hide", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK).setAutomatic(); // Hide the windows of the currently running application (equivalent to the Hide ApplicationName command). See "The Application Menu."
-		Shortcut.registerSystemShortcut("system:hideothers", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Hide the windows of all other running applications (equivalent to the Hide Others command). See "The Application Menu."
-		// What about applications that have italic text AND info windows?
-		//Shortcut.registerSystemCut("system:italic", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Italicize the selected text or toggle italic text on or off (equivalent to the Italic command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:info", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Display an Info window. See "Inspector Windows."
-		Shortcut.registerSystemShortcut("system:inspector", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Display an inspector window. See "Inspector Windows."
-		Shortcut.registerSystemShortcut("system:toselection", "reserved", KeyEvent.VK_J, KeyEvent.META_DOWN_MASK); // Scroll to a selection.
-		Shortcut.registerSystemShortcut("system:minimize", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK); // Minimize the active window to the Dock (equivalent to the Minimize command). See "The Window Menu."
-		Shortcut.registerSystemShortcut("system:minimizeall", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Minimize all windows of the active application to the Dock (equivalent to the Minimize All command). See "The Window Menu."
-		Shortcut.registerSystemShortcut("system:new", "reserved", KeyEvent.VK_N, KeyEvent.META_DOWN_MASK); // Open a new document (equivalent to the New command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:open", "reserved", KeyEvent.VK_O, KeyEvent.META_DOWN_MASK); // Display a dialog for choosing a document to open (equivalent to the Open command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:print", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK); // Display the Print dialog (equivalent to the Print command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:printsetup", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display a dialog for specifying printing parameters (equivalent to the Page Setup command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:menuexit", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK).setAutomatic(); // Quit the application (equivalent to the Quit command). See "The Application Menu."
-
-		Shortcut.registerSystemShortcut("apple-reserved-43", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Log out the current user (equivalent to the Log Out command).
-		Shortcut.registerSystemShortcut("apple-reserved-44", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Log out the current user without confirmation.
-
-		Shortcut.registerSystemShortcut("system:save", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK); // Save the active document (equivalent to the Save command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:saveas", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Save dialog (equivalent to the Save As command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:fonts", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK); // Display the Fonts window (equivalent to the Show Fonts command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:toggletoolbar", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Show or hide a toolbar (equivalent to the Show/Hide Toolbar command). See "The View Menu" and "Toolbars."
-		Shortcut.registerSystemShortcut("system:underline", "reserved", KeyEvent.VK_U, KeyEvent.META_DOWN_MASK); // Underline the selected text or turn underlining on or off (equivalent to the Underline command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:paste", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK); // Insert the Clipboard contents at the insertion point (equivalent to the Paste command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:pastestyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of one object to the selected object (equivalent to the Paste Style command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:pastemwithoutstyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of the surrounding text to the inserted object (equivalent to the Paste and Match Style command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:pasteformatting", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Apply formatting settings to the selected object (equivalent to the Paste Ruler command). See "The Format Menu."
-		Shortcut.registerSystemShortcut("system:closewindow", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK); // Close the active window (equivalent to the Close command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:closefile", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Close a file and its associated windows (equivalent to the Close File command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:closeallwindows", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Close all windows in the application (equivalent to the Close All command). See "The File Menu."
-		Shortcut.registerSystemShortcut("system:cut", "reserved", KeyEvent.VK_X, KeyEvent.META_DOWN_MASK); // Remove the selection and store on the Clipboard (equivalent to the Cut command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:undo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK); // Reverse the effect of the user's previous operation (equivalent to the Undo command). See "The Edit Menu."
-		Shortcut.registerSystemShortcut("system:redo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Reverse the effect of the last Undo command (equivalent to the Redo command). See "The Edit Menu."
-
-		Shortcut.registerSystemShortcut("apple-reserved-45", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of Roman script.
-		//Shortcut.registerSystemCut("apple-reserved-46", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the next semantic unit, typically the end of the current line.
-		//Shortcut.registerSystemCut("apple-reserved-47", "reserved", KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the right.
-		//Shortcut.registerSystemCut("apple-reserved-48", "reserved", KeyEvent.VK_RIGHT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current word, then to the end of the next word.
-
-		Shortcut.registerSystemShortcut("system:movefocusright", "reserved", KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
-
-		Shortcut.registerSystemShortcut("apple-reserved-49", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of system script.
-		//Shortcut.registerSystemCut("apple-reserved-50", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the previous semantic unit, typically the beginning of the current line.
-		//Shortcut.registerSystemCut("apple-reserved-51", "reserved", KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the left.
-		//Shortcut.registerSystemCut("apple-reserved-52", "reserved", KeyEvent.VK_LEFT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current word, then to the beginning of the previous word.
-
-		Shortcut.registerSystemShortcut("system:movefocusleft", "reserved", KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
-
-		//Shortcut.registerSystemCut("apple-reserved-53", "reserved", KeyEvent.VK_UP, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection upward in the next semantic unit, typically the beginning of the document.
-		//Shortcut.registerSystemCut("apple-reserved-54", "reserved", KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line above, to the nearest character boundary at the same horizontal location.
-		//Shortcut.registerSystemCut("apple-reserved-55", "reserved", KeyEvent.VK_UP, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current paragraph, then to the beginning of the next paragraph.
-
-		Shortcut.registerSystemShortcut("system:movefocusup", "reserved", KeyEvent.VK_UP, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
-
-		//Shortcut.registerSystemCut("apple-reserved-56", "reserved", KeyEvent.VK_DOWN, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection downward in the next semantic unit, typically the end of the document.
-		//Shortcut.registerSystemCut("apple-reserved-57", "reserved", KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line below, to the nearest character boundary at the same horizontal location.
-		//Shortcut.registerSystemCut("apple-reserved-58", "reserved", KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current paragraph, then to the end of the next paragraph (include the blank line between paragraphs in cut, copy, and paste operations).
-
-		Shortcut.registerSystemShortcut("system:movefocusdown", "reserved", KeyEvent.VK_DOWN, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
-
-		Shortcut.registerSystemShortcut("system:about", "reserved", 0, -1).setAutomatic(); // About
-	}
-	public String makeTooltip(String name, Shortcut sc) {
-		String lafid = UIManager.getLookAndFeel().getID();
-		boolean canHtml = true;
-		// "Mac" is the native LAF, "Aqua" is Quaqua. Both use native menus with native tooltips.
-		if (lafid.contains("Mac") || lafid.contains("Aqua")) {
-			canHtml = false;
-		}
-		String result = "";
-		if (canHtml) result += "<html>";
-		result += name;
-		if (sc != null && sc.getKeyText().length() != 0) {
-			result += " ";
-			if (canHtml) result += "<font size='-2'>";
-			result += "("+sc.getKeyText()+")";
-			if (canHtml) result += "</font>";
-		}
-		if (canHtml) result += "&nbsp;</html>";
-		return result;
-	}
+    private static PlatformHookOsx ivhandler = new PlatformHookOsx();
+    public void preStartupHook(){
+        // This will merge our MenuBar into the system menu.
+        // MUST be set before Swing is initialized!
+        // And will not work when one of the system independet LAFs is used.
+        // They just insist on painting themselves...
+        System.setProperty("apple.laf.useScreenMenuBar", "true");
+    }
+    public void startupHook() {
+        // Here we register callbacks for the menu entries in the system menu
+        try {
+            Class Ccom_apple_eawt_Application = Class.forName("com.apple.eawt.Application");
+            Object Ocom_apple_eawt_Application = Ccom_apple_eawt_Application.getConstructor((Class[])null).newInstance((Object[])null);
+            Class Ccom_apple_eawt_ApplicationListener = Class.forName("com.apple.eawt.ApplicationListener");
+            Method MaddApplicationListener = Ccom_apple_eawt_Application.getDeclaredMethod("addApplicationListener", new Class[] { Ccom_apple_eawt_ApplicationListener });
+            Object Oproxy = Proxy.newProxyInstance(PlatformHookOsx.class.getClassLoader(), new Class[] { Ccom_apple_eawt_ApplicationListener }, ivhandler);
+            MaddApplicationListener.invoke(Ocom_apple_eawt_Application, new Object[] { Oproxy });
+            Method MsetEnabledPreferencesMenu = Ccom_apple_eawt_Application.getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
+            MsetEnabledPreferencesMenu.invoke(Ocom_apple_eawt_Application, new Object[] { Boolean.TRUE });
+        } catch (Exception ex) {
+            // Oops, what now?
+            // We'll just ignore this for now. The user will still be able to close JOSM
+            // by closing all its windows.
+            System.out.println("Failed to register with OSX: " + ex);
+        }
+    }
+    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
+        Boolean handled = Boolean.TRUE;
+        //System.out.println("Going to handle method "+method+" (short: "+method.getName()+") with event "+args[0]);
+        if (method.getName().equals("handleQuit")) {
+            handled = !Main.main.breakBecauseUnsavedChanges();
+        } else if (method.getName().equals("handleAbout")) {
+            Main.main.menu.about.actionPerformed(null);
+        } else if (method.getName().equals("handlePreferences")) {
+            Main.main.menu.preferences.actionPerformed(null);
+        } else {
+            return null;
+        }
+        if (args[0] != null) {
+            try {
+                args[0].getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class }).invoke(args[0], new Object[] { handled });
+            } catch (Exception ex) {
+                System.out.println("Failed to report handled event: " + ex);
+            }
+        }
+        return null;
+    }
+    public void openUrl(String url) throws IOException {
+        // Ain't that KISS?
+        Runtime.getRuntime().exec("open " + url);
+    }
+    public void initShortcutGroups() {
+        // Everything but Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU is guesswork.
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.META_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
+
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+    }
+    public void initSystemShortcuts() {
+        // Yeah, it's a long, long list. And people always complain that OSX has no shortcuts.
+        Shortcut.registerSystemShortcut("apple-reserved-01", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Show or hide the Spotlight search field (when multiple languages are installed, may rotate through enabled script systems).
+        Shortcut.registerSystemShortcut("apple-reserved-02", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Apple reserved.
+        Shortcut.registerSystemShortcut("apple-reserved-03", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show the Spotlight search results window (when multiple languages are installed, may rotate through keyboard layouts and input methods within a script).
+        Shortcut.registerSystemShortcut("apple-reserved-04", "reserved", KeyEvent.VK_SPACE, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); //  | Apple reserved.
+        Shortcut.registerSystemShortcut("apple-reserved-05", "reserved", KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Navigate through controls in a reverse direction. See "Keyboard Focus and Navigation."
+        Shortcut.registerSystemShortcut("apple-reserved-06", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK).setAutomatic(); // Move forward to the next most recently used application in a list of open applications.
+        Shortcut.registerSystemShortcut("apple-reserved-07", "reserved", KeyEvent.VK_TAB, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move backward through a list of open applications (sorted by recent use).
+        Shortcut.registerSystemShortcut("apple-reserved-08", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the next grouping of controls in a dialog or the next table (when Tab moves to the next cell). See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-09", "reserved", KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous grouping of controls. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-10", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open Front Row.
+        Shortcut.registerSystemShortcut("apple-reserved-11", "reserved", KeyEvent.VK_ESCAPE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Open the Force Quit dialog.
+        Shortcut.registerSystemShortcut("apple-reserved-12", "reserved", KeyEvent.VK_F1, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Toggle full keyboard access on or off. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-13", "reserved", KeyEvent.VK_F2, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the menu bar. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-14", "reserved", KeyEvent.VK_F3, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the Dock. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-15", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the active (or next) window. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-16", "reserved", KeyEvent.VK_F4, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previously active window. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-17", "reserved", KeyEvent.VK_F5, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the toolbar. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-18", "reserved", KeyEvent.VK_F5, KeyEvent.META_DOWN_MASK).setAutomatic(); // Turn VoiceOver on or off. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-19", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Move focus to the first (or next) panel. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-20", "reserved", KeyEvent.VK_F6, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Move focus to the previous panel. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-21", "reserved", KeyEvent.VK_F7, KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Temporarily override the current keyboard access mode in windows and dialogs. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-22", "reserved", KeyEvent.VK_F9, 0).setAutomatic(); // Tile or untile all open windows.
+        Shortcut.registerSystemShortcut("apple-reserved-23", "reserved", KeyEvent.VK_F10, 0).setAutomatic(); // Tile or untile all open windows in the currently active application.
+        Shortcut.registerSystemShortcut("apple-reserved-24", "reserved", KeyEvent.VK_F11, 0).setAutomatic(); // Hide or show all open windows.
+        Shortcut.registerSystemShortcut("apple-reserved-25", "reserved", KeyEvent.VK_F12, 0).setAutomatic(); // Hide or display Dashboard.
+        Shortcut.registerSystemShortcut("apple-reserved-26", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK).setAutomatic(); // Activate the next open window in the frontmost application. See "Window Layering."
+        Shortcut.registerSystemShortcut("apple-reserved-27", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Activate the previous open window in the frontmost application. See "Window Layering."
+        Shortcut.registerSystemShortcut("apple-reserved-28", "reserved", KeyEvent.VK_DEAD_GRAVE, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Move focus to the window drawer.
+        Shortcut.registerSystemShortcut("apple-reserved-29", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK).setAutomatic(); // Decrease the size of the selected item (equivalent to the Smaller command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("apple-reserved-30", "reserved", KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom out when screen zooming is on. See Accessibility Overview.
+
+        Shortcut.registerSystemShortcut("system:align-left", "reserved", KeyEvent.VK_OPEN_BRACKET, KeyEvent.META_DOWN_MASK); // Left-align a selection (equivalent to the Align Left command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:align-right","reserved", KeyEvent.VK_CLOSE_BRACKET, KeyEvent.META_DOWN_MASK); // Right-align a selection (equivalent to the Align Right command). See "The Format Menu."
+        // I found no KeyEvent for |
+        //Shortcut.registerSystemCut("system:align-center", "reserved", '|', KeyEvent.META_DOWN_MASK); // Center-align a selection (equivalent to the Align Center command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:spelling", "reserved", KeyEvent.VK_COLON, KeyEvent.META_DOWN_MASK); // Display the Spelling window (equivalent to the Spelling command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:spellcheck", "reserved", KeyEvent.VK_SEMICOLON, KeyEvent.META_DOWN_MASK); // Find misspelled words in the document (equivalent to the Check Spelling command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:preferences", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's preferences window (equivalent to the Preferences command). See "The Application Menu."
+
+        Shortcut.registerSystemShortcut("apple-reserved-31", "reserved", KeyEvent.VK_COMMA, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Decrease screen contrast. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-32", "reserved", KeyEvent.VK_PERIOD, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Increase screen contrast. See Accessibility Overview.
+
+        // I found no KeyEvent for ?
+        //Shortcut.registerSystemCut("system:help", "reserved", '?', KeyEvent.META_DOWN_MASK).setAutomatic(); // Open the application's help in Help Viewer. See "The Help Menu."
+
+        Shortcut.registerSystemShortcut("apple-reserved-33", "reserved", KeyEvent.VK_SLASH, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn font smoothing on or off.
+        Shortcut.registerSystemShortcut("apple-reserved-34", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Increase the size of the selected item (equivalent to the Bigger command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("apple-reserved-35", "reserved", KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Zoom in when screen zooming is on. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-36", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture the screen to a file.
+        Shortcut.registerSystemShortcut("apple-reserved-37", "reserved", KeyEvent.VK_3, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture the screen to the Clipboard.
+        Shortcut.registerSystemShortcut("apple-reserved-38", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Capture a selection to a file.
+        Shortcut.registerSystemShortcut("apple-reserved-39", "reserved", KeyEvent.VK_4, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Capture a selection to the Clipboard.
+        Shortcut.registerSystemShortcut("apple-reserved-40", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Turn screen zooming on or off. See Accessibility Overview.
+        Shortcut.registerSystemShortcut("apple-reserved-41", "reserved", KeyEvent.VK_8, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Invert the screen colors. See Accessibility Overview.
+
+        Shortcut.registerSystemShortcut("system:selectall", "reserved", KeyEvent.VK_A, KeyEvent.META_DOWN_MASK); // Highlight every item in a document or window, or all characters in a text field (equivalent to the Select All command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:bold", "reserved", KeyEvent.VK_B, KeyEvent.META_DOWN_MASK); // Boldface the selected text or toggle boldfaced text on and off (equivalent to the Bold command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:copy", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK); // Duplicate the selected data and store on the Clipboard (equivalent to the Copy command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:colors", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Colors window (equivalent to the Show Colors command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:copystyle", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Copy the style of the selected text (equivalent to the Copy Style command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:copyformat", "reserved", KeyEvent.VK_C, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK).setAutomatic(); // Copy the formatting settings of the selected item and store on the Clipboard (equivalent to the Copy Ruler command). See "The Format Menu."
+
+        Shortcut.registerSystemShortcut("apple-reserved-42", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Show or hide the Dock. See "The Dock."
+
+        Shortcut.registerSystemShortcut("system:dictionarylookup", "reserved", KeyEvent.VK_D, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Display the definition of the selected word in the Dictionary application.
+        Shortcut.registerSystemShortcut("system:findselected", "reserved", KeyEvent.VK_E, KeyEvent.META_DOWN_MASK); // Use the selection for a find operation. See "Find Windows."
+        Shortcut.registerSystemShortcut("system:find", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK); // Open a Find window (equivalent to the Find command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:search", "reserved", KeyEvent.VK_F, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Jump to the search field control. See "Search Fields."
+        Shortcut.registerSystemShortcut("system:findnext", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK); // Find the next occurrence of the selection (equivalent to the Find Next command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:findprev", "reserved", KeyEvent.VK_G, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Find the previous occurrence of the selection (equivalent to the Find Previous command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:hide", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK).setAutomatic(); // Hide the windows of the currently running application (equivalent to the Hide ApplicationName command). See "The Application Menu."
+        Shortcut.registerSystemShortcut("system:hideothers", "reserved", KeyEvent.VK_H, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Hide the windows of all other running applications (equivalent to the Hide Others command). See "The Application Menu."
+        // What about applications that have italic text AND info windows?
+        //Shortcut.registerSystemCut("system:italic", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Italicize the selected text or toggle italic text on or off (equivalent to the Italic command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:info", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK); // Display an Info window. See "Inspector Windows."
+        Shortcut.registerSystemShortcut("system:inspector", "reserved", KeyEvent.VK_I, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Display an inspector window. See "Inspector Windows."
+        Shortcut.registerSystemShortcut("system:toselection", "reserved", KeyEvent.VK_J, KeyEvent.META_DOWN_MASK); // Scroll to a selection.
+        Shortcut.registerSystemShortcut("system:minimize", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK); // Minimize the active window to the Dock (equivalent to the Minimize command). See "The Window Menu."
+        Shortcut.registerSystemShortcut("system:minimizeall", "reserved", KeyEvent.VK_M, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Minimize all windows of the active application to the Dock (equivalent to the Minimize All command). See "The Window Menu."
+        Shortcut.registerSystemShortcut("system:new", "reserved", KeyEvent.VK_N, KeyEvent.META_DOWN_MASK); // Open a new document (equivalent to the New command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:open", "reserved", KeyEvent.VK_O, KeyEvent.META_DOWN_MASK); // Display a dialog for choosing a document to open (equivalent to the Open command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:print", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK); // Display the Print dialog (equivalent to the Print command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:printsetup", "reserved", KeyEvent.VK_P, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display a dialog for specifying printing parameters (equivalent to the Page Setup command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:menuexit", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK).setAutomatic(); // Quit the application (equivalent to the Quit command). See "The Application Menu."
+
+        Shortcut.registerSystemShortcut("apple-reserved-43", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Log out the current user (equivalent to the Log Out command).
+        Shortcut.registerSystemShortcut("apple-reserved-44", "reserved", KeyEvent.VK_Q, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic(); // Log out the current user without confirmation.
+
+        Shortcut.registerSystemShortcut("system:save", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK); // Save the active document (equivalent to the Save command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:saveas", "reserved", KeyEvent.VK_S, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Display the Save dialog (equivalent to the Save As command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:fonts", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK); // Display the Fonts window (equivalent to the Show Fonts command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:toggletoolbar", "reserved", KeyEvent.VK_T, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Show or hide a toolbar (equivalent to the Show/Hide Toolbar command). See "The View Menu" and "Toolbars."
+        Shortcut.registerSystemShortcut("system:underline", "reserved", KeyEvent.VK_U, KeyEvent.META_DOWN_MASK); // Underline the selected text or turn underlining on or off (equivalent to the Underline command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:paste", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK); // Insert the Clipboard contents at the insertion point (equivalent to the Paste command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:pastestyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of one object to the selected object (equivalent to the Paste Style command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:pastemwithoutstyle", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Apply the style of the surrounding text to the inserted object (equivalent to the Paste and Match Style command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:pasteformatting", "reserved", KeyEvent.VK_V, KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); // Apply formatting settings to the selected object (equivalent to the Paste Ruler command). See "The Format Menu."
+        Shortcut.registerSystemShortcut("system:closewindow", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK); // Close the active window (equivalent to the Close command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:closefile", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Close a file and its associated windows (equivalent to the Close File command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:closeallwindows", "reserved", KeyEvent.VK_W, KeyEvent.META_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); // Close all windows in the application (equivalent to the Close All command). See "The File Menu."
+        Shortcut.registerSystemShortcut("system:cut", "reserved", KeyEvent.VK_X, KeyEvent.META_DOWN_MASK); // Remove the selection and store on the Clipboard (equivalent to the Cut command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:undo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK); // Reverse the effect of the user's previous operation (equivalent to the Undo command). See "The Edit Menu."
+        Shortcut.registerSystemShortcut("system:redo", "reserved", KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); // Reverse the effect of the last Undo command (equivalent to the Redo command). See "The Edit Menu."
+
+        Shortcut.registerSystemShortcut("apple-reserved-45", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of Roman script.
+        //Shortcut.registerSystemCut("apple-reserved-46", "reserved", KeyEvent.VK_RIGHT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the next semantic unit, typically the end of the current line.
+        //Shortcut.registerSystemCut("apple-reserved-47", "reserved", KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the right.
+        //Shortcut.registerSystemCut("apple-reserved-48", "reserved", KeyEvent.VK_RIGHT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current word, then to the end of the next word.
+
+        Shortcut.registerSystemShortcut("system:movefocusright", "reserved", KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
+
+        Shortcut.registerSystemShortcut("apple-reserved-49", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK).setAutomatic(); // Change the keyboard layout to current layout of system script.
+        //Shortcut.registerSystemCut("apple-reserved-50", "reserved", KeyEvent.VK_LEFT, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the previous semantic unit, typically the beginning of the current line.
+        //Shortcut.registerSystemCut("apple-reserved-51", "reserved", KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection one character to the left.
+        //Shortcut.registerSystemCut("apple-reserved-52", "reserved", KeyEvent.VK_LEFT, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current word, then to the beginning of the previous word.
+
+        Shortcut.registerSystemShortcut("system:movefocusleft", "reserved", KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
+
+        //Shortcut.registerSystemCut("apple-reserved-53", "reserved", KeyEvent.VK_UP, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection upward in the next semantic unit, typically the beginning of the document.
+        //Shortcut.registerSystemCut("apple-reserved-54", "reserved", KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line above, to the nearest character boundary at the same horizontal location.
+        //Shortcut.registerSystemCut("apple-reserved-55", "reserved", KeyEvent.VK_UP, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the beginning of the current paragraph, then to the beginning of the next paragraph.
+
+        Shortcut.registerSystemShortcut("system:movefocusup", "reserved", KeyEvent.VK_UP, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
+
+        //Shortcut.registerSystemCut("apple-reserved-56", "reserved", KeyEvent.VK_DOWN, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection downward in the next semantic unit, typically the end of the document.
+        //Shortcut.registerSystemCut("apple-reserved-57", "reserved", KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the line below, to the nearest character boundary at the same horizontal location.
+        //Shortcut.registerSystemCut("apple-reserved-58", "reserved", KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK).setAutomatic(); // Extend selection to the end of the current paragraph, then to the end of the next paragraph (include the blank line between paragraphs in cut, copy, and paste operations).
+
+        Shortcut.registerSystemShortcut("system:movefocusdown", "reserved", KeyEvent.VK_DOWN, KeyEvent.CTRL_DOWN_MASK); // Move focus to another value or cell within a view, such as a table. See Accessibility Overview.
+
+        Shortcut.registerSystemShortcut("system:about", "reserved", 0, -1).setAutomatic(); // About
+    }
+    public String makeTooltip(String name, Shortcut sc) {
+        String lafid = UIManager.getLookAndFeel().getID();
+        boolean canHtml = true;
+        // "Mac" is the native LAF, "Aqua" is Quaqua. Both use native menus with native tooltips.
+        if (lafid.contains("Mac") || lafid.contains("Aqua")) {
+            canHtml = false;
+        }
+        String result = "";
+        if (canHtml) result += "<html>";
+        result += name;
+        if (sc != null && sc.getKeyText().length() != 0) {
+            result += " ";
+            if (canHtml) result += "<font size='-2'>";
+            result += "("+sc.getKeyText()+")";
+            if (canHtml) result += "</font>";
+        }
+        if (canHtml) result += "&nbsp;</html>";
+        return result;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 1169)
@@ -15,64 +15,64 @@
   */
 public class PlatformHookUnixoid implements PlatformHook {
-	public void preStartupHook(){
-	}
-	public void startupHook() {
-	}
-	public void openUrl(String url) throws IOException {
-		String[] programs = {"gnome-open", "kfmclient openURL", "firefox"};
-		for (String program : programs) {
-			try {
-				Runtime.getRuntime().exec(program+" "+url);
-				return;
-			} catch (IOException e) {
-			}
-		}
-	}
-	public void initShortcutGroups() {
-		// This is the Windows list. Someone should look over it and make it more "*nix"...
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
+    public void preStartupHook(){
+    }
+    public void startupHook() {
+    }
+    public void openUrl(String url) throws IOException {
+        String[] programs = {"gnome-open", "kfmclient openURL", "firefox"};
+        for (String program : programs) {
+            try {
+                Runtime.getRuntime().exec(program+" "+url);
+                return;
+            } catch (IOException e) {
+            }
+        }
+    }
+    public void initShortcutGroups() {
+        // This is the Windows list. Someone should look over it and make it more "*nix"...
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
 
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
 
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-	}
-	public void initSystemShortcuts() {
-		// TODO: Insert system shortcuts here. See Windows and espacially OSX to see how to.
-	}
-	/**
-	  * This should work for all platforms. Yeah, should.
-	  * See PlatformHook.java for a list of reasons why
-	  * this is implemented here...
-	  */
-	public String makeTooltip(String name, Shortcut sc) {
-		String result = "";
-		result += "<html>";
-		result += name;
-		if (sc != null && sc.getKeyText().length() != 0) {
-			result += " ";
-			result += "<font size='-2'>";
-			result += "("+sc.getKeyText()+")";
-			result += "</font>";
-		}
-		result += "&nbsp;</html>";
-		return result;
-	}
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+    }
+    public void initSystemShortcuts() {
+        // TODO: Insert system shortcuts here. See Windows and espacially OSX to see how to.
+    }
+    /**
+      * This should work for all platforms. Yeah, should.
+      * See PlatformHook.java for a list of reasons why
+      * this is implemented here...
+      */
+    public String makeTooltip(String name, Shortcut sc) {
+        String result = "";
+        result += "<html>";
+        result += name;
+        if (sc != null && sc.getKeyText().length() != 0) {
+            result += " ";
+            result += "<font size='-2'>";
+            result += "("+sc.getKeyText()+")";
+            result += "</font>";
+        }
+        result += "&nbsp;</html>";
+        return result;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 1169)
@@ -14,46 +14,46 @@
   */
 public class PlatformHookWindows extends PlatformHookUnixoid implements PlatformHook {
-	public void preStartupHook(){
-	}
-	public void startupHook() {
-	}
-	public void openUrl(String url) throws IOException {
-		Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
-	}
-	public void initShortcutGroups() {
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
+    public void preStartupHook(){
+    }
+    public void startupHook() {
+    }
+    public void openUrl(String url) throws IOException {
+        Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
+    }
+    public void initShortcutGroups() {
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_NONE),    Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_HOTKEY),  Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MENU),    Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_EDIT),    Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_LAYER),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_DIRECT),  Integer.toString(0));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_DEFAULT+Shortcut.GROUP_MNEMONIC),Integer.toString(KeyEvent.ALT_DOWN_MASK));
 
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT1+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
 
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.CTRL_DOWN_MASK));
-		Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
-	}
-	public void initSystemShortcuts() {
-		// This list if far from complete!
-		Shortcut.registerSystemShortcut("system:exit", "unused", KeyEvent.VK_F4, KeyEvent.ALT_DOWN_MASK).setAutomatic(); // items with automatic shortcuts will not be added to the menu bar at all
-		Shortcut.registerSystemShortcut("system:menuexit", "unused", KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK);
-		Shortcut.registerSystemShortcut("system:copy", "unused", KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK);
-		Shortcut.registerSystemShortcut("system:paste", "unused", KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
-		Shortcut.registerSystemShortcut("system:cut", "unused", KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK);
-		Shortcut.registerSystemShortcut("system:duplicate", "unused", KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK); // not really system, but to avoid odd results
-		Shortcut.registerSystemShortcut("system:help", "unused", KeyEvent.VK_F1, 0);
-	}
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_NONE),       Integer.toString(-1));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_HOTKEY),     Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MENU),       Integer.toString(KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_EDIT),       Integer.toString(KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_LAYER),      Integer.toString(KeyEvent.ALT_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_DIRECT),     Integer.toString(KeyEvent.CTRL_DOWN_MASK));
+        Main.pref.put("shortcut.groups."+(Shortcut.GROUPS_ALT2+Shortcut.GROUP_MNEMONIC),   Integer.toString(KeyEvent.ALT_DOWN_MASK));
+    }
+    public void initSystemShortcuts() {
+        // This list if far from complete!
+        Shortcut.registerSystemShortcut("system:exit", "unused", KeyEvent.VK_F4, KeyEvent.ALT_DOWN_MASK).setAutomatic(); // items with automatic shortcuts will not be added to the menu bar at all
+        Shortcut.registerSystemShortcut("system:menuexit", "unused", KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK);
+        Shortcut.registerSystemShortcut("system:copy", "unused", KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK);
+        Shortcut.registerSystemShortcut("system:paste", "unused", KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
+        Shortcut.registerSystemShortcut("system:cut", "unused", KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK);
+        Shortcut.registerSystemShortcut("system:duplicate", "unused", KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK); // not really system, but to avoid odd results
+        Shortcut.registerSystemShortcut("system:help", "unused", KeyEvent.VK_F1, 0);
+    }
 }
 
Index: trunk/src/org/openstreetmap/josm/tools/PrimaryDateParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/PrimaryDateParser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/PrimaryDateParser.java	(revision 1169)
@@ -15,255 +15,255 @@
  * based on similar code in JOSM. This class is not threadsafe, a separate
  * instance must be created per thread.
- * 
+ *
  * @author Brett Henderson
  */
 public class PrimaryDateParser {
-	private DatatypeFactory datatypeFactory;
-	private FallbackDateParser fallbackDateParser;
-	private Calendar calendar;
-	
-	
-	/**
-	 * Creates a new instance.
-	 */
-	public PrimaryDateParser() {
-		// Build an xml data type factory.
-		try {
-			datatypeFactory = DatatypeFactory.newInstance();
-			
-		} catch (DatatypeConfigurationException e) {
-			throw new RuntimeException("Unable to instantiate xml datatype factory.", e);
-		}
-		
-		fallbackDateParser = new FallbackDateParser();
-		
-		calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
-	}
-	
-	
-	private boolean isDateInShortStandardFormat(String date) {
-		char[] dateChars;
-		// We can only parse the date if it is in a very specific format.
-		// eg. 2007-09-23T08:25:43Z
-		
-		if (date.length() != 20) {
-			return false;
-		}
-		
-		dateChars = date.toCharArray();
-		
-		// Make sure any fixed characters are in the correct place.
-		if (dateChars[4] != '-') {
-			return false;
-		}
-		if (dateChars[7] != '-') {
-			return false;
-		}
-		if (dateChars[10] != 'T') {
-			return false;
-		}
-		if (dateChars[13] != ':') {
-			return false;
-		}
-		if (dateChars[16] != ':') {
-			return false;
-		}
-		if (dateChars[19] != 'Z') {
-			return false;
-		}
-		
-		// Ensure all remaining characters are numbers.
-		for (int i = 0; i < 4; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 5; i < 7; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 8; i < 10; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 11; i < 13; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 14; i < 16; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 17; i < 19; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		
-		// No problems found so it is in the special case format.
-		return true;
-	}
-	
-	
-	private boolean isDateInLongStandardFormat(String date) {
-		char[] dateChars;
-		// We can only parse the date if it is in a very specific format.
-		// eg. 2007-09-23T08:25:43.000Z
-		
-		if (date.length() != 24) {
-			return false;
-		}
-		
-		dateChars = date.toCharArray();
-		
-		// Make sure any fixed characters are in the correct place.
-		if (dateChars[4] != '-') {
-			return false;
-		}
-		if (dateChars[7] != '-') {
-			return false;
-		}
-		if (dateChars[10] != 'T') {
-			return false;
-		}
-		if (dateChars[13] != ':') {
-			return false;
-		}
-		if (dateChars[16] != ':') {
-			return false;
-		}
-		if (dateChars[19] != '.') {
-			return false;
-		}
-		if (dateChars[23] != 'Z') {
-			return false;
-		}
-		
-		// Ensure all remaining characters are numbers.
-		for (int i = 0; i < 4; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 5; i < 7; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 8; i < 10; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 11; i < 13; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 14; i < 16; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 17; i < 19; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		for (int i = 20; i < 23; i++) {
-			if (dateChars[i] < '0' || dateChars[i] > '9') {
-				return false;
-			}
-		}
-		
-		// No problems found so it is in the special case format.
-		return true;
-	}
-	
-	
-	private Date parseShortStandardDate(String date) {
-		int year;
-		int month;
-		int day;
-		int hour;
-		int minute;
-		int second;
-		
-		year = Integer.parseInt(date.substring(0, 4));
-		month = Integer.parseInt(date.substring(5, 7));
-		day = Integer.parseInt(date.substring(8, 10));
-		hour = Integer.parseInt(date.substring(11, 13));
-		minute = Integer.parseInt(date.substring(14, 16));
-		second = Integer.parseInt(date.substring(17, 19));
-		
-		calendar.clear();
-		calendar.set(Calendar.YEAR, year);
-		calendar.set(Calendar.MONTH, month - 1);
-		calendar.set(Calendar.DAY_OF_MONTH, day);
-		calendar.set(Calendar.HOUR_OF_DAY, hour);
-		calendar.set(Calendar.MINUTE, minute);
-		calendar.set(Calendar.SECOND, second);
-		
-		return calendar.getTime();
-	}
-	
-	
-	private Date parseLongStandardDate(String date) {
-		int year;
-		int month;
-		int day;
-		int hour;
-		int minute;
-		int second;
-		int millisecond;
-		
-		year = Integer.parseInt(date.substring(0, 4));
-		month = Integer.parseInt(date.substring(5, 7));
-		day = Integer.parseInt(date.substring(8, 10));
-		hour = Integer.parseInt(date.substring(11, 13));
-		minute = Integer.parseInt(date.substring(14, 16));
-		second = Integer.parseInt(date.substring(17, 19));
-		millisecond = Integer.parseInt(date.substring(20, 23));
-		
-		calendar.clear();
-		calendar.set(Calendar.YEAR, year);
-		calendar.set(Calendar.MONTH, month - 1);
-		calendar.set(Calendar.DAY_OF_MONTH, day);
-		calendar.set(Calendar.HOUR_OF_DAY, hour);
-		calendar.set(Calendar.MINUTE, minute);
-		calendar.set(Calendar.SECOND, second);
-		calendar.set(Calendar.MILLISECOND, millisecond);
-		
-		return calendar.getTime();
-	}
-	
-	
-	/**
-	 * Attempts to parse the specified date.
-	 * 
-	 * @param date
-	 *            The date to parse.
-	 * @return The date.
-	 * @throws ParseException
-	 *             Occurs if the date does not match any of the supported date
-	 *             formats.
-	 */
-	public Date parse(String date) throws ParseException {
-		try {
-			if (isDateInShortStandardFormat(date)) {
-				return parseShortStandardDate(date);
-			} else if (isDateInLongStandardFormat(date)) {
-				return parseLongStandardDate(date);
-			} else {
-				return datatypeFactory.newXMLGregorianCalendar(date).toGregorianCalendar().getTime();
-			}
-			
-		} catch (IllegalArgumentException e) {
-			return fallbackDateParser.parse(date);
-		}
-	}
+    private DatatypeFactory datatypeFactory;
+    private FallbackDateParser fallbackDateParser;
+    private Calendar calendar;
+
+
+    /**
+     * Creates a new instance.
+     */
+    public PrimaryDateParser() {
+        // Build an xml data type factory.
+        try {
+            datatypeFactory = DatatypeFactory.newInstance();
+
+        } catch (DatatypeConfigurationException e) {
+            throw new RuntimeException("Unable to instantiate xml datatype factory.", e);
+        }
+
+        fallbackDateParser = new FallbackDateParser();
+
+        calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    }
+
+
+    private boolean isDateInShortStandardFormat(String date) {
+        char[] dateChars;
+        // We can only parse the date if it is in a very specific format.
+        // eg. 2007-09-23T08:25:43Z
+
+        if (date.length() != 20) {
+            return false;
+        }
+
+        dateChars = date.toCharArray();
+
+        // Make sure any fixed characters are in the correct place.
+        if (dateChars[4] != '-') {
+            return false;
+        }
+        if (dateChars[7] != '-') {
+            return false;
+        }
+        if (dateChars[10] != 'T') {
+            return false;
+        }
+        if (dateChars[13] != ':') {
+            return false;
+        }
+        if (dateChars[16] != ':') {
+            return false;
+        }
+        if (dateChars[19] != 'Z') {
+            return false;
+        }
+
+        // Ensure all remaining characters are numbers.
+        for (int i = 0; i < 4; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 5; i < 7; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 8; i < 10; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 11; i < 13; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 14; i < 16; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 17; i < 19; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+
+        // No problems found so it is in the special case format.
+        return true;
+    }
+
+
+    private boolean isDateInLongStandardFormat(String date) {
+        char[] dateChars;
+        // We can only parse the date if it is in a very specific format.
+        // eg. 2007-09-23T08:25:43.000Z
+
+        if (date.length() != 24) {
+            return false;
+        }
+
+        dateChars = date.toCharArray();
+
+        // Make sure any fixed characters are in the correct place.
+        if (dateChars[4] != '-') {
+            return false;
+        }
+        if (dateChars[7] != '-') {
+            return false;
+        }
+        if (dateChars[10] != 'T') {
+            return false;
+        }
+        if (dateChars[13] != ':') {
+            return false;
+        }
+        if (dateChars[16] != ':') {
+            return false;
+        }
+        if (dateChars[19] != '.') {
+            return false;
+        }
+        if (dateChars[23] != 'Z') {
+            return false;
+        }
+
+        // Ensure all remaining characters are numbers.
+        for (int i = 0; i < 4; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 5; i < 7; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 8; i < 10; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 11; i < 13; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 14; i < 16; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 17; i < 19; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+        for (int i = 20; i < 23; i++) {
+            if (dateChars[i] < '0' || dateChars[i] > '9') {
+                return false;
+            }
+        }
+
+        // No problems found so it is in the special case format.
+        return true;
+    }
+
+
+    private Date parseShortStandardDate(String date) {
+        int year;
+        int month;
+        int day;
+        int hour;
+        int minute;
+        int second;
+
+        year = Integer.parseInt(date.substring(0, 4));
+        month = Integer.parseInt(date.substring(5, 7));
+        day = Integer.parseInt(date.substring(8, 10));
+        hour = Integer.parseInt(date.substring(11, 13));
+        minute = Integer.parseInt(date.substring(14, 16));
+        second = Integer.parseInt(date.substring(17, 19));
+
+        calendar.clear();
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month - 1);
+        calendar.set(Calendar.DAY_OF_MONTH, day);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, second);
+
+        return calendar.getTime();
+    }
+
+
+    private Date parseLongStandardDate(String date) {
+        int year;
+        int month;
+        int day;
+        int hour;
+        int minute;
+        int second;
+        int millisecond;
+
+        year = Integer.parseInt(date.substring(0, 4));
+        month = Integer.parseInt(date.substring(5, 7));
+        day = Integer.parseInt(date.substring(8, 10));
+        hour = Integer.parseInt(date.substring(11, 13));
+        minute = Integer.parseInt(date.substring(14, 16));
+        second = Integer.parseInt(date.substring(17, 19));
+        millisecond = Integer.parseInt(date.substring(20, 23));
+
+        calendar.clear();
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month - 1);
+        calendar.set(Calendar.DAY_OF_MONTH, day);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, second);
+        calendar.set(Calendar.MILLISECOND, millisecond);
+
+        return calendar.getTime();
+    }
+
+
+    /**
+     * Attempts to parse the specified date.
+     *
+     * @param date
+     *            The date to parse.
+     * @return The date.
+     * @throws ParseException
+     *             Occurs if the date does not match any of the supported date
+     *             formats.
+     */
+    public Date parse(String date) throws ParseException {
+        try {
+            if (isDateInShortStandardFormat(date)) {
+                return parseShortStandardDate(date);
+            } else if (isDateInLongStandardFormat(date)) {
+                return parseLongStandardDate(date);
+            } else {
+                return datatypeFactory.newXMLGregorianCalendar(date).toGregorianCalendar().getTime();
+            }
+
+        } catch (IllegalArgumentException e) {
+            return fallbackDateParser.parse(date);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/Shortcut.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Shortcut.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/Shortcut.java	(revision 1169)
@@ -139,6 +139,6 @@
      */
     public KeyStroke getKeyStroke() {
-        if (assignedModifier != -1) 
-            return KeyStroke.getKeyStroke(assignedKey, assignedModifier);		
+        if (assignedModifier != -1)
+            return KeyStroke.getKeyStroke(assignedKey, assignedModifier);
         return null;
     }
@@ -351,5 +351,5 @@
             System.err.println("CONFLICT WITH SYSTEM KEY "+shortText);
             return null;
-        } 
+        }
         potentialShortcut = new Shortcut(shortText, longText, key, GROUP_RESERVED, key, modifier, true, false);
         shortcuts.put(shortText, potentialShortcut);
@@ -441,5 +441,5 @@
     // a lengthy warning message
     private static void displayWarning(Shortcut conflictsWith, Shortcut potentialShortcut, String shortText, String longText) {
-        JOptionPane.showMessageDialog(Main.parent, 
+        JOptionPane.showMessageDialog(Main.parent,
                 tr("Setting the keyboard shortcut ''{0}'' for the action ''{1}'' ({2}) failed\n"+
                         "because the shortcut is already taken by the action ''{3}'' ({4}).\n\n",
Index: trunk/src/org/openstreetmap/josm/tools/UrlLabel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/UrlLabel.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/UrlLabel.java	(revision 1169)
@@ -12,24 +12,24 @@
 public class UrlLabel extends JEditorPane implements HyperlinkListener {
 
-	private final String url;
+    private final String url;
 
-	public UrlLabel(String url) {
-		this (url, url);
-	}
+    public UrlLabel(String url) {
+        this (url, url);
+    }
 
-	public UrlLabel(String url, String description) {
-		this.url = url;
-		setContentType("text/html");
-		setText("<html><a href=\""+url+"\">"+description+"</a></html>");
-		setToolTipText(url);
-		setEditable(false);
-		setOpaque(false);
-		addHyperlinkListener(this);
-	}
+    public UrlLabel(String url, String description) {
+        this.url = url;
+        setContentType("text/html");
+        setText("<html><a href=\""+url+"\">"+description+"</a></html>");
+        setToolTipText(url);
+        setEditable(false);
+        setOpaque(false);
+        addHyperlinkListener(this);
+    }
 
-	public void hyperlinkUpdate(HyperlinkEvent e) {
-		if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
-			OpenBrowser.displayUrl(url);
-		}
-	}
+    public void hyperlinkUpdate(HyperlinkEvent e) {
+        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+            OpenBrowser.displayUrl(url);
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/WikiReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/WikiReader.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/WikiReader.java	(revision 1169)
@@ -14,54 +14,54 @@
 public class WikiReader {
 
-	public static final String JOSM_EXTERN = "http://josm-extern.";
-	private final String baseurl;
+    public static final String JOSM_EXTERN = "http://josm-extern.";
+    private final String baseurl;
 
-	public WikiReader(String baseurl) {
-		this.baseurl = baseurl;
+    public WikiReader(String baseurl) {
+        this.baseurl = baseurl;
     }
 
-	/**
-	 * Read the page specified by the url and return the content.
-	 *
-	 * If the url is within the baseurl path, parse it as an trac wikipage and
-	 * replace relative pathes etc..
-	 *
-	 * @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) throws IOException {
+    /**
+     * Read the page specified by the url and return the content.
+     *
+     * If the url is within the baseurl path, parse it as an trac wikipage and
+     * replace relative pathes etc..
+     *
+     * @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) throws IOException {
         BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream(), "utf-8"));
         if (url.startsWith(baseurl))
-        	return readFromTrac(in, url);
+            return readFromTrac(in, url);
         return readNormal(in);
-	}
-
-	private String readNormal(BufferedReader in) throws IOException {
-		StringBuilder b = new StringBuilder("<html>");
-		for (String line = in.readLine(); line != null; line = in.readLine()) {
-			line = adjustText(line);
-			b.append(line);
-			b.append("\n");
-		}
-		return b.toString();
     }
 
-	private String readFromTrac(BufferedReader in, String url) throws IOException {
+    private String readNormal(BufferedReader in) throws IOException {
+        StringBuilder b = new StringBuilder("<html>");
+        for (String line = in.readLine(); line != null; line = in.readLine()) {
+            line = adjustText(line);
+            b.append(line);
+            b.append("\n");
+        }
+        return b.toString();
+    }
+
+    private String readFromTrac(BufferedReader in, String url) throws IOException {
         boolean inside = false;
         StringBuilder b = new StringBuilder("<html>");
         for (String line = in.readLine(); line != null; line = in.readLine()) {
-        	if (line.contains("<div id=\"searchable\">"))
-        		inside = true;
-        	else if (line.contains("<div class=\"buttons\">"))
-        		inside = false;
-        	if (inside) {
-        		line = line.replaceAll("<img src=\"/", "<img src=\""+baseurl+"/");
-        		line = line.replaceAll("href=\"/", "href=\""+baseurl+"/");
-        		if (!line.contains("$"))
-        			line = line.replaceAll("<p>Describe \"([^\"]+)\" here</p>", "<p>Describe \"$1\" <a href=\""+JOSM_EXTERN+url.substring(7)+"\">here</a></p>");
-        		line = adjustText(line);
-        		b.append(line);
-        		b.append("\n");
-        	}
+            if (line.contains("<div id=\"searchable\">"))
+                inside = true;
+            else if (line.contains("<div class=\"buttons\">"))
+                inside = false;
+            if (inside) {
+                line = line.replaceAll("<img src=\"/", "<img src=\""+baseurl+"/");
+                line = line.replaceAll("href=\"/", "href=\""+baseurl+"/");
+                if (!line.contains("$"))
+                    line = line.replaceAll("<p>Describe \"([^\"]+)\" here</p>", "<p>Describe \"$1\" <a href=\""+JOSM_EXTERN+url.substring(7)+"\">here</a></p>");
+                line = adjustText(line);
+                b.append(line);
+                b.append("\n");
+            }
         }
         b.append("</html>");
@@ -69,7 +69,7 @@
     }
 
-	private String adjustText(String text) {
-	    text = text.replaceAll(" />", ">");
-	    return text;
+    private String adjustText(String text) {
+        text = text.replaceAll(" />", ">");
+        return text;
     }
 }
Index: trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 1168)
+++ trunk/src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 1169)
@@ -31,258 +31,258 @@
 
         public static final String lang = Main.getLanguageCode();
-	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 DefaultHandler {
-		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();
-				if (mapping.get(qname).both)
-				{
-					try {
-						queue.put(current.peek());
-					} catch (InterruptedException e) {
-					}
-				}
-			}
-		}
-		@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.trim());
-				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(fieldName.startsWith(lang))
-					{
-						String locfieldName = "locale_" +
-						fieldName.substring(lang.length());
-						try {
-							f = c.getClass().getField(locfieldName);
-						} catch (NoSuchFieldException ex) {
-						}
-					}
-				}
-				if (f != null && Modifier.isPublic(f.getModifiers()))
-					f.set(c, getValueForClass(f.getType(), value));
-				else {
-					if(fieldName.startsWith(lang))
-					{
-						int l = lang.length();
-						fieldName = "set" + fieldName.substring(l,l+1).toUpperCase() + fieldName.substring(l+1);
-					}
-					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) {
-				e.printStackTrace(); // SAXException does not dump inner exceptions.
-				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;
-		boolean both;
-		public Entry(Class<?> klass, boolean onStart, boolean both) {
-			super();
-			this.klass = klass;
-			this.onStart = onStart;
-			this.both = both;
-		}
-	}
-
-	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 {
-			        SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(in), parser);
-				} 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,false));
-	}
-
-	public void mapOnStart(String tagName, Class<?> klass) {
-		mapping.put(tagName, new Entry(klass,true,false));
-	}
-
-	public void mapBoth(String tagName, Class<?> klass) {
-		mapping.put(tagName, new Entry(klass,false,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();
+    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 DefaultHandler {
+        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();
+                if (mapping.get(qname).both)
+                {
+                    try {
+                        queue.put(current.peek());
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+        @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.trim());
+                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(fieldName.startsWith(lang))
+                    {
+                        String locfieldName = "locale_" +
+                        fieldName.substring(lang.length());
+                        try {
+                            f = c.getClass().getField(locfieldName);
+                        } catch (NoSuchFieldException ex) {
+                        }
+                    }
+                }
+                if (f != null && Modifier.isPublic(f.getModifiers()))
+                    f.set(c, getValueForClass(f.getType(), value));
+                else {
+                    if(fieldName.startsWith(lang))
+                    {
+                        int l = lang.length();
+                        fieldName = "set" + fieldName.substring(l,l+1).toUpperCase() + fieldName.substring(l+1);
+                    }
+                    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) {
+                e.printStackTrace(); // SAXException does not dump inner exceptions.
+                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;
+        boolean both;
+        public Entry(Class<?> klass, boolean onStart, boolean both) {
+            super();
+            this.klass = klass;
+            this.onStart = onStart;
+            this.both = both;
+        }
+    }
+
+    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 {
+                    SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(in), parser);
+                } 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,false));
+    }
+
+    public void mapOnStart(String tagName, Class<?> klass) {
+        mapping.put(tagName, new Entry(klass,true,false));
+    }
+
+    public void mapBoth(String tagName, Class<?> klass) {
+        mapping.put(tagName, new Entry(klass,false,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) {
-					e.printStackTrace();
-					throw new RuntimeException(e);
-				}
-			}
-			public Object next() {
-				try {
-					return XmlObjectParser.this.next();
-				} catch (SAXException e) {
-					e.printStackTrace();
-					throw new RuntimeException(e);
-				}
-			}
-			public void remove() {
-				throw new UnsupportedOperationException();
-			}
-		};
-	}
+    }
+
+    public Iterator<Object> iterator() {
+        return new Iterator<Object>(){
+            public boolean hasNext() {
+                try {
+                    return XmlObjectParser.this.hasNext();
+                } catch (SAXException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e);
+                }
+            }
+            public Object next() {
+                try {
+                    return XmlObjectParser.this.next();
+                } catch (SAXException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e);
+                }
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
 }
