Index: src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AboutAction.java	(revision 291)
+++ src/org/openstreetmap/josm/actions/AboutAction.java	(revision 292)
@@ -23,5 +23,4 @@
 import javax.swing.JTabbedPane;
 import javax.swing.JTextArea;
-import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
@@ -70,35 +69,14 @@
 
 		JPanel info = new JPanel(new GridBagLayout());
-		info.add(new JLabel(tr("Java OpenStreetMap Editor Version {0}",version)), GBC.eol());
-		info.add(new JLabel(tr("last change at {0}",time)), GBC.eol());
-		info.add(new JLabel(tr("Java Version {0}",System.getProperty("java.version"))), GBC.eol());
-		info.add(new JLabel(tr("Latest Version on JOSM homepage is")), GBC.std().insets(0,0,5,0));
-		final JLabel checkVersionLabel = new JLabel("<html><em>"+tr("checking...")+"</em></html>");
-		info.add(checkVersionLabel, GBC.eol());
-		new Thread(){
-			@Override public void run() {
-				final String version = checkLatestVersion();
-				try {
-					if (version == null)
-						throw new NullPointerException();
-	                SwingUtilities.invokeAndWait(new Runnable(){
-	                	public void run() {
-	                		checkVersionLabel.setText(version);
-	                    }
-	                });
-                } catch (Exception e) {
-	                checkVersionLabel.setText("failed.");
-                }
-            }
-		}.start();
-		
+		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());
+		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());
+		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());
+		info.add(new UrlLabel("http://www.opengeodata.org/?cat=17"), GBC.eol().fill(GBC.HORIZONTAL));
 
 		StringBuilder pluginsStr = new StringBuilder();
Index: src/org/openstreetmap/josm/actions/AutoScaleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 291)
+++ src/org/openstreetmap/josm/actions/AutoScaleAction.java	(revision 292)
@@ -29,5 +29,5 @@
 
 	public AutoScaleAction(String mode) {
-		super(tr(mode), "dialogs/autoscale/"+mode, tr("Zoom the view to {0}."), 0, 0, true);
+		super(tr("Zoom to {0}", mode), "dialogs/autoscale/"+mode, tr("Zoom the view to {0}.", tr(mode)), 0, 0, true);
 		String modeHelp = Character.toUpperCase(mode.charAt(0))+mode.substring(1);
 		putValue("help", "Action/AutoScale/"+modeHelp);
Index: src/org/openstreetmap/josm/actions/ExitAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ExitAction.java	(revision 291)
+++ src/org/openstreetmap/josm/actions/ExitAction.java	(revision 292)
@@ -5,4 +5,6 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.Main;
 
 /**
@@ -18,7 +20,8 @@
 		super(tr("Exit"), "exit", tr("Exit the application."), KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK, true);
 	}
-	
+
 	public void actionPerformed(ActionEvent e) {
-		System.exit(0);
+		if (!Main.breakBecauseUnsavedChanges())
+			System.exit(0);
 	}
 }
Index: src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/JosmAction.java	(revision 291)
+++ src/org/openstreetmap/josm/actions/JosmAction.java	(revision 292)
@@ -27,8 +27,11 @@
 		super(name, ImageProvider.get(iconName));
 		setHelpId();
-		putValue(SHORT_DESCRIPTION, "<html>"+tooltip+" <font size='-2'>"+ShortCutLabel.name(shortCut, modifier)+"</font>&nbsp;</html>");
-		this.shortCut = KeyStroke.getKeyStroke(shortCut, modifier);
-        Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(this.shortCut, name);
-        Main.contentPane.getActionMap().put(name, this);
+		String scl = ShortCutLabel.name(shortCut, modifier);
+		putValue(SHORT_DESCRIPTION, "<html>"+tooltip+" <font size='-2'>"+scl+"</font>"+(scl.equals("")?"":"&nbsp;")+"</html>");
+		if (shortCut != 0) {
+			this.shortCut = KeyStroke.getKeyStroke(shortCut, modifier);
+			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(this.shortCut, name);
+			Main.contentPane.getActionMap().put(name, this);
+		}
         putValue("toolbar", iconName);
         if (register)
@@ -37,6 +40,8 @@
 
 	public void destroy() {
-		Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortCut);
-		Main.contentPane.getActionMap().remove(shortCut);
+		if (shortCut != null) {
+			Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(shortCut);
+			Main.contentPane.getActionMap().remove(shortCut);
+		}
 	}
 	
Index: src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 291)
+++ src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java	(revision 292)
@@ -44,5 +44,5 @@
 	 */
 	public ZoomAction(MapFrame mapFrame) {
-		super(tr("Zoom"), "zoom", tr("Zoom in by dragging. (Ctrl+up,left,down,right,+,-)"), KeyEvent.VK_Z, mapFrame, ImageProvider.getCursor("normal", "zoom"));
+		super(tr("Zoom"), "zoom", tr("Zoom in by dragging. (Ctrl+up,left,down,right,',','.')"), KeyEvent.VK_Z, mapFrame, ImageProvider.getCursor("normal", "zoom"));
 		mv = mapFrame.mapView;
 		selectionManager = new SelectionManager(this, true, mv);
Index: src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 291)
+++ src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 292)
@@ -196,6 +196,6 @@
 				double size = 180.0 / Math.pow(2, Integer.parseInt(map.get("zoom")));
 				b = new Bounds(
-	            	new LatLon(Double.parseDouble(map.get("mlat")) - size/2, Double.parseDouble(map.get("mlon")) - size),
-	            	new LatLon(Double.parseDouble(map.get("mlat")) + size/2, Double.parseDouble(map.get("mlon")) + size));
+	            	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) {
@@ -204,3 +204,9 @@
 		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: src/org/openstreetmap/josm/plugins/Plugin.java
===================================================================
--- src/org/openstreetmap/josm/plugins/Plugin.java	(revision 291)
+++ src/org/openstreetmap/josm/plugins/Plugin.java	(revision 292)
@@ -6,6 +6,4 @@
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
-import java.net.URLClassLoader;
 import java.util.List;
 
@@ -17,22 +15,23 @@
 /**
  * All plugins *must* have an standard constructor taking no arguments.
+ *
  * This constructor is called at JOSM startup, after all Main-objects have been initialized.
  * For all purposes of loading dynamic resources, the Plugin's class loader should be used
  * (or else, the plugin jar will not be within the class path).
  *
- * All plugins should have at least one class subclassing this abstract base class.
+ * A plugin may subclass this abstract base class (but it is optional).
  *
- * The actual implementation of this interface is optional, as all functions will be called
- * 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 be called. That simple.
+ * 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 
+ * 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
+ * be called. That simple.
  *
- * Or in other words: See this base class as an documentation of what functions are provided.
- * Subclassing it and overriding some functions makes it easy for you to keep sync with the
- * correct actual plugin architecture of JOSM.
- *
- *
- * The pluginname provided to the constructor is also the name of the directory to
- * store the plugin's own stuff (located under the josm preferences directory)
+ * Or in other words: See this base class as an documentation of what automatic callbacks
+ * 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.
  *
  * @author Immanuel.Scholz
@@ -40,35 +39,19 @@
 public abstract class Plugin {
 
-	String name;
-
-	public Plugin() {
-		try {
-	        URL[] urls = ((URLClassLoader)getClass().getClassLoader()).getURLs();
-	        name = urls[urls.length-1].toString();
-	        if (name.toLowerCase().endsWith(".jar")) {
-	        	int lastSlash = name.lastIndexOf('/');
-	        	name = name.substring(lastSlash+1, name.length()-4);
-	        }
-        } catch (RuntimeException e) {
-        	name = "unknown";
-        }
-    }
+	/**
+	 * 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 name of this plugin. This is the name of the .jar file.
-	 * @deprecated Plugins have to know their name by themself.
+	 * @return The directory for the plugin to store all kind of stuff.
 	 */
-	@Deprecated public final String getName() {
-		return name;
+	public final String getPluginDir() {
+		return Main.pref.getPreferencesDir()+"plugins/"+info.name+"/";
 	}
-	/**
-	 * @return The directory for the plugin to store all kind of stuff.
-	 * @deprecated Use <code>Main.pref.getPreferencesDir()+"plugins/"+name+"/";</code> instead.
-	 */
-	@Deprecated public final String getPluginDir() {
-		return Main.pref.getPreferencesDir()+"plugins/"+name+"/";
-	}
-
-
 
 	/**
@@ -92,25 +75,18 @@
 	
 	/**
-	 * @deprecated Use copy(String pluginName, String from, String to) instead
-	 */
-	@Deprecated public void copy(String from, String to) throws FileNotFoundException, IOException {
-		copy(name, from, to);
-    }
-
-	/**
 	 * Copies the ressource 'from' to the file in the plugin directory named 'to'.
 	 */
-	public void copy(String pluginName, String from, String to) throws FileNotFoundException, IOException {
-	    String pluginDirName = Main.pref.getPreferencesDir()+"plugins/"+pluginName+"/";
-		File pluginDir = new File(pluginDirName);
-		if (!pluginDir.exists())
-			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);
-    	in.close();
-    	out.close();
+	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();
+        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);
+        in.close();
+        out.close();
     }
 }
Index: src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 291)
+++ src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 292)
@@ -36,4 +36,13 @@
 
 	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;
 
 	/**
@@ -102,4 +111,5 @@
 	public PluginProxy load(Class<?> klass) {
 		try {
+			currentPluginInitialization = this;
 			return new PluginProxy(klass.newInstance(), this);
 		} catch (Exception e) {
Index: src/org/openstreetmap/josm/plugins/PluginProxy.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 291)
+++ src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 292)
@@ -19,20 +19,8 @@
 	public final Object plugin;
 	public final PluginInformation info;
-	public boolean misbehaving = false;
 
 	public PluginProxy(Object plugin, PluginInformation info) {
 		this.plugin = plugin;
 		this.info = info;
-
-		// setting name of the plugin by reflection
-		if (plugin instanceof Plugin) {
-			try {
-		        Plugin.class.getDeclaredField("name").set(plugin, info.name);
-	        } catch (Exception e) {
-	        	if (e instanceof RuntimeException)
-	        		throw (RuntimeException)e;
-	        	throw new RuntimeException(e);
-	        }
-		}
     }
 
Index: src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java
===================================================================
--- src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java	(revision 291)
+++ src/org/openstreetmap/josm/tools/BugReportExceptionHandler.java	(revision 292)
@@ -4,4 +4,9 @@
 
 import java.awt.GridBagLayout;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
 import java.io.BufferedReader;
 import java.io.File;
@@ -37,50 +42,41 @@
 		if (Main.parent != null) {
 			if (e instanceof OutOfMemoryError) {
+				// do not translate the string, as translation may raise an exception
 				JOptionPane.showMessageDialog(Main.parent, "You are out of memory. Strange things may happen.\nPlease restart JOSM and load smaller data sets.");
 				return;
 			}
 
+			PluginProxy plugin = null;
+
 			// Check for an explicit problem when calling a plugin function
-			if (e instanceof PluginException) {
-				PluginProxy plugin = ((PluginException)e).plugin;
-				if (plugin != null && !plugin.misbehaving) {
-					JOptionPane.showMessageDialog(Main.parent, tr("The plugin {0} threw an exception: {1}\nIt may be outdated. Please contact the plugin's author.\nThis message will not shown again until JOSM is restarted.", plugin.info.name, e.getMessage()));
-					plugin.misbehaving = true;
+			if (e instanceof PluginException)
+				plugin = ((PluginException)e).plugin;
+			
+			if (plugin == null)
+				plugin = guessPlugin(e);
+
+			if (plugin != null) {
+				int answer = JOptionPane.showConfirmDialog(
+						Main.parent, 
+						tr("An unexpected exception occurred, that may come from in 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("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;
-				}
-			}
-
-			// Try a heuristic to guess whether the problem may be within a plugin
-			String pluginName = guessPlugin(e);
-			if (pluginName != null) {
-				boolean loaded = false;
-				for (PluginProxy p : Main.plugins)
-					if (p.info.name.equals(pluginName))
-						loaded = true;
-				if (loaded) {
-					String author = findPluginAuthor(pluginName);
-					int answer = JOptionPane.showConfirmDialog(
-							Main.parent, 
-							tr("An unexpected exception occurred, that may come from in the ''{0}'' plugin.", pluginName)+"\n"+
-								(author != null ? tr("According to the information within the plugin, the author is {0}.", author) : "")+"\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(pluginName)) {
-							while (plugins.remove(pluginName)) {}
-							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;
-					}
 				}
 			}
@@ -98,5 +94,5 @@
 
 					URL revUrl = Main.class.getResource("/REVISION");
-					StringBuilder sb = new StringBuilder(tr("Please send this to josm@eigenheimstrasse.de\n\n"));
+					StringBuilder sb = new StringBuilder();
 					if (revUrl == null) {
 						sb.append("Development version. Unknown revision.");
@@ -121,5 +117,12 @@
 
 					JPanel p = new JPanel(new GridBagLayout());
-					p.add(new JLabel(tr("Please send an email with the following information to josm@eigenheimstrasse.de")), GBC.eop());
+					p.add(new JLabel(tr("Please send an email with the following information to josm@eigenheimstrasse.de")), 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);
@@ -136,12 +139,9 @@
 	}
 
-	/**
-	 * Try to find the author of the given plugin. Return <code>null</code>
-	 * if no author specified or the plugin is not found.
-	 */
-	private String findPluginAuthor(String pluginName) {
-		for (PluginProxy proxy : Main.plugins)
-			if (pluginName.equals(proxy.info.name))
-				return proxy.info.author;
+	private PluginProxy guessPlugin(Throwable e) {
+		String name = guessPluginName(e);
+		for (PluginProxy p : Main.plugins)
+			if (p.info.name.equals(name))
+				return p;
 		return null;
 	}
@@ -158,7 +158,8 @@
 	 * bug reports ;-). 
 	 */
-	private String guessPlugin(Throwable e) {
+	private String guessPluginName(Throwable e) {
 		for (StackTraceElement element : e.getStackTrace()) {
 			String c = element.getClassName();
+			
 			if (c.contains("wmsplugin.") || c.contains(".WMSLayer"))
 				return "wmsplugin";
@@ -171,4 +172,13 @@
 			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;
Index: src/org/openstreetmap/josm/tools/OpenBrowser.java
===================================================================
--- src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 291)
+++ src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 292)
@@ -52,8 +52,11 @@
 
 	private static void linux(String url) throws IOException {
-		try {
-			Runtime.getRuntime().exec("gnome-open " + url);
-		} catch (IOException e) {
-			Runtime.getRuntime().exec("kfmclient openURL " + url);
+		String[] programs = {"gnome-open", "kfmclient openURL", "firefox"};
+		for (String program : programs) {
+			try {
+				Runtime.getRuntime().exec(program+" "+url);
+				return;
+			} catch (IOException e) {
+            }
 		}
 	}
Index: src/org/openstreetmap/josm/tools/ShortCutLabel.java
===================================================================
--- src/org/openstreetmap/josm/tools/ShortCutLabel.java	(revision 291)
+++ src/org/openstreetmap/josm/tools/ShortCutLabel.java	(revision 292)
@@ -8,4 +8,6 @@
 public class ShortCutLabel {
 	public static String name(int shortCut, int modifiers) {
+		if (shortCut == 0 && modifiers == 0)
+			return "";
 		String s = "";
 		if ((modifiers & KeyEvent.CTRL_MASK) != 0 || (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0)
