Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/AvailablePluginsView.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/AvailablePluginsView.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/AvailablePluginsView.cs	(revision 6413)
@@ -117,10 +117,11 @@
     void updateOrInstallPluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
       UpdateOrInstallPluginsBackgroundWorkerArgument info = (UpdateOrInstallPluginsBackgroundWorkerArgument)e.Argument;
+      bool cancelled = false;
       if (info.PluginsToInstall.Count() > 0)
-        installationManager.Install(info.PluginsToInstall);
+        installationManager.Install(info.PluginsToInstall, out cancelled);
       if (info.PluginsToUpdate.Count() > 0)
-        installationManager.Update(info.PluginsToUpdate);
-
-      if (info.PluginsToInstall.Count() > 0 || info.PluginsToUpdate.Count() > 0)
+        installationManager.Update(info.PluginsToUpdate, out cancelled);
+
+      if (!cancelled && (info.PluginsToInstall.Count() > 0 || info.PluginsToUpdate.Count() > 0))
         pluginManager.DiscoverAndCheckPlugins();
     }
@@ -176,9 +177,9 @@
       var pluginsToInstall = selectedProduct.Plugins.Except(pluginsToUpdate);
 
-      updateOrInstallInfo.PluginsToInstall = 
+      updateOrInstallInfo.PluginsToInstall =
         pluginsToInstall
         .Cast<IPluginDescription>()
         .ToList();
-      updateOrInstallInfo.PluginsToUpdate = 
+      updateOrInstallInfo.PluginsToUpdate =
         pluginsToUpdate
         .Cast<IPluginDescription>()
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/BasicUpdateView.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/BasicUpdateView.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/BasicUpdateView.cs	(revision 6413)
@@ -79,6 +79,8 @@
                             select remotePlugin;
       if (pluginsToUpdate.Count() > 0) {
-        installationManager.Update(pluginsToUpdate);
-        pluginManager.DiscoverAndCheckPlugins();
+        bool cancelled;
+        installationManager.Update(pluginsToUpdate, out cancelled);
+        if (!cancelled)
+          pluginManager.DiscoverAndCheckPlugins();
         e.Cancel = false;
       } else {
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstallationManager.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstallationManager.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstallationManager.cs	(revision 6413)
@@ -98,8 +98,9 @@
     /// </summary>
     /// <param name="plugins"></param>
-    public void Install(IEnumerable<IPluginDescription> plugins) {
+    public void Install(IEnumerable<IPluginDescription> plugins, out bool cancelled) {
       var args = new PluginInfrastructureCancelEventArgs(plugins);
       OnPreInstall(args);
       if (!args.Cancel) {
+        cancelled = false;
         var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
         try {
@@ -123,4 +124,6 @@
           throw new InstallationManagerException("General communication exception in connection to server.", e);
         }
+      } else {
+        cancelled = true;
       }
     }
@@ -130,8 +133,9 @@
     /// </summary>
     /// <param name="plugins"></param>
-    public void Update(IEnumerable<IPluginDescription> plugins) {
+    public void Update(IEnumerable<IPluginDescription> plugins, out bool cancelled) {
       PluginInfrastructureCancelEventArgs args = new PluginInfrastructureCancelEventArgs(plugins);
       OnPreUpdate(args);
       if (!args.Cancel) {
+        cancelled = false;
         var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
         try {
@@ -155,4 +159,6 @@
           throw new InstallationManagerException("General communication exception in connection to server.", e);
         }
+      } else {
+        cancelled = true;
       }
     }
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstalledPluginsView.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstalledPluginsView.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/InstalledPluginsView.cs	(revision 6413)
@@ -116,7 +116,8 @@
                             select remotePlugin;
       if (pluginsToUpdate.Count() > 0) {
-        installationManager.Update(pluginsToUpdate);
-      }
-      pluginManager.DiscoverAndCheckPlugins();
+        bool cancelled;
+        installationManager.Update(pluginsToUpdate, out cancelled);
+        if (!cancelled) pluginManager.DiscoverAndCheckPlugins();
+      }
     }
 
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.Designer.cs	(revision 6413)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.Designer.cs	(revision 6413)
@@ -0,0 +1,122 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.PluginInfrastructure.Advanced {
+  partial class PluginUpdaterForm {
+    /// <summary>
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary>
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Windows Form Designer generated code
+
+    /// <summary>
+    /// Required method for Designer support - do not modify
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+      this.progressBar = new System.Windows.Forms.ProgressBar();
+      this.statusLabel = new System.Windows.Forms.Label();
+      this.okButton = new System.Windows.Forms.Button();
+      this.SuspendLayout();
+      // 
+      // progressBar
+      // 
+      this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.progressBar.Location = new System.Drawing.Point(12, 73);
+      this.progressBar.Name = "progressBar";
+      this.progressBar.Size = new System.Drawing.Size(350, 23);
+      this.progressBar.TabIndex = 1;
+      this.progressBar.UseWaitCursor = true;
+      // 
+      // statusLabel
+      // 
+      this.statusLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.statusLabel.AutoSize = true;
+      this.statusLabel.Location = new System.Drawing.Point(13, 13);
+      this.statusLabel.Name = "statusLabel";
+      this.statusLabel.Size = new System.Drawing.Size(61, 13);
+      this.statusLabel.TabIndex = 2;
+      this.statusLabel.Text = "statusLabel";
+      this.statusLabel.UseWaitCursor = true;
+      // 
+      // okButton
+      // 
+      this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.okButton.Location = new System.Drawing.Point(12, 73);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(78, 23);
+      this.okButton.TabIndex = 3;
+      this.okButton.Text = "Ok";
+      this.okButton.UseVisualStyleBackColor = true;
+      this.okButton.UseWaitCursor = true;
+      this.okButton.Visible = false;
+      this.okButton.Click += new System.EventHandler(this.okButton_Click);
+      // 
+      // PluginUpdaterForm
+      // 
+      this.AcceptButton = this.okButton;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.ClientSize = new System.Drawing.Size(374, 108);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.statusLabel);
+      this.Controls.Add(this.progressBar);
+      this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
+      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+      this.Icon = global::HeuristicLab.PluginInfrastructure.Resources.HeuristicLab;
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "PluginUpdaterForm";
+      this.ShowInTaskbar = false;
+      this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+      this.Text = "Plugin Updater";
+      this.UseWaitCursor = true;
+      this.Load += new System.EventHandler(this.PluginUpdaterForm_Load);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.ToolTip toolTip;
+    private System.Windows.Forms.ProgressBar progressBar;
+    private System.Windows.Forms.Label statusLabel;
+    private System.Windows.Forms.Button okButton;
+  }
+}
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.cs	(revision 6413)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/PluginUpdaterForm.cs	(revision 6413)
@@ -0,0 +1,263 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure.Manager;
+
+namespace HeuristicLab.PluginInfrastructure.Advanced {
+  internal partial class PluginUpdaterForm : Form, IStatusView {
+    private InstallationManager installationManager;
+    private PluginManager pluginManager;
+    private string pluginDir;
+    private BackgroundWorker updatePluginsBackgroundWorker;
+
+    public PluginUpdaterForm(PluginManager pluginManager)
+      : base() {
+      InitializeComponent();
+      FileVersionInfo pluginInfrastructureVersion = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location);
+      Text = "HeuristicLab Plugin Manager " + pluginInfrastructureVersion.FileVersion;
+      pluginManager.PluginLoaded += pluginManager_PluginLoaded;
+      pluginManager.PluginUnloaded += pluginManager_PluginUnloaded;
+      pluginManager.Initializing += pluginManager_Initializing;
+      pluginManager.Initialized += pluginManager_Initialized;
+
+      pluginDir = Application.StartupPath;
+
+      installationManager = new InstallationManager(pluginDir);
+      installationManager.PluginInstalled += new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginInstalled);
+      installationManager.PluginRemoved += new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginRemoved);
+      installationManager.PluginUpdated += new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginUpdated);
+      installationManager.PreInstallPlugin += new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreInstallPlugin);
+      installationManager.PreRemovePlugin += new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreRemovePlugin);
+      installationManager.PreUpdatePlugin += new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreUpdatePlugin);
+
+      this.pluginManager = pluginManager;
+
+      updatePluginsBackgroundWorker = new BackgroundWorker();
+      updatePluginsBackgroundWorker.DoWork += new DoWorkEventHandler(updatePluginsBackgroundWorker_DoWork);
+      updatePluginsBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(updatePluginsBackgroundWorker_RunWorkerCompleted);
+    }
+
+
+    private void PluginUpdaterForm_Load(object sender, EventArgs e) {
+      updatePluginsBackgroundWorker.RunWorkerAsync();
+      ShowProgressIndicator();
+      ShowMessage("Downloading and installing plugins...");
+    }
+
+    #region event handlers for update plugins backgroundworker
+    void updatePluginsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      if (e.Error != null) {
+        ShowError("Installation Error", "There was a problem while downloading and installing updates." + Environment.NewLine + "Please check your connection settings.");
+      } else {
+        Close();
+      }
+    }
+
+    void updatePluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
+      IEnumerable<IPluginDescription> installedPlugins = pluginManager.Plugins.OfType<IPluginDescription>().ToList();
+      var remotePlugins = installationManager.GetRemotePluginList();
+      // if there is a local plugin with same name and same major and minor version then it's an update
+      var pluginsToUpdate = from remotePlugin in remotePlugins
+                            let matchingLocalPlugins = from installedPlugin in installedPlugins
+                                                       where installedPlugin.Name == remotePlugin.Name
+                                                       where installedPlugin.Version.Major == remotePlugin.Version.Major
+                                                       where installedPlugin.Version.Minor == remotePlugin.Version.Minor
+                                                       where Util.IsNewerThan(remotePlugin, installedPlugin)
+                                                       select installedPlugin
+                            where matchingLocalPlugins.Count() > 0
+                            select remotePlugin;
+      if (pluginsToUpdate.Count() > 0) {
+        bool canceled;
+        installationManager.Update(pluginsToUpdate, out canceled);
+        if (!canceled)
+          pluginManager.DiscoverAndCheckPlugins();
+        e.Cancel = false;
+      }
+    }
+    #endregion
+
+    #region plugin manager event handlers
+    private void pluginManager_Initialized(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Initialized PluginInfrastructure");
+    }
+
+    private void pluginManager_Initializing(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Initializing PluginInfrastructure");
+    }
+
+    private void pluginManager_PluginUnloaded(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Unloaded " + e.Entity);
+    }
+
+    private void pluginManager_PluginLoaded(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Loaded " + e.Entity);
+    }
+    #endregion
+
+    #region installation manager event handlers
+    private void installationManager_PreUpdatePlugin(object sender, PluginInfrastructureCancelEventArgs e) {
+      if (e.Plugins.Count() > 0) {
+        e.Cancel = (bool)Invoke((Func<IEnumerable<IPluginDescription>, bool>)ConfirmUpdateAction, e.Plugins) == false;
+      }
+    }
+
+    private void installationManager_PreRemovePlugin(object sender, PluginInfrastructureCancelEventArgs e) {
+      if (e.Plugins.Count() > 0) {
+        e.Cancel = (bool)Invoke((Func<IEnumerable<IPluginDescription>, bool>)ConfirmRemoveAction, e.Plugins) == false;
+      }
+    }
+
+    private void installationManager_PreInstallPlugin(object sender, PluginInfrastructureCancelEventArgs e) {
+      if (e.Plugins.Count() > 0)
+        if ((bool)Invoke((Func<IEnumerable<IPluginDescription>, bool>)ConfirmInstallAction, e.Plugins) == true) {
+          SetStatusStrip("Installing " + e.Plugins.Aggregate("", (a, b) => a.ToString() + "; " + b.ToString()));
+          e.Cancel = false;
+        } else {
+          e.Cancel = true;
+          SetStatusStrip("Install canceled");
+        }
+    }
+
+    private void installationManager_PluginUpdated(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Updated " + e.Entity);
+    }
+
+    private void installationManager_PluginRemoved(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Removed " + e.Entity);
+    }
+
+    private void installationManager_PluginInstalled(object sender, PluginInfrastructureEventArgs e) {
+      SetStatusStrip("Installed " + e.Entity);
+    }
+    #endregion
+
+    #region confirmation dialogs
+    private bool ConfirmRemoveAction(IEnumerable<IPluginDescription> plugins) {
+      StringBuilder strBuilder = new StringBuilder();
+      foreach (var plugin in plugins) {
+        foreach (var file in plugin.Files) {
+          strBuilder.AppendLine(Path.GetFileName(file.Name));
+        }
+      }
+      using (var confirmationDialog = new ConfirmationDialog("Confirm Delete", "Do you want to delete following files?", strBuilder.ToString())) {
+        return (confirmationDialog.ShowDialog(this)) == DialogResult.OK;
+      }
+    }
+
+    private bool ConfirmUpdateAction(IEnumerable<IPluginDescription> plugins) {
+      StringBuilder strBuilder = new StringBuilder();
+      foreach (var plugin in plugins) {
+        strBuilder.AppendLine(plugin.ToString());
+      }
+      using (var confirmationDialog = new ConfirmationDialog("Confirm Update", "Do you want to update following plugins?", strBuilder.ToString())) {
+        return (confirmationDialog.ShowDialog(this)) == DialogResult.OK;
+      }
+    }
+
+    private bool ConfirmInstallAction(IEnumerable<IPluginDescription> plugins) {
+      foreach (var plugin in plugins) {
+        if (!string.IsNullOrEmpty(plugin.LicenseText)) {
+          using (var licenseConfirmationBox = new LicenseConfirmationDialog(plugin)) {
+            if (licenseConfirmationBox.ShowDialog(this) != DialogResult.OK)
+              return false;
+          }
+        }
+      }
+      return true;
+    }
+
+
+    #endregion
+
+    #region helper methods
+    private void SetStatusStrip(string msg) {
+      if (InvokeRequired) Invoke((Action<string>)SetStatusStrip, msg);
+      else {
+        statusLabel.Text = msg;
+      }
+    }
+
+    #endregion
+
+
+    protected override void OnClosing(CancelEventArgs e) {
+      installationManager.PluginInstalled -= new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginInstalled);
+      installationManager.PluginRemoved -= new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginRemoved);
+      installationManager.PluginUpdated -= new EventHandler<PluginInfrastructureEventArgs>(installationManager_PluginUpdated);
+      installationManager.PreInstallPlugin -= new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreInstallPlugin);
+      installationManager.PreRemovePlugin -= new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreRemovePlugin);
+      installationManager.PreUpdatePlugin -= new EventHandler<PluginInfrastructureCancelEventArgs>(installationManager_PreUpdatePlugin);
+      base.OnClosing(e);
+    }
+
+    #region IStatusView Members
+
+    public void ShowProgressIndicator(double percentProgress) {
+      if (percentProgress < 0.0 || percentProgress > 1.0) throw new ArgumentException("percentProgress");
+      progressBar.Visible = true;
+      progressBar.Style = ProgressBarStyle.Continuous;
+      int range = progressBar.Maximum - progressBar.Minimum;
+      progressBar.Value = (int)(percentProgress * range + progressBar.Minimum);
+    }
+
+    public void ShowProgressIndicator() {
+      progressBar.Visible = true;
+      progressBar.Style = ProgressBarStyle.Marquee;
+    }
+
+    public void HideProgressIndicator() {
+      progressBar.Visible = false;
+    }
+
+    public void ShowMessage(string message) {
+      statusLabel.Text = message;
+    }
+
+    public void RemoveMessage(string message) {
+      statusLabel.Text = string.Empty;
+    }
+
+    public void LockUI() {
+      Cursor = Cursors.AppStarting;
+    }
+    public void UnlockUI() {
+      Cursor = Cursors.Default;
+    }
+    public void ShowError(string shortMessage, string description) {
+      progressBar.Visible = false;
+      okButton.Visible = true;
+      statusLabel.Text = shortMessage + Environment.NewLine + description;
+      this.Cursor = Cursors.Default;
+    }
+    #endregion
+
+    private void okButton_Click(object sender, EventArgs e) {
+      Close();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/Util.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/Util.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Advanced/Util.cs	(revision 6413)
@@ -66,4 +66,10 @@
     }
 
+    // compares for two plugins with same major and minor version if plugin1 is newer than plugin2
+    internal static bool IsNewerThan(IPluginDescription plugin1, IPluginDescription plugin2) {
+      // newer: build version is higher, or if build version is the same revision is higher
+      return plugin1.Version.Build > plugin2.Version.Build ||
+        (plugin1.Version.Build == plugin2.Version.Build && plugin1.Version.Revision > plugin2.Version.Revision);
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/HeuristicLab.PluginInfrastructure-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/HeuristicLab.PluginInfrastructure-3.3.csproj	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/HeuristicLab.PluginInfrastructure-3.3.csproj	(revision 6413)
@@ -144,4 +144,10 @@
       <DependentUpon>ConnectionSetupView.cs</DependentUpon>
     </Compile>
+    <Compile Include="Advanced\PluginUpdaterForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Advanced\PluginUpdaterForm.Designer.cs">
+      <DependentUpon>PluginUpdaterForm.cs</DependentUpon>
+    </Compile>
     <Compile Include="Advanced\DeploymentService\AdminServiceClientFactory.cs" />
     <Compile Include="Advanced\DeploymentService\DeploymentServerCertificateValidator.cs" />
@@ -259,5 +265,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <None Include="Advanced\DeploymentService\GenerateServiceClients.cmd" />
-    <None Include="app.config" />
+    <None Include="app.config">
+      <SubType>Designer</SubType>
+    </None>
     <None Include="HeuristicLab.snk" />
     <None Include="Properties\AssemblyInfo.frame" />
@@ -308,5 +316,5 @@
     <None Include="Resources\HeuristicLabLogo.png" />
     <None Include="Resources\HeuristicLabBanner.png" />
-    <None Include="Resources\VS2008ImageLibrary_Actions_Delete.png" />
+    <Content Include="Resources\UpdateAvailable.ico" />
     <Content Include="Resources\VS2008ImageLibrary_Actions_PublishToWebHS.png" />
     <Content Include="Resources\VS2008ImageLibrary_Actions_RepeatHS.png" />
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.Designer.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.Designer.cs	(revision 6413)
@@ -2,5 +2,5 @@
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.1
+//     Runtime Version:4.0.30319.225
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
@@ -10,212 +10,220 @@
 
 namespace HeuristicLab.PluginInfrastructure {
-
-
-  /// <summary>
-  ///   A strongly-typed resource class, for looking up localized strings, etc.
-  /// </summary>
-  // This class was auto-generated by the StronglyTypedResourceBuilder
-  // class via a tool like ResGen or Visual Studio.
-  // To add or remove a member, edit your .ResX file then rerun ResGen
-  // with the /str option, or rebuild your VS project.
-  [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
-  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-  internal class Resources {
-
-    private static global::System.Resources.ResourceManager resourceMan;
-
-    private static global::System.Globalization.CultureInfo resourceCulture;
-
-    [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-    internal Resources() {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HeuristicLab.PluginInfrastructure.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Add {
+            get {
+                object obj = ResourceManager.GetObject("Add", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap ArrowUp {
+            get {
+                object obj = ResourceManager.GetObject("ArrowUp", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Assembly {
+            get {
+                object obj = ResourceManager.GetObject("Assembly", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Document {
+            get {
+                object obj = ResourceManager.GetObject("Document", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Error {
+            get {
+                object obj = ResourceManager.GetObject("Error", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Icon ErrorIcon {
+            get {
+                object obj = ResourceManager.GetObject("ErrorIcon", resourceCulture);
+                return ((System.Drawing.Icon)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap File {
+            get {
+                object obj = ResourceManager.GetObject("File", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Icon HeuristicLab {
+            get {
+                object obj = ResourceManager.GetObject("HeuristicLab", resourceCulture);
+                return ((System.Drawing.Icon)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap HeuristicLabBanner {
+            get {
+                object obj = ResourceManager.GetObject("HeuristicLabBanner", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap HeuristicLabLogo {
+            get {
+                object obj = ResourceManager.GetObject("HeuristicLabLogo", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Install {
+            get {
+                object obj = ResourceManager.GetObject("Install", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Internet {
+            get {
+                object obj = ResourceManager.GetObject("Internet", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to HeuristicLab is free software: you can redistribute it and/or modify
+        ///it under the terms of the GNU General Public License as published by
+        ///the Free Software Foundation, either version 3 of the License, or
+        ///(at your option) any later version.
+        ///
+        ///HeuristicLab is distributed in the hope that it will be useful,
+        ///but WITHOUT ANY WARRANTY; without even the implied warranty of
+        ///MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        ///GNU General Public License for more details.
+        ///
+        ///You should have received a copy of t [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string LicenseText {
+            get {
+                return ResourceManager.GetString("LicenseText", resourceCulture);
+            }
+        }
+        
+        internal static System.Drawing.Bitmap NetworkConnections {
+            get {
+                object obj = ResourceManager.GetObject("NetworkConnections", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Plugin {
+            get {
+                object obj = ResourceManager.GetObject("Plugin", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap PublishToWeb {
+            get {
+                object obj = ResourceManager.GetObject("PublishToWeb", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Remove {
+            get {
+                object obj = ResourceManager.GetObject("Remove", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap Repeat {
+            get {
+                object obj = ResourceManager.GetObject("Repeat", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Icon Setup_Install {
+            get {
+                object obj = ResourceManager.GetObject("Setup_Install", resourceCulture);
+                return ((System.Drawing.Icon)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap ShowDetails {
+            get {
+                object obj = ResourceManager.GetObject("ShowDetails", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap ShowIcons {
+            get {
+                object obj = ResourceManager.GetObject("ShowIcons", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Icon UpdateAvailable {
+            get {
+                object obj = ResourceManager.GetObject("UpdateAvailable", resourceCulture);
+                return ((System.Drawing.Icon)(obj));
+            }
+        }
     }
-
-    /// <summary>
-    ///   Returns the cached ResourceManager instance used by this class.
-    /// </summary>
-    [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-    internal static global::System.Resources.ResourceManager ResourceManager {
-      get {
-        if (object.ReferenceEquals(resourceMan, null)) {
-          global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HeuristicLab.PluginInfrastructure.Resources", typeof(Resources).Assembly);
-          resourceMan = temp;
-        }
-        return resourceMan;
-      }
-    }
-
-    /// <summary>
-    ///   Overrides the current thread's CurrentUICulture property for all
-    ///   resource lookups using this strongly typed resource class.
-    /// </summary>
-    [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-    internal static global::System.Globalization.CultureInfo Culture {
-      get {
-        return resourceCulture;
-      }
-      set {
-        resourceCulture = value;
-      }
-    }
-
-    internal static System.Drawing.Bitmap Add {
-      get {
-        object obj = ResourceManager.GetObject("Add", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap ArrowUp {
-      get {
-        object obj = ResourceManager.GetObject("ArrowUp", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Assembly {
-      get {
-        object obj = ResourceManager.GetObject("Assembly", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Document {
-      get {
-        object obj = ResourceManager.GetObject("Document", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Error {
-      get {
-        object obj = ResourceManager.GetObject("Error", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Icon ErrorIcon {
-      get {
-        object obj = ResourceManager.GetObject("ErrorIcon", resourceCulture);
-        return ((System.Drawing.Icon)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap File {
-      get {
-        object obj = ResourceManager.GetObject("File", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Icon HeuristicLab {
-      get {
-        object obj = ResourceManager.GetObject("HeuristicLab", resourceCulture);
-        return ((System.Drawing.Icon)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap HeuristicLabBanner {
-      get {
-        object obj = ResourceManager.GetObject("HeuristicLabBanner", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap HeuristicLabLogo {
-      get {
-        object obj = ResourceManager.GetObject("HeuristicLabLogo", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Install {
-      get {
-        object obj = ResourceManager.GetObject("Install", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Internet {
-      get {
-        object obj = ResourceManager.GetObject("Internet", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    /// <summary>
-    ///   Looks up a localized string similar to HeuristicLab is free software: you can redistribute it and/or modify
-    ///it under the terms of the GNU General Public License as published by
-    ///the Free Software Foundation, either version 3 of the License, or
-    ///(at your option) any later version.
-    ///
-    ///HeuristicLab is distributed in the hope that it will be useful,
-    ///but WITHOUT ANY WARRANTY; without even the implied warranty of
-    ///MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    ///GNU General Public License for more details.
-    ///
-    ///You should have received a copy of t [rest of string was truncated]&quot;;.
-    /// </summary>
-    internal static string LicenseText {
-      get {
-        return ResourceManager.GetString("LicenseText", resourceCulture);
-      }
-    }
-
-    internal static System.Drawing.Bitmap NetworkConnections {
-      get {
-        object obj = ResourceManager.GetObject("NetworkConnections", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Plugin {
-      get {
-        object obj = ResourceManager.GetObject("Plugin", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap PublishToWeb {
-      get {
-        object obj = ResourceManager.GetObject("PublishToWeb", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Remove {
-      get {
-        object obj = ResourceManager.GetObject("Remove", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap Repeat {
-      get {
-        object obj = ResourceManager.GetObject("Repeat", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Icon Setup_Install {
-      get {
-        object obj = ResourceManager.GetObject("Setup_Install", resourceCulture);
-        return ((System.Drawing.Icon)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap ShowDetails {
-      get {
-        object obj = ResourceManager.GetObject("ShowDetails", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-
-    internal static System.Drawing.Bitmap ShowIcons {
-      get {
-        object obj = ResourceManager.GetObject("ShowIcons", resourceCulture);
-        return ((System.Drawing.Bitmap)(obj));
-      }
-    }
-  }
 }
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.resx
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.resx	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Resources.resx	(revision 6413)
@@ -113,10 +113,10 @@
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
   <data name="Add" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>Resources\VS2008ImageLibrary_CommonElements_Actions_Add.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -194,3 +194,6 @@
     <value>Resources\show_icons.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="UpdateAvailable" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>resources\updateavailable.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
Index: /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Starter/StarterForm.cs
===================================================================
--- /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Starter/StarterForm.cs	(revision 6412)
+++ /trunk/sources/HeuristicLab.PluginInfrastructure/3.3/Starter/StarterForm.cs	(revision 6413)
@@ -29,4 +29,5 @@
 using HeuristicLab.PluginInfrastructure.Advanced;
 using HeuristicLab.PluginInfrastructure.Manager;
+using System.Threading.Tasks;
 
 namespace HeuristicLab.PluginInfrastructure.Starter {
@@ -36,4 +37,7 @@
   /// </summary>
   public partial class StarterForm : Form {
+    private const string pluginManagerItemName = "Plugin Manager";
+    private const string updatePluginsItemName = "Updates Available";
+
 
     private ListViewItem pluginManagerListViewItem;
@@ -41,4 +45,5 @@
     private PluginManager pluginManager;
     private SplashScreen splashScreen;
+    private bool updatesAvailable = false;
 
     /// <summary>
@@ -50,5 +55,7 @@
       InitializeComponent();
       largeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.HeuristicLab.ToBitmap());
+      largeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.UpdateAvailable.ToBitmap());
       smallImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.HeuristicLab.ToBitmap());
+      smallImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.UpdateAvailable.ToBitmap());
       FileVersionInfo pluginInfrastructureVersion = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location);
       Text = "HeuristicLab " + pluginInfrastructureVersion.FileVersion;
@@ -61,4 +68,29 @@
       pluginManager.DiscoverAndCheckPlugins();
       UpdateApplicationsList();
+
+      CheckUpdatesAvailableAsync(pluginPath);
+    }
+
+    private void CheckUpdatesAvailableAsync(string pluginPath) {
+      var task = Task.Factory.StartNew<bool>(() => {
+        var installationManager = new InstallationManager(pluginPath);
+        IEnumerable<IPluginDescription> installedPlugins = pluginManager.Plugins.OfType<IPluginDescription>();
+        var remotePlugins = installationManager.GetRemotePluginList();
+        // if there is a local plugin with same name and same major and minor version then it's an update
+        var pluginsToUpdate = from remotePlugin in remotePlugins
+                              let matchingLocalPlugins = from installedPlugin in installedPlugins
+                                                         where installedPlugin.Name == remotePlugin.Name
+                                                         where installedPlugin.Version.Major == remotePlugin.Version.Major
+                                                         where installedPlugin.Version.Minor == remotePlugin.Version.Minor
+                                                         where Util.IsNewerThan(remotePlugin, installedPlugin)
+                                                         select installedPlugin
+                              where matchingLocalPlugins.Count() > 0
+                              select remotePlugin;
+        return pluginsToUpdate.Count() > 0;
+      });
+      task.ContinueWith(t => {
+        updatesAvailable = t.Result;
+        UpdateApplicationsList();
+      }, TaskContinuationOptions.NotOnFaulted);
     }
 
@@ -85,5 +117,5 @@
       if (applicationsListView.SelectedItems.Count > 0) {
         ListViewItem selected = applicationsListView.SelectedItems[0];
-        if (selected == pluginManagerListViewItem) {
+        if (selected.Text == pluginManagerItemName) {
           if (pluginManager.Plugins.Any(x => x.PluginState == PluginState.Loaded)) {
             MessageBox.Show("Installation Manager cannot be started while another HeuristicLab application is active." + Environment.NewLine +
@@ -102,4 +134,21 @@
             }
           }
+        } else if (selected.Text == updatePluginsItemName) {
+          if (pluginManager.Plugins.Any(x => x.PluginState == PluginState.Loaded)) {
+            MessageBox.Show("Updating is not possible while another HeuristicLab application is active." + Environment.NewLine +
+              "Please stop all active HeuristicLab applications and try again.", "Update plugins",
+              MessageBoxButtons.OK, MessageBoxIcon.Information);
+          } else {
+            try {
+              Cursor = Cursors.AppStarting;
+              using (PluginUpdaterForm form = new PluginUpdaterForm(pluginManager)) {
+                form.ShowDialog(this);
+              }
+              UpdateApplicationsList();
+            }
+            finally {
+              Cursor = Cursors.Arrow;
+            }
+          }
         } else {
           ApplicationDescription app = (ApplicationDescription)applicationsListView.SelectedItems[0].Tag;
@@ -110,27 +159,49 @@
 
     private void UpdateApplicationsList() {
-      applicationsListView.Items.Clear();
-      FileVersionInfo pluginInfrastructureVersion = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location);
-      pluginManagerListViewItem = new ListViewItem("Plugin Manager", 0);
-      pluginManagerListViewItem.Group = applicationsListView.Groups["Plugin Management"];
-      pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, pluginInfrastructureVersion.FileVersion));
-      pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, "Install, upgrade or delete plugins"));
-      pluginManagerListViewItem.ToolTipText = "Install, upgrade or delete plugins";
-
-      applicationsListView.Items.Add(pluginManagerListViewItem);
-
-      foreach (ApplicationDescription info in pluginManager.Applications) {
-        ListViewItem item = new ListViewItem(info.Name, 0);
-        item.Tag = info;
-        item.Group = applicationsListView.Groups["Applications"];
-        item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Version.ToString()));
-        item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Description));
-        item.ToolTipText = info.Description;
-        applicationsListView.Items.Add(item);
-      }
-      foreach (ColumnHeader column in applicationsListView.Columns) {
-        if (applicationsListView.Items.Count > 0)
-          column.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
-        else column.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+      if (InvokeRequired) Invoke((Action)UpdateApplicationsList);
+      else {
+        applicationsListView.Items.Clear();
+        AddPluginManagerItem();
+        AddUpdatePluginsItem();
+
+        foreach (ApplicationDescription info in pluginManager.Applications) {
+          ListViewItem item = new ListViewItem(info.Name, 0);
+          item.Tag = info;
+          item.Group = applicationsListView.Groups["Applications"];
+          item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Version.ToString()));
+          item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Description));
+          item.ToolTipText = info.Description;
+          applicationsListView.Items.Add(item);
+        }
+        foreach (ColumnHeader column in applicationsListView.Columns) {
+          if (applicationsListView.Items.Count > 0)
+            column.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
+          else column.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
+        }
+      }
+    }
+
+    private void AddPluginManagerItem() {
+      if (HeuristicLab.PluginInfrastructure.Properties.Settings.Default.ShowPluginUploadControls) {
+        FileVersionInfo pluginInfrastructureVersion = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location);
+        pluginManagerListViewItem = new ListViewItem(pluginManagerItemName, 0);
+        pluginManagerListViewItem.Group = applicationsListView.Groups["Plugin Management"];
+        pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, pluginInfrastructureVersion.FileVersion));
+        pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, "Install, upgrade or delete plugins"));
+        pluginManagerListViewItem.ToolTipText = "Install, upgrade or delete plugins";
+
+        applicationsListView.Items.Add(pluginManagerListViewItem);
+      }
+    }
+
+    private void AddUpdatePluginsItem() {
+      if (updatesAvailable) {
+        var updateListViewItem = new ListViewItem(updatePluginsItemName, 1);
+        updateListViewItem.Group = applicationsListView.Groups["Plugin Management"];
+        updateListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(updateListViewItem, ""));
+        updateListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(updateListViewItem, "Download and install updates"));
+        updateListViewItem.ToolTipText = "Download and install updates";
+
+        applicationsListView.Items.Add(updateListViewItem);
       }
     }
