Index: /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 3089)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 3090)
@@ -17,4 +17,5 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -77,5 +78,5 @@
             sb.append("<ul>");
             for(PluginInformation pi: downloaded) {
-                sb.append("<li>").append(pi.name).append("</li>");
+                sb.append("<li>").append(pi.name).append(" (").append(pi.version).append(")").append("</li>");
             }
             sb.append("</ul>");
@@ -283,7 +284,6 @@
                     SwingUtilities.invokeLater(new Runnable() {
                         public void run() {
-                            model.setAvailablePlugins(task.getAvailabePlugins());
+                            model.updateAvailablePlugins(task.getAvailabePlugins());
                             pnlPluginPreferences.refreshView();
-
                         }
                     });
@@ -320,5 +320,5 @@
                     sb.toString(),
                     tr("Update plugins"),
-                    failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE,
+                    !failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE,
                             // FIXME: check help topic
                             HelpUtil.ht("/Preferences/Plugin")
@@ -326,6 +326,16 @@
         }
 
+        protected void alertNothingToUpdate() {
+            HelpAwareOptionPane.showOptionDialog(
+                    pnlPluginPreferences,
+                    tr("All installed plugins are up to date. JOSM does not have to download newer versions."),
+                    tr("Plugins up to date"),
+                    JOptionPane.INFORMATION_MESSAGE,
+                    null // FIXME: provide help context
+            );
+        }
+
         public void actionPerformed(ActionEvent e) {
-            List<PluginInformation> toUpdate = model.getSelectedPlugins();
+            final List<PluginInformation> toUpdate = model.getSelectedPlugins();
             // the async task for downloading plugins
             final PluginDownloadTask pluginDownloadTask = new PluginDownloadTask(
@@ -345,4 +355,5 @@
                     notifyDownloadResults(pluginDownloadTask);
                     model.refreshLocalPluginVersion(pluginDownloadTask.getDownloadedPlugins());
+                    model.clearPendingPlugins(pluginDownloadTask.getDownloadedPlugins());
                     pnlPluginPreferences.refreshView();
                 }
@@ -355,4 +366,19 @@
                     if (pluginInfoDownloadTask.isCanceled())
                         return;
+                    model.updateAvailablePlugins(pluginInfoDownloadTask.getAvailabePlugins());
+                    // select plugins which actually have to be updated
+                    //
+                    Iterator<PluginInformation> it = toUpdate.iterator();
+                    while(it.hasNext()) {
+                        PluginInformation pi = it.next();
+                        if (!pi.isUpdateRequired()) {
+                            it.remove();
+                        }
+                    }
+                    if (toUpdate.isEmpty()) {
+                        alertNothingToUpdate();
+                        return;
+                    }
+                    pluginDownloadTask.setPluginsToDownload(toUpdate);
                     Main.worker.submit(pluginDownloadTask);
                     Main.worker.submit(pluginDownloadContinuation);
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 3089)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 3090)
@@ -74,4 +74,39 @@
     }
 
+    protected  void updateAvailablePlugin(PluginInformation other) {
+        if (other == null) return;
+        PluginInformation pi = getPluginInformation(other.name);
+        if (pi == null) {
+            availablePlugins.add(other);
+            return;
+        }
+        pi.updateFromPluginSite(other);
+    }
+
+    /**
+     * Updates the list of plugin information objects with new information from
+     * plugin update sites.
+     * 
+     * @param fromPluginSite plugin information read from plugin update sites
+     */
+    public void updateAvailablePlugins(Collection<PluginInformation> fromPluginSite) {
+        for (PluginInformation other: fromPluginSite) {
+            updateAvailablePlugin(other);
+        }
+        sort();
+        filterDisplayedPlugins(filterExpression);
+        Set<String> activePlugins = new HashSet<String>();
+        activePlugins.addAll(Main.pref.getCollection("plugins", activePlugins));
+        for (PluginInformation pi: availablePlugins) {
+            if (selectedPluginsMap.get(pi) == null) {
+                if (activePlugins.contains(pi.name)) {
+                    selectedPluginsMap.put(pi, true);
+                }
+            }
+        }
+        clearChanged();
+        notifyObservers();
+    }
+
     /**
      * Replies the list of selected plugin information objects
@@ -113,6 +148,6 @@
                 new Comparator<PluginInformation>() {
                     public int compare(PluginInformation o1, PluginInformation o2) {
-                        String n1 = o1.getName() == null ? "" : o1.getName();
-                        String n2 = o2.getName() == null ? "" : o2.getName();
+                        String n1 = o1.getName() == null ? "" : o1.getName().toLowerCase();
+                        String n2 = o2.getName() == null ? "" : o2.getName().toLowerCase();
                         return n1.compareTo(n2);
                     }
@@ -164,4 +199,17 @@
         if (!selected) {
             pendingDownloads.remove(name);
+        }
+    }
+
+    /**
+     * Removes all the plugin in {@code plugins} from the list of plugins
+     * with a pending download
+     * 
+     * @param plugins the list of plugins to clear for a pending download
+     */
+    public void clearPendingPlugins(Collection<PluginInformation> plugins){
+        if (plugins == null || plugins.isEmpty()) return;
+        for(PluginInformation pi: plugins) {
+            pendingDownloads.remove(pi.name);
         }
     }
Index: /trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java	(revision 3089)
+++ /trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java	(revision 3090)
@@ -38,5 +38,5 @@
     private static final Logger logger = Logger.getLogger(PluginDownloadTask.class.getName());
 
-    private final Collection<PluginInformation> toUpdate;
+    private final Collection<PluginInformation> toUpdate = new LinkedList<PluginInformation>();
     private final Collection<PluginInformation> failed = new LinkedList<PluginInformation>();
     private final Collection<PluginInformation> downloaded = new LinkedList<PluginInformation>();
@@ -56,5 +56,5 @@
         super(parent, title == null ? "" : title, false /* don't ignore exceptions */);
         CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
-        this.toUpdate = toUpdate;
+        this.toUpdate.addAll(toUpdate);
     }
 
@@ -70,5 +70,17 @@
         super(title, monitor == null? NullProgressMonitor.INSTANCE: monitor, false /* don't ignore exceptions */);
         CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
-        this.toUpdate = toUpdate;
+        this.toUpdate.addAll(toUpdate);
+    }
+
+    /**
+     * Sets the collection of plugins to update.
+     * 
+     * @param toUpdate the collection of plugins to update. Must not be null.
+     * @throws IllegalArgumentException thrown if toUpdate is null
+     */
+    public void setPluginsToDownload(Collection<PluginInformation> toUpdate) throws IllegalArgumentException{
+        CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
+        this.toUpdate.clear();
+        this.toUpdate.addAll(toUpdate);
     }
 
Index: /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 3089)
+++ /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 3090)
@@ -382,5 +382,14 @@
                 pluginList.add(plugin.load(klass));
             }
-        } catch (Throwable e) {
+        } catch(PluginException e) {
+            if (e.getCause() instanceof ClassNotFoundException) {
+                e.printStackTrace();
+                String msg = tr("<html>Could not load plugin {0} because the plugin<br>main class ''{1}'' was not found.<br>"
+                        + "Delete from preferences?", plugin.name, plugin.className);
+                if (confirmDisablePlugin(parent, msg, plugin.name)) {
+                    Main.pref.removeFromCollection("plugins", plugin.name);
+                }
+            }
+        }  catch (Throwable e) {
             e.printStackTrace();
             String msg = tr("Could not load plugin {0}. Delete from preferences?", plugin.name);
@@ -639,29 +648,41 @@
             }
 
-            // try to update the locally installed plugins
+            // filter plugins which actually have to be updated
             //
-            PluginDownloadTask task2 = new PluginDownloadTask(
-                    monitor.createSubTaskMonitor(1,false),
-                    plugins,
-                    tr("Update plugins")
-            );
-
-            future = service.submit(task2);
-            try {
-                future.get();
-            } catch(ExecutionException e) {
-                e.printStackTrace();
-                alertFailedPluginUpdate(parent, plugins);
-                return;
-            } catch(InterruptedException e) {
-                e.printStackTrace();
-                alertFailedPluginUpdate(parent, plugins);
-                return;
-            }
-            // notify user if downloading a locally installed plugin failed
-            //
-            if (! task2.getFailedPlugins().isEmpty()) {
-                alertFailedPluginUpdate(parent, task2.getFailedPlugins());
-                return;
+            Iterator<PluginInformation> it = plugins.iterator();
+            while(it.hasNext()) {
+                PluginInformation pi = it.next();
+                if (!pi.isUpdateRequired()) {
+                    it.remove();
+                }
+            }
+
+            if (!plugins.isEmpty()) {
+                // try to update the locally installed plugins
+                //
+                PluginDownloadTask task2 = new PluginDownloadTask(
+                        monitor.createSubTaskMonitor(1,false),
+                        plugins,
+                        tr("Update plugins")
+                );
+
+                future = service.submit(task2);
+                try {
+                    future.get();
+                } catch(ExecutionException e) {
+                    e.printStackTrace();
+                    alertFailedPluginUpdate(parent, plugins);
+                    return;
+                } catch(InterruptedException e) {
+                    e.printStackTrace();
+                    alertFailedPluginUpdate(parent, plugins);
+                    return;
+                }
+                // notify user if downloading a locally installed plugin failed
+                //
+                if (! task2.getFailedPlugins().isEmpty()) {
+                    alertFailedPluginUpdate(parent, task2.getFailedPlugins());
+                    return;
+                }
             }
         } finally {
@@ -744,4 +765,9 @@
      * ".jar" files.
      * 
+     * If {@code dowarn} is true, this methods emits warning messages on the console if a downloaded
+     * but not yet installed plugin .jar can't be be installed. If {@code dowarn} is false, the
+     * installation of the respective plugin is sillently skipped.
+     * 
+     * @param dowarn if true, warning messages are displayed; false otherwise
      */
     public static void installDownloadedPlugins(boolean dowarn) {
@@ -760,5 +786,5 @@
             String pluginName = updatedPlugin.getName().substring(0, updatedPlugin.getName().length() - 8);
             if (plugin.exists()) {
-                if (!plugin.delete() && !dowarn) {
+                if (!plugin.delete() && dowarn) {
                     System.err.println(tr("Warning: failed to delete outdated plugin ''{0}''.", plugin.toString()));
                     System.err.println(tr("Warning: failed to install already downloaded plugin ''{0}''. Skipping installation. JOSM is still going to load the old plugin version.", pluginName));
@@ -766,5 +792,5 @@
                 }
             }
-            if (!updatedPlugin.renameTo(plugin) && !dowarn) {
+            if (!updatedPlugin.renameTo(plugin) && dowarn) {
                 System.err.println(tr("Warning: failed to install plugin ''{0}'' from temporary download file ''{1}''. Renaming failed.", plugin.toString(), updatedPlugin.toString()));
                 System.err.println(tr("Warning: failed to install already downloaded plugin ''{0}''. Skipping installation. JOSM is still going to load the old plugin version.", pluginName));
Index: /trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 3089)
+++ /trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 3090)
@@ -48,9 +48,14 @@
     public String downloadlink = null;
     public List<URL> libraries = new LinkedList<URL>();
-
     public final Map<String, String> attr = new TreeMap<String, String>();
 
     /**
-     * @param file the plugin jar file.
+     * Creates a plugin information object by reading the plugin information from
+     * the manifest in the plugin jar.
+     * 
+     * The plugin name is derived from the file name.
+     * 
+     * @param file the plugin jar file
+     * @throws PluginException if reading the manifest fails
      */
     public PluginInformation(File file) throws PluginException{
@@ -58,4 +63,12 @@
     }
 
+    /**
+     * Creates a plugin information object for the plugin with name {@code name}.
+     * Information about the plugin is extracted from the maifest file in the the plugin jar
+     * {@code file}.
+     * @param file the plugin jar
+     * @param name the plugin name
+     * @throws PluginException thrown if reading the manifest file fails
+     */
     public PluginInformation(File file, String name) throws PluginException{
         this.name = name;
@@ -80,4 +93,13 @@
     }
 
+    /**
+     * Creates a plugin information object by reading plugin information in Manifest format
+     * from the input stream {@code manifestStream}.
+     * 
+     * @param manifestStream the stream to read the manifest from
+     * @param name the plugin name
+     * @param url the download URL for the plugin
+     * @throws PluginException thrown if the plugin information can't be read from the input stream
+     */
     public PluginInformation(InputStream manifestStream, String name, String url) throws PluginException {
         this.name = name;
@@ -94,6 +116,29 @@
     }
 
-    private void scanManifest(Manifest manifest, boolean oldcheck)
-    {
+    /**
+     * Updates the plugin information of this plugin information object with the
+     * plugin information in a plugin information object retrieved from a plugin
+     * update site.
+     * 
+     * @param other the plugin information object retrieved from the update
+     * site
+     */
+    public void updateFromPluginSite(PluginInformation other) {
+        this.mainversion = other.mainversion;
+        this.className = other.className;
+        this.requires = other.requires;
+        this.link = other.link;
+        this.description = other.description;
+        this.early = other.early;
+        this.author = other.author;
+        this.stage = other.stage;
+        this.version = other.version;
+        this.downloadlink = other.downloadlink;
+        this.libraries = other.libraries;
+        this.attr.clear();
+        this.attr.putAll(other.attr);
+    }
+
+    private void scanManifest(Manifest manifest, boolean oldcheck){
         String lang = LanguageInfo.getLanguageCodeManifest();
         Attributes attr = manifest.getMainAttributes();
