Index: src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 298)
+++ src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 299)
@@ -104,5 +104,5 @@
 				return;
 			}
-			((OsmDataLayer)layer).cleanData(null, false);
+			layer.cleanData(null, false);
 		} catch (IOException e) {
 			e.printStackTrace();
Index: src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 298)
+++ src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 299)
@@ -1,3 +1,3 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+//License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.gui.preferences;
 
@@ -14,6 +14,8 @@
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
@@ -50,13 +52,15 @@
 		public String description;
 		public String resource;
-		public PluginDescription(String name, String description, 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() {
-        }
-	}
-	
+		}
+	}
+
 	private Map<PluginDescription, Boolean> pluginMap;
 	private Box pluginPanel = Box.createVerticalBox();
@@ -75,22 +79,23 @@
 			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);
-            }
+				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 current"));
 		update.addActionListener(new ActionListener(){
 			public void actionPerformed(ActionEvent e) {
-				JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
-            }
-		});
-		//TODO: plugin.add(update, GBC.std().insets(0,0,10,0));
+				update();
+			}
+
+		});
+		plugin.add(update, GBC.std().insets(0,0,10,0));
 
 		JButton configureSites = new JButton(tr("Configure Plugin Sites"));
@@ -98,5 +103,5 @@
 			public void actionPerformed(ActionEvent e) {
 				JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet."));
-            }
+			}
 		});
 		//TODO: plugin.add(configureSites, GBC.std());
@@ -105,12 +110,39 @@
 	}
 
+	private void update() {
+		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."));
+			return;
+		}
+		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)
+			return;
+		PluginDownloader.update(toUpdate);
+	}
+
+	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();
+		Collection<PluginDescription> availablePlugins = getAvailablePlugins();
+		pluginMap = new HashMap<PluginDescription, Boolean>();
+		pluginPanel.removeAll();
 		Collection<String> enabledPlugins = Arrays.asList(Main.pref.get("plugins").split(","));
 		for (final PluginDescription plugin : availablePlugins) {
 			boolean enabled = enabledPlugins.contains(plugin.name);
-			final JCheckBox pluginCheck = new JCheckBox(plugin.name, enabled);
+			final JCheckBox pluginCheck = new JCheckBox(plugin.name+(plugin.version != null && !plugin.version.equals("") ? " Version: "+plugin.version : ""), enabled);
 			pluginPanel.add(pluginCheck);
 
@@ -130,11 +162,11 @@
 		}
 		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);
-            }
+				return o1.compareToIgnoreCase(o2);
+			}
 		});
 		for (String location : PluginInformation.getPluginLocations()) {
@@ -148,17 +180,18 @@
 						try {
 							PluginInformation info = new PluginInformation(f);
-		                    availablePlugins.put(info.name, new PluginDescription(info.name, info.description, PluginInformation.getURLString(f.getPath())));
-	                    } catch (PluginException x) {
-	                    }
+							if (!availablePlugins.containsKey(info.name))
+								availablePlugins.put(info.name, new PluginDescription(info.name, info.description, PluginInformation.getURLString(f.getPath()), 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()));
-                        }
+							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()));
+						}
 					}
 				}
@@ -170,7 +203,8 @@
 						proxy.info.name, 
 						proxy.info.description, 
-						proxy.info.file == null ? null : PluginInformation.getURLString(proxy.info.file.getPath())));
-	    return availablePlugins.values();
-    }
+						proxy.info.file == null ? null : PluginInformation.getURLString(proxy.info.file.getPath()),
+								proxy.info.version));
+		return availablePlugins.values();
+	}
 
 	public void ok() {
@@ -195,5 +229,5 @@
 					if (!PluginDownloader.downloadPlugin(pd))
 						pluginMap.put(pd, false);
-						
+
 		}
 
@@ -204,5 +238,5 @@
 		if (plugins.endsWith(","))
 			plugins = plugins.substring(0, plugins.length()-1);
-		
+
 		String oldPlugins = Main.pref.get("plugins");
 		if (!plugins.equals(oldPlugins)) {
Index: src/org/openstreetmap/josm/plugins/PluginDownloader.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginDownloader.java	(revision 298)
+++ src/org/openstreetmap/josm/plugins/PluginDownloader.java	(revision 299)
@@ -1,3 +1,3 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+//License: GPL. Copyright 2007 by Immanuel Scholz and others
 /**
  * 
@@ -6,7 +6,9 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
@@ -15,5 +17,7 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collection;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -22,8 +26,44 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.preferences.PluginPreference.PluginDescription;
+import org.xml.sax.SAXException;
 
 public class PluginDownloader {
-	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>(.*)");
+
+	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;
+		}
+
+		@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 realRun() throws SAXException, IOException {
+			for (PluginDescription d : toUpdate) {
+				File tempFile = new File(Main.pref.getPreferencesDir()+"temp.jar");
+				if (download(d.resource, tempFile)) {
+					tempFile.renameTo(new File(Main.pref.getPreferencesDir()+"plugins/"+d.name+".jar"));
+					count++;
+				} else
+					errors += d.name + "\n";
+			}
+		}
+	}
+
+	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>(.*)");
 
 	public static int downloadDescription() {
@@ -66,4 +106,5 @@
 			b.append("    <resource>"+escape(m.group(1))+"</resource>\n");
 			b.append("    <description>"+escape(m.group(3))+"</description>\n");
+			b.append("    <version>"+escape(m.group(4))+"</version>\n");
 			b.append("  </plugin>\n");
 		}
@@ -73,30 +114,47 @@
 
 	private static String escape(String s) {
-	    return s.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
-    }
+		return s.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+	}
 
 	public static boolean downloadPlugin(PluginDescription pd) {
 		File file = new File(Main.pref.getPreferencesDir()+"plugins/"+pd.name+".jar");
-	    try {
-	        InputStream in = new URL(pd.resource).openStream();
+		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();
-	        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));
-            }
-        } catch (Exception e) {
-        	JOptionPane.showMessageDialog(Main.parent, tr("Could not download plugin: {0} from {1}", pd.name, pd.resource));
-        }
-        if (file.exists())
-        	file.delete();
-        return false;
-    }
+			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));
+	}
 }
Index: src/org/openstreetmap/josm/tools/OpenBrowser.java
===================================================================
--- src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 298)
+++ src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 299)
@@ -52,5 +52,5 @@
 	}
 
-	private static void linux(String url) throws IOException {
+	private static void linux(String url) {
 		String[] programs = {"gnome-open", "kfmclient openURL", "firefox"};
 		for (String program : programs) {
