Index: trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 8017)
@@ -423,5 +423,5 @@
 
         monitor.indeterminateSubTask(tr("Loading early plugins"));
-        PluginHandler.loadEarlyPlugins(splash,pluginsToLoad, monitor.createSubTaskMonitor(1, false));
+        PluginHandler.loadEarlyPlugins(splash, pluginsToLoad, monitor.createSubTaskMonitor(1, false));
 
         monitor.indeterminateSubTask(tr("Setting defaults"));
@@ -432,5 +432,5 @@
 
         monitor.indeterminateSubTask(tr("Loading plugins"));
-        PluginHandler.loadLatePlugins(splash,pluginsToLoad,  monitor.createSubTaskMonitor(1, false));
+        PluginHandler.loadLatePlugins(splash, pluginsToLoad,  monitor.createSubTaskMonitor(1, false));
         toolbar.refreshToolbarControl();
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 8017)
@@ -318,9 +318,4 @@
             public void run() {
                 boolean requiresRestart = false;
-                if (task != null && !task.isCanceled()) {
-                    if (!task.getDownloadedPlugins().isEmpty()) {
-                        requiresRestart = true;
-                    }
-                }
 
                 for (PreferenceSetting setting : settingsInitialized) {
@@ -370,4 +365,26 @@
                             );
                 }
+
+                // load the plugins that can be loaded at runtime
+                List<PluginInformation> newPlugins = preference.getNewlyActivatedPlugins();
+                if (newPlugins != null) {
+                    Collection<PluginInformation> downloadedPlugins = null;
+                    if (task != null && !task.isCanceled()) {
+                        downloadedPlugins = task.getDownloadedPlugins();
+                    }
+                    List<PluginInformation> toLoad = new ArrayList<>();
+                    for (PluginInformation pi : newPlugins) {
+                        if (toDownload.contains(pi) && downloadedPlugins != null && !downloadedPlugins.contains(pi)) {
+                            continue; // failed download
+                        }
+                        if (pi.canloadatruntime) {
+                            toLoad.add(pi);
+                        }
+                    }
+                    if (!toLoad.isEmpty()) {
+                        PluginHandler.loadPlugins(PreferenceTabbedPane.this, toLoad, null); // FIXME: progress bar
+                    }
+                }
+
                 Main.parent.repaint();
             }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java	(revision 8017)
@@ -123,5 +123,5 @@
      * @since 6797
      */
-    public static void notifyDownloadResults(final Component parent, PluginDownloadTask task) {
+    public void notifyDownloadResults(final Component parent, PluginDownloadTask task) {
         final Collection<PluginInformation> downloaded = task.getDownloadedPlugins();
         final Collection<PluginInformation> failed = task.getFailedPlugins();
@@ -129,5 +129,12 @@
         sb.append("<html>");
         sb.append(buildDownloadSummary(task));
-        if (!downloaded.isEmpty()) {
+        boolean restartRequired = false;
+        for (PluginInformation pi : downloaded) {
+            if (!model.getNewlyActivatedPlugins().contains(pi) || !pi.canloadatruntime) {
+                restartRequired = true;
+                break;
+            }
+        }
+        if (restartRequired) {
             sb.append(tr("Please restart JOSM to activate the downloaded plugins."));
         }
@@ -276,4 +283,8 @@
     }
 
+    public List<PluginInformation> getNewlyActivatedPlugins() {
+        return model != null ? model.getNewlyActivatedPlugins() : null;
+    }
+
     @Override
     public boolean ok() {
@@ -285,5 +296,8 @@
             Collections.sort(l);
             Main.pref.putCollection("plugins", l);
-            return true;
+            if (!model.getNewlyDeactivatedPlugins().isEmpty()) return true;
+            for (PluginInformation pi : model.getNewlyActivatedPlugins()) {
+                if (!pi.canloadatruntime) return true;
+            }
         }
         return false;
@@ -436,5 +450,5 @@
                     //
                     Iterator<PluginInformation> it = toUpdate.iterator();
-                    while(it.hasNext()) {
+                    while (it.hasNext()) {
                         PluginInformation pi = it.next();
                         if (!pi.isUpdateRequired()) {
@@ -590,3 +604,5 @@
         }
     }
+
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 8017)
@@ -25,10 +25,12 @@
  */
 public class PluginPreferencesModel extends Observable {
+    // remember the initial list of active plugins
+    private final Set<String> currentActivePlugins;
     private final List<PluginInformation> availablePlugins = new ArrayList<>();
+    private String filterExpression;
     private final List<PluginInformation> displayedPlugins = new ArrayList<>();
     private final Map<PluginInformation, Boolean> selectedPluginsMap = new HashMap<>();
+    // plugins that still require an update/download
     private Set<String> pendingDownloads = new HashSet<>();
-    private String filterExpression;
-    private Set<String> currentActivePlugins;
 
     /**
@@ -197,5 +199,5 @@
         PluginInformation pi = getPluginInformation(name);
         if (pi != null) {
-            selectedPluginsMap.put(pi,selected);
+            selectedPluginsMap.put(pi, selected);
             if (pi.isUpdateRequired()) {
                 pendingDownloads.add(pi.name);
@@ -213,7 +215,7 @@
      * @param plugins the list of plugins to clear for a pending download
      */
-    public void clearPendingPlugins(Collection<PluginInformation> plugins){
+    public void clearPendingPlugins(Collection<PluginInformation> plugins) {
         if (plugins == null || plugins.isEmpty()) return;
-        for(PluginInformation pi: plugins) {
+        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 8015)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java	(revision 8017)
@@ -187,7 +187,7 @@
 
     /**
-     * Replies the list of successfully downloaded plugins
-     *
-     * @return the list of successfully downloaded plugins
+     * Replies the list of plugins whose download has failed.
+     *
+     * @return the list of plugins whose download has failed
      */
     public Collection<PluginInformation> getFailedPlugins() {
@@ -196,7 +196,7 @@
 
     /**
-     * Replies the list of plugins whose download has failed
-     *
-     * @return the list of plugins whose download has failed
+     * Replies the list of successfully downloaded plugins.
+     *
+     * @return the list of successfully downloaded plugins
      */
     public Collection<PluginInformation> getDownloadedPlugins() {
Index: trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 8017)
@@ -187,4 +187,21 @@
 
     /**
+     * ClassLoader that makes the addURL method of URLClassLoader public.
+     *
+     * Like URLClassLoader, but allows to add more URLs after construction.
+     */
+    public static class DynamicURLClassLoader extends URLClassLoader {
+
+        public DynamicURLClassLoader(URL[] urls, ClassLoader parent) {
+            super(urls, parent);
+        }
+
+        @Override
+        public void addURL(URL url) {
+            super.addURL(url);
+        }
+    }
+
+    /**
      * List of unmaintained plugins. Not really up-to-date as the vast majority of plugins are not really maintained after a few months, sadly...
      */
@@ -200,4 +217,9 @@
      */
     public static final Collection<PluginProxy> pluginList = new LinkedList<>();
+
+    /**
+     * Global plugin ClassLoader.
+     */
+    private static DynamicURLClassLoader pluginClassLoader;
 
     /**
@@ -536,39 +558,42 @@
 
     /**
-     * Creates a class loader for loading plugin code.
-     *
-     * @param plugins the collection of plugins which are going to be loaded with this
-     * class loader
+     * Get the class loader for loading plugin code.
+     *
      * @return the class loader
      */
-    public static ClassLoader createClassLoader(Collection<PluginInformation> plugins) {
+    public static DynamicURLClassLoader getPluginClassLoader() {
+        if (pluginClassLoader == null) {
+            pluginClassLoader = AccessController.doPrivileged(new PrivilegedAction<DynamicURLClassLoader>() {
+                public DynamicURLClassLoader run() {
+                    return new DynamicURLClassLoader(new URL[0], Main.class.getClassLoader());
+                }
+            });
+            sources.add(0, pluginClassLoader);
+        }
+        return pluginClassLoader;
+    }
+
+    /**
+     * Add more plugins to the plugin class loader.
+     *
+     * @param plugins the plugins that should be handled by the plugin class loader
+     */
+    public static void extendPluginClassLoader(Collection<PluginInformation> plugins) {
         // iterate all plugins and collect all libraries of all plugins:
-        List<URL> allPluginLibraries = new LinkedList<>();
         File pluginDir = Main.pref.getPluginsDirectory();
-
-        // Add all plugins already loaded (to include early plugins in the classloader, allowing late plugins to rely on early ones)
-        Collection<PluginInformation> allPlugins = new HashSet<>(plugins);
-        for (PluginProxy proxy : pluginList) {
-            allPlugins.add(proxy.getPluginInformation());
-        }
-
-        for (PluginInformation info : allPlugins) {
+        DynamicURLClassLoader cl = getPluginClassLoader();
+
+        for (PluginInformation info : plugins) {
             if (info.libraries == null) {
                 continue;
             }
-            allPluginLibraries.addAll(info.libraries);
+            for (URL libUrl : info.libraries) {
+                cl.addURL(libUrl);
+            }
             File pluginJar = new File(pluginDir, info.name + ".jar");
             I18n.addTexts(pluginJar);
             URL pluginJarUrl = Utils.fileToURL(pluginJar);
-            allPluginLibraries.add(pluginJarUrl);
-        }
-
-        // create a classloader for all plugins:
-        final URL[] jarUrls = allPluginLibraries.toArray(new URL[allPluginLibraries.size()]);
-        return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
-            public ClassLoader run() {
-                return new URLClassLoader(jarUrls, Main.class.getClassLoader());
-            }
-      });
+            cl.addURL(pluginJarUrl);
+        }
     }
 
@@ -614,5 +639,5 @@
      * @param monitor the progress monitor. Defaults to {@link NullProgressMonitor#INSTANCE} if null.
      */
-    public static void loadPlugins(Component parent,Collection<PluginInformation> plugins, ProgressMonitor monitor) {
+    public static void loadPlugins(Component parent, Collection<PluginInformation> plugins, ProgressMonitor monitor) {
         if (monitor == null) {
             monitor = NullProgressMonitor.INSTANCE;
@@ -644,10 +669,9 @@
                 return;
 
-            ClassLoader pluginClassLoader = createClassLoader(toLoad);
-            sources.add(0, pluginClassLoader);
+            extendPluginClassLoader(toLoad);
             monitor.setTicksCount(toLoad.size());
             for (PluginInformation info : toLoad) {
                 monitor.setExtraText(tr("Loading plugin ''{0}''...", info.name));
-                loadPlugin(parent, info, pluginClassLoader);
+                loadPlugin(parent, info, getPluginClassLoader());
                 monitor.worked(1);
             }
@@ -1045,5 +1069,5 @@
      * 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.
+     * installation of the respective plugin is silently skipped.
      *
      * @param dowarn if true, warning messages are displayed; false otherwise
Index: trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 8015)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 8017)
@@ -78,4 +78,6 @@
     /** The plugin icon. */
     public ImageIcon icon;
+    /** Plugin can be loaded at any time and not just at start. */
+    public boolean canloadatruntime = false;
     /** The libraries referenced in Class-Path manifest attribute. */
     public List<URL> libraries = new LinkedList<>();
@@ -169,4 +171,5 @@
         this.icon = other.icon;
         this.iconPath = other.iconPath;
+        this.canloadatruntime = other.canloadatruntime;
         this.libraries = other.libraries;
         this.attr.clear();
@@ -189,4 +192,5 @@
         this.early = other.early;
         this.className = other.className;
+        this.canloadatruntime = other.canloadatruntime;
         this.libraries = other.libraries;
         this.stage = other.stage;
@@ -250,4 +254,5 @@
             }
         }
+        canloadatruntime = Boolean.parseBoolean(attr.getValue("Plugin-Canloadatruntime"));
         if (oldcheck && mainversion > Version.getInstance().getVersion()) {
             int myv = Version.getInstance().getVersion();
