Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/HeuristicLab.DeploymentService.AdminClient.csproj
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/HeuristicLab.DeploymentService.AdminClient.csproj	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/HeuristicLab.DeploymentService.AdminClient.csproj	(revision 3045)
@@ -94,4 +94,16 @@
       <DependentUpon>PluginComparisonView.cs</DependentUpon>
     </Compile>
+    <Compile Include="PluginEditor.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="PluginEditor.Designer.cs">
+      <DependentUpon>PluginEditor.cs</DependentUpon>
+    </Compile>
+    <Compile Include="PluginListView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="PluginListView.Designer.cs">
+      <DependentUpon>PluginListView.cs</DependentUpon>
+    </Compile>
     <Compile Include="PluginView.cs">
       <SubType>UserControl</SubType>
@@ -113,10 +125,4 @@
     <Compile Include="MainForm.cs">
       <SubType>Form</SubType>
-    </Compile>
-    <Compile Include="PluginListView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="PluginListView.Designer.cs">
-      <DependentUpon>PluginListView.cs</DependentUpon>
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
@@ -157,4 +163,10 @@
       <DependentUpon>PluginComparisonView.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="PluginEditor.resx">
+      <DependentUpon>PluginEditor.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="PluginListView.resx">
+      <DependentUpon>PluginListView.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="PluginView.resx">
       <DependentUpon>PluginView.cs</DependentUpon>
@@ -162,7 +174,4 @@
     <EmbeddedResource Include="ProductEditor.resx">
       <DependentUpon>ProductEditor.cs</DependentUpon>
-    </EmbeddedResource>
-    <EmbeddedResource Include="PluginListView.resx">
-      <DependentUpon>PluginListView.cs</DependentUpon>
     </EmbeddedResource>
   </ItemGroup>
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/MainForm.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/MainForm.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/MainForm.cs	(revision 3045)
@@ -16,5 +16,5 @@
     protected override void OnInitialized(EventArgs e) {
       base.OnInitialized(e);
-      (new PluginListView()).Show();
+      (new PluginEditor()).Show();
     }
 
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/OpenServerProductsEditMenuItem.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/OpenServerProductsEditMenuItem.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/OpenServerProductsEditMenuItem.cs	(revision 3045)
@@ -8,9 +8,9 @@
   class OpenServerProductsEditorMenuItem : HeuristicLab.MainForm.WindowsForms.MenuItem, IUserInterfaceItemProvider {
     public override string Name {
-      get { return "Edit products"; }
+      get { return "Edit Products"; }
     }
 
     public override IEnumerable<string> Structure {
-      get { return new string[] { "Plugin server" }; }
+      get { return new string[] { "Plugin Server" }; }
     }
 
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.Designer.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.Designer.cs	(revision 3045)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.Designer.cs	(revision 3045)
@@ -0,0 +1,126 @@
+﻿namespace HeuristicLab.DeploymentService.AdminClient {
+  partial class PluginEditor {
+    /// <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 Component 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.listView = new System.Windows.Forms.ListView();
+      this.nameHeader = new System.Windows.Forms.ColumnHeader();
+      this.localVersion = new System.Windows.Forms.ColumnHeader();
+      this.serverVersion = new System.Windows.Forms.ColumnHeader();
+      this.imageList = new System.Windows.Forms.ImageList(this.components);
+      this.refreshButton = new System.Windows.Forms.Button();
+      this.uploadButton = new System.Windows.Forms.Button();
+      this.SuspendLayout();
+      // 
+      // listView
+      // 
+      this.listView.Activation = System.Windows.Forms.ItemActivation.TwoClick;
+      this.listView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+                  | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.listView.CheckBoxes = true;
+      this.listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+            this.nameHeader,
+            this.localVersion,
+            this.serverVersion});
+      this.listView.Enabled = false;
+      this.listView.FullRowSelect = true;
+      this.listView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+      this.listView.Location = new System.Drawing.Point(0, 30);
+      this.listView.Name = "listView";
+      this.listView.ShowGroups = false;
+      this.listView.Size = new System.Drawing.Size(536, 446);
+      this.listView.StateImageList = this.imageList;
+      this.listView.TabIndex = 0;
+      this.listView.UseCompatibleStateImageBehavior = false;
+      this.listView.View = System.Windows.Forms.View.Details;
+      this.listView.ItemActivate += new System.EventHandler(this.listView_ItemActivate);
+      this.listView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);
+      // 
+      // nameHeader
+      // 
+      this.nameHeader.Text = "Name";
+      this.nameHeader.Width = 188;
+      // 
+      // localVersion
+      // 
+      this.localVersion.Text = "Local version";
+      this.localVersion.Width = 100;
+      // 
+      // serverVersion
+      // 
+      this.serverVersion.Text = "Server version";
+      this.serverVersion.Width = 100;
+      // 
+      // imageList
+      // 
+      this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
+      this.imageList.ImageSize = new System.Drawing.Size(16, 16);
+      this.imageList.TransparentColor = System.Drawing.Color.Transparent;
+      // 
+      // refreshButton
+      // 
+      this.refreshButton.Location = new System.Drawing.Point(3, 3);
+      this.refreshButton.Name = "refreshButton";
+      this.refreshButton.Size = new System.Drawing.Size(75, 23);
+      this.refreshButton.TabIndex = 6;
+      this.refreshButton.Text = "Refresh";
+      this.refreshButton.UseVisualStyleBackColor = true;
+      this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
+      // 
+      // uploadButton
+      // 
+      this.uploadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.uploadButton.Location = new System.Drawing.Point(3, 482);
+      this.uploadButton.Name = "uploadButton";
+      this.uploadButton.Size = new System.Drawing.Size(75, 23);
+      this.uploadButton.TabIndex = 7;
+      this.uploadButton.Text = "Upload";
+      this.uploadButton.UseVisualStyleBackColor = true;
+      this.uploadButton.Click += new System.EventHandler(this.uploadButton_Click);
+      // 
+      // PluginListView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.uploadButton);
+      this.Controls.Add(this.refreshButton);
+      this.Controls.Add(this.listView);
+      this.Name = "PluginListView";
+      this.Size = new System.Drawing.Size(539, 508);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.ListView listView;
+    private System.Windows.Forms.ColumnHeader nameHeader;
+    private System.Windows.Forms.ColumnHeader localVersion;
+    private System.Windows.Forms.ColumnHeader serverVersion;
+    private System.Windows.Forms.Button refreshButton;
+    private System.Windows.Forms.Button uploadButton;
+    private System.Windows.Forms.ImageList imageList;
+  }
+}
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.cs	(revision 3045)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.cs	(revision 3045)
@@ -0,0 +1,263 @@
+﻿using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+using PluginDeploymentService = HeuristicLab.PluginInfrastructure.Advanced.DeploymentService;
+using HeuristicLab.PluginInfrastructure.Manager;
+using System.ServiceModel;
+using ICSharpCode.SharpZipLib.Zip;
+using System.IO;
+
+namespace HeuristicLab.DeploymentService.AdminClient {
+  public partial class PluginEditor : HeuristicLab.MainForm.WindowsForms.View {
+    private Dictionary<IPluginDescription, PluginDeploymentService.PluginDescription> localAndServerPlugins;
+    private BackgroundWorker pluginUploadWorker;
+    private BackgroundWorker updateServerPluginsWorker;
+
+    public PluginEditor() {
+      InitializeComponent();
+      imageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.Assembly);
+      imageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.ArrowUp);
+      Caption = "Plugins";
+
+      localAndServerPlugins = new Dictionary<IPluginDescription, PluginDeploymentService.PluginDescription>();
+
+      #region initialize backgroundworkers
+      pluginUploadWorker = new BackgroundWorker();
+      pluginUploadWorker.DoWork += new DoWorkEventHandler(pluginUploadWorker_DoWork);
+      pluginUploadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(pluginUploadWorker_RunWorkerCompleted);
+
+      updateServerPluginsWorker = new BackgroundWorker();
+      updateServerPluginsWorker.DoWork += new DoWorkEventHandler(updateServerPluginsWorker_DoWork);
+      updateServerPluginsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(updateServerPluginsWorker_RunWorkerCompleted);
+      #endregion
+    }
+
+    #region refresh plugins from server backgroundworker
+    void updateServerPluginsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      if (!e.Cancelled && e.Result != null) {
+        // refresh local plugins
+        localAndServerPlugins.Clear();
+        foreach (var plugin in ApplicationManager.Manager.Plugins) {
+          localAndServerPlugins.Add(plugin, null);
+        }
+        // refresh server plugins (find matching local plugins)
+        var plugins = (PluginDeploymentService.PluginDescription[])e.Result;
+        foreach (var plugin in plugins) {
+          var matchingLocalPlugin = (from localPlugin in localAndServerPlugins.Keys
+                                     where localPlugin.Name == plugin.Name
+                                     where localPlugin.Version == localPlugin.Version
+                                     select localPlugin).SingleOrDefault();
+          if (matchingLocalPlugin != null) {
+            localAndServerPlugins[matchingLocalPlugin] = plugin;
+          }
+        }
+        // refresh the list view with plugins
+        listView.Items.Clear();
+        foreach (var pair in localAndServerPlugins) {
+          var item = MakeListViewItem(pair.Key);
+          listView.Items.Add(item);
+        }
+        UpdateControlsConnectedState();
+      } else {
+        UpdateControlsDisconnectedState();
+      }
+      // make sure cursor is set correctly
+      Cursor = Cursors.Default;
+    }
+
+    void updateServerPluginsWorker_DoWork(object sender, DoWorkEventArgs e) {
+      try {
+        var client = PluginDeploymentService.UpdateClientFactory.CreateClient();
+        e.Result = client.GetPlugins();
+        e.Cancel = false;
+      }
+      catch (EndpointNotFoundException) {
+        e.Result = null;
+        e.Cancel = true;
+      }
+      catch (FaultException) {
+        e.Result = null;
+        e.Cancel = true;
+      }
+    }
+    #endregion
+
+    #region upload plugins to server backgroundworker
+    void pluginUploadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      Cursor = Cursors.Default;
+      if (e.Cancelled) {
+        UpdateControlsDisconnectedState();
+      } else {
+        UpdateControlsConnectedState();
+        // start another async call to refresh plugin information from server
+        RefreshPluginsAsync();
+      }
+    }
+
+    void pluginUploadWorker_DoWork(object sender, DoWorkEventArgs e) {
+      try {
+        var selectedPlugins = (IEnumerable<IPluginDescription>)e.Argument;
+        PluginDeploymentService.AdminClient adminClient = PluginDeploymentService.AdminClientFactory.CreateClient();
+
+        foreach (var plugin in IteratePlugins(selectedPlugins)) {
+         adminClient.DeployPlugin(MakePluginDescription(plugin), CreateZipPackage(plugin));
+        }
+        e.Cancel = false;
+      }
+      catch (EndpointNotFoundException) {
+        e.Cancel = true;
+      }
+      catch (FaultException) {
+        e.Cancel = true;
+      }
+    }
+    #endregion
+
+
+    #region button events
+    private void uploadButton_Click(object sender, EventArgs e) {
+      var selectedPlugins = from item in listView.Items.Cast<ListViewItem>()
+                            where item.Checked
+                            where item.Tag is IPluginDescription
+                            select item.Tag as IPluginDescription;
+      if (selectedPlugins.Count() > 0) {
+        Cursor = Cursors.AppStarting;
+        DisableControl();
+        pluginUploadWorker.RunWorkerAsync(selectedPlugins.ToList());
+      }
+    }
+
+    private void connectButton_Click(object sender, EventArgs e) {
+      var connectionSetupView = new ConnectionSetupView();
+      connectionSetupView.Show();
+    }
+
+    private void refreshButton_Click(object sender, EventArgs e) {
+      DisableControl();
+      RefreshPluginsAsync();
+    }
+
+    #endregion
+
+    #region item list events
+    private void listView_ItemActivate(object sender, EventArgs e) {
+      foreach (var item in listView.SelectedItems) {
+        var plugin = (IPluginDescription)((ListViewItem)item).Tag;
+        var compView = new PluginComparisonView(plugin, localAndServerPlugins[plugin]);
+        compView.Show();
+      }
+    }
+
+    private void listView_ItemChecked(object sender, ItemCheckedEventArgs e) {      
+      // also check all dependencies
+      if (e.Item.Checked) {
+        uploadButton.Enabled = true;
+        var plugin = (IPluginDescription)e.Item.Tag;
+        foreach (var dep in plugin.Dependencies) {
+          var depItem = FindItemForPlugin(dep);
+          if (!depItem.Checked) depItem.Checked = true;
+        }
+      } else {
+        uploadButton.Enabled = (from i in listView.Items.Cast<ListViewItem>()
+                                where i.Checked
+                                select i).Any();
+        // also uncheck all dependent plugins
+        var plugin = (IPluginDescription)e.Item.Tag;
+        foreach (ListViewItem item in listView.Items) {
+          var dep = (IPluginDescription)item.Tag;
+          if (dep.Dependencies.Contains(plugin) && item.Checked) {
+            item.Checked = false;
+          }
+        }
+      }
+    }
+    #endregion
+
+    #region helper methods
+    private byte[] CreateZipPackage(IPluginDescription plugin) {
+      using (MemoryStream stream = new MemoryStream()) {
+        ZipFile zipFile = new ZipFile(stream);
+        zipFile.BeginUpdate();
+        foreach (var file in plugin.Files) {
+          zipFile.Add(file.Name);
+        }
+        zipFile.CommitUpdate();
+        stream.Seek(0, SeekOrigin.Begin);
+        return stream.GetBuffer();
+      }
+    }
+
+    private ListViewItem MakeListViewItem(IPluginDescription plugin) {
+      ListViewItem item;
+      if (localAndServerPlugins[plugin] != null) {
+        item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), localAndServerPlugins[plugin].Version.ToString() });
+      } else {
+        item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), string.Empty });
+      }
+      item.Tag = plugin;
+      item.Checked = false;
+      return item;
+    }
+
+    private ListViewItem FindItemForPlugin(IPluginDescription dep) {
+      return (from i in listView.Items.Cast<ListViewItem>()
+              where i.Tag == dep
+              select i).Single();
+    }
+
+    private PluginDeploymentService.PluginDescription MakePluginDescription(IPluginDescription plugin) {
+      var dependencies = from dep in plugin.Dependencies
+                         select MakePluginDescription(dep);
+      return new PluginDeploymentService.PluginDescription(plugin.Name, plugin.Version, dependencies, plugin.ContactName, plugin.ContactEmail, plugin.LicenseText);
+    }
+
+    private IEnumerable<IPluginDescription> IteratePlugins(IEnumerable<IPluginDescription> plugins) {
+      foreach (var plugin in plugins) {
+        foreach (var dependency in IteratePlugins(plugin.Dependencies)) {
+          yield return dependency;
+        }
+        yield return plugin;
+      }
+    }
+
+    // start background process to refresh the plugin list (local and server)
+    private void RefreshPluginsAsync() {
+      Cursor = Cursors.AppStarting;
+      DisableControl();
+      updateServerPluginsWorker.RunWorkerAsync();
+    }
+
+    // is called by all methods that start a background process
+    // controls must be enabled manuall again when the backgroundworker finishes
+    private void DisableControl() {
+      MainFormManager.GetMainForm<MainForm>().ShowProgressBar();
+      foreach (Control ctrl in Controls)
+        ctrl.Enabled = false;
+    }
+
+    private void UpdateControlsDisconnectedState() {
+      refreshButton.Enabled = false;
+
+      localAndServerPlugins.Clear();
+      listView.Items.Clear();
+      listView.Enabled = false;
+      uploadButton.Enabled = false;
+      MainFormManager.GetMainForm<MainForm>().HideProgressBar();
+    }
+
+    private void UpdateControlsConnectedState() {
+      refreshButton.Enabled = true;
+      listView.Enabled = true;
+      uploadButton.Enabled = false;
+      MainFormManager.GetMainForm<MainForm>().HideProgressBar();
+    }
+    #endregion
+  }
+}
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.resx
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.resx	(revision 3045)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginEditor.resx	(revision 3045)
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.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>
+  </resheader>
+  <metadata name="imageList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.Designer.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.Designer.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.Designer.cs	(revision 3045)
@@ -1,60 +1,51 @@
-﻿namespace HeuristicLab.DeploymentService.AdminClient {
-  partial class PluginListView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
+﻿namespace HeuristicLab.DeploymentService.AdminClient
+{
+	partial class PluginListView
+	{
+		/// <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);
-    }
+		/// <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 Component Designer generated code
+		#region Component 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();
+		/// <summary> 
+		/// Required method for Designer support - do not modify 
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
       this.listView = new System.Windows.Forms.ListView();
       this.nameHeader = new System.Windows.Forms.ColumnHeader();
-      this.localVersion = new System.Windows.Forms.ColumnHeader();
-      this.serverVersion = new System.Windows.Forms.ColumnHeader();
-      this.imageList = new System.Windows.Forms.ImageList(this.components);
-      this.refreshButton = new System.Windows.Forms.Button();
-      this.uploadButton = new System.Windows.Forms.Button();
+      this.versionHeader = new System.Windows.Forms.ColumnHeader();
       this.SuspendLayout();
       // 
       // listView
       // 
-      this.listView.Activation = System.Windows.Forms.ItemActivation.TwoClick;
-      this.listView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
       this.listView.CheckBoxes = true;
       this.listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
             this.nameHeader,
-            this.localVersion,
-            this.serverVersion});
-      this.listView.Enabled = false;
+            this.versionHeader});
+      this.listView.Dock = System.Windows.Forms.DockStyle.Fill;
       this.listView.FullRowSelect = true;
-      this.listView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
-      this.listView.Location = new System.Drawing.Point(0, 30);
+      this.listView.Location = new System.Drawing.Point(0, 0);
       this.listView.Name = "listView";
-      this.listView.ShowGroups = false;
-      this.listView.Size = new System.Drawing.Size(536, 446);
-      this.listView.StateImageList = this.imageList;
+      this.listView.Size = new System.Drawing.Size(341, 320);
       this.listView.TabIndex = 0;
       this.listView.UseCompatibleStateImageBehavior = false;
       this.listView.View = System.Windows.Forms.View.Details;
-      this.listView.ItemActivate += new System.EventHandler(this.listView_ItemActivate);
       this.listView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);
       // 
@@ -62,42 +53,8 @@
       // 
       this.nameHeader.Text = "Name";
-      this.nameHeader.Width = 188;
       // 
-      // localVersion
+      // versionHeader
       // 
-      this.localVersion.Text = "Local version";
-      this.localVersion.Width = 100;
-      // 
-      // serverVersion
-      // 
-      this.serverVersion.Text = "Server version";
-      this.serverVersion.Width = 100;
-      // 
-      // imageList
-      // 
-      this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
-      this.imageList.ImageSize = new System.Drawing.Size(16, 16);
-      this.imageList.TransparentColor = System.Drawing.Color.Transparent;
-      // 
-      // refreshButton
-      // 
-      this.refreshButton.Location = new System.Drawing.Point(3, 3);
-      this.refreshButton.Name = "refreshButton";
-      this.refreshButton.Size = new System.Drawing.Size(75, 23);
-      this.refreshButton.TabIndex = 6;
-      this.refreshButton.Text = "Refresh";
-      this.refreshButton.UseVisualStyleBackColor = true;
-      this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
-      // 
-      // uploadButton
-      // 
-      this.uploadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.uploadButton.Location = new System.Drawing.Point(3, 482);
-      this.uploadButton.Name = "uploadButton";
-      this.uploadButton.Size = new System.Drawing.Size(75, 23);
-      this.uploadButton.TabIndex = 7;
-      this.uploadButton.Text = "Upload";
-      this.uploadButton.UseVisualStyleBackColor = true;
-      this.uploadButton.Click += new System.EventHandler(this.uploadButton_Click);
+      this.versionHeader.Text = "Version";
       // 
       // PluginListView
@@ -105,22 +62,16 @@
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.uploadButton);
-      this.Controls.Add(this.refreshButton);
       this.Controls.Add(this.listView);
       this.Name = "PluginListView";
-      this.Size = new System.Drawing.Size(539, 508);
+      this.Size = new System.Drawing.Size(341, 320);
       this.ResumeLayout(false);
 
-    }
+		}
 
-    #endregion
+		#endregion
 
     private System.Windows.Forms.ListView listView;
     private System.Windows.Forms.ColumnHeader nameHeader;
-    private System.Windows.Forms.ColumnHeader localVersion;
-    private System.Windows.Forms.ColumnHeader serverVersion;
-    private System.Windows.Forms.Button refreshButton;
-    private System.Windows.Forms.Button uploadButton;
-    private System.Windows.Forms.ImageList imageList;
-  }
+    private System.Windows.Forms.ColumnHeader versionHeader;
+	}
 }
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/PluginListView.cs	(revision 3045)
@@ -7,257 +7,115 @@
 using System.Text;
 using System.Windows.Forms;
-using HeuristicLab.MainForm;
 using HeuristicLab.PluginInfrastructure;
-using PluginDeploymentService = HeuristicLab.PluginInfrastructure.Advanced.DeploymentService;
-using HeuristicLab.PluginInfrastructure.Manager;
-using System.ServiceModel;
-using ICSharpCode.SharpZipLib.Zip;
-using System.IO;
 
 namespace HeuristicLab.DeploymentService.AdminClient {
-  public partial class PluginListView : HeuristicLab.MainForm.WindowsForms.View {
-    private Dictionary<IPluginDescription, PluginDeploymentService.PluginDescription> localAndServerPlugins;
-    private BackgroundWorker pluginUploadWorker;
-    private BackgroundWorker updateServerPluginsWorker;
+  public partial class PluginListView : UserControl {
+    public event ItemCheckedEventHandler ItemChecked;
+
+    private IEnumerable<IPluginDescription> plugins;
+    public IEnumerable<IPluginDescription> Plugins {
+      get { return plugins; }
+      set {
+        plugins = value;
+        UpdateControls();
+      }
+    }
+
+    public IEnumerable<IPluginDescription> CheckedPlugins {
+      get {
+        return from item in listView.Items.OfType<ListViewItem>()
+               where item.Checked
+               select item.Tag as IPluginDescription;
+      }
+    }
+
+    private bool suppressItemCheckedEvents = false;
 
     public PluginListView() {
       InitializeComponent();
-      imageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.Assembly);
-      imageList.Images.Add(HeuristicLab.Common.Resources.VS2008ImageLibrary.ArrowUp);
-      Caption = "Plugins";
-
-      localAndServerPlugins = new Dictionary<IPluginDescription, PluginDeploymentService.PluginDescription>();
-
-      #region initialize backgroundworkers
-      pluginUploadWorker = new BackgroundWorker();
-      pluginUploadWorker.DoWork += new DoWorkEventHandler(pluginUploadWorker_DoWork);
-      pluginUploadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(pluginUploadWorker_RunWorkerCompleted);
-
-      updateServerPluginsWorker = new BackgroundWorker();
-      updateServerPluginsWorker.DoWork += new DoWorkEventHandler(updateServerPluginsWorker_DoWork);
-      updateServerPluginsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(updateServerPluginsWorker_RunWorkerCompleted);
-      #endregion
     }
 
-    #region refresh plugins from server backgroundworker
-    void updateServerPluginsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
-      if (!e.Cancelled && e.Result != null) {
-        // refresh local plugins
-        localAndServerPlugins.Clear();
-        foreach (var plugin in ApplicationManager.Manager.Plugins) {
-          localAndServerPlugins.Add(plugin, null);
-        }
-        // refresh server plugins (find matching local plugins)
-        var plugins = (PluginDeploymentService.PluginDescription[])e.Result;
-        foreach (var plugin in plugins) {
-          var matchingLocalPlugin = (from localPlugin in localAndServerPlugins.Keys
-                                     where localPlugin.Name == plugin.Name
-                                     where localPlugin.Version == localPlugin.Version
-                                     select localPlugin).SingleOrDefault();
-          if (matchingLocalPlugin != null) {
-            localAndServerPlugins[matchingLocalPlugin] = plugin;
-          }
-        }
-        // refresh the list view with plugins
-        listView.Items.Clear();
-        foreach (var pair in localAndServerPlugins) {
-          var item = MakeListViewItem(pair.Key);
-          listView.Items.Add(item);
-        }
-        UpdateControlsConnectedState();
-      } else {
-        UpdateControlsDisconnectedState();
-      }
-      // make sure cursor is set correctly
-      Cursor = Cursors.Default;
-    }
-
-    void updateServerPluginsWorker_DoWork(object sender, DoWorkEventArgs e) {
-      try {
-        var client = PluginDeploymentService.UpdateClientFactory.CreateClient();
-        e.Result = client.GetPlugins();
-        e.Cancel = false;
-      }
-      catch (EndpointNotFoundException) {
-        e.Result = null;
-        e.Cancel = true;
-      }
-      catch (FaultException) {
-        e.Result = null;
-        e.Cancel = true;
-      }
-    }
-    #endregion
-
-    #region upload plugins to server backgroundworker
-    void pluginUploadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
-      Cursor = Cursors.Default;
-      if (e.Cancelled) {
-        UpdateControlsDisconnectedState();
-      } else {
-        UpdateControlsConnectedState();
-        // start another async call to refresh plugin information from server
-        RefreshPluginsAsync();
+    public void CheckPlugin(IPluginDescription plugin) {
+      var items = FindItemsForPlugin(plugin);
+      if (items.Count() == 0) throw new ArgumentException();
+      var item = items.Single();
+      if (!item.Checked) {
+        suppressItemCheckedEvents = true;
+        item.Checked = true;
+        suppressItemCheckedEvents = false;
       }
     }
 
-    void pluginUploadWorker_DoWork(object sender, DoWorkEventArgs e) {
-      try {
-        var selectedPlugins = (IEnumerable<IPluginDescription>)e.Argument;
-        PluginDeploymentService.AdminClient adminClient = PluginDeploymentService.AdminClientFactory.CreateClient();
-
-        foreach (var plugin in IteratePlugins(selectedPlugins)) {
-         adminClient.DeployPlugin(MakePluginDescription(plugin), CreateZipPackage(plugin));
+    private void UpdateControls() {
+      if (plugins != null) {
+        listView.Items.Clear();
+        suppressItemCheckedEvents = true;
+        foreach (var plugin in plugins) {
+          listView.Items.Add(CreateListViewItem(plugin));
         }
-        e.Cancel = false;
-      }
-      catch (EndpointNotFoundException) {
-        e.Cancel = true;
-      }
-      catch (FaultException) {
-        e.Cancel = true;
-      }
-    }
-    #endregion
-
-
-    #region button events
-    private void uploadButton_Click(object sender, EventArgs e) {
-      var selectedPlugins = from item in listView.Items.Cast<ListViewItem>()
-                            where item.Checked
-                            where item.Tag is IPluginDescription
-                            select item.Tag as IPluginDescription;
-      if (selectedPlugins.Count() > 0) {
-        Cursor = Cursors.AppStarting;
-        DisableControl();
-        pluginUploadWorker.RunWorkerAsync(selectedPlugins.ToList());
+        suppressItemCheckedEvents = false;
       }
     }
 
-    private void connectButton_Click(object sender, EventArgs e) {
-      var connectionSetupView = new ConnectionSetupView();
-      connectionSetupView.Show();
+    private ListViewItem CreateListViewItem(IPluginDescription plugin) {
+      var item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString() });
+      item.Tag = plugin;
+      return item;
     }
 
-    private void refreshButton_Click(object sender, EventArgs e) {
-      DisableControl();
-      RefreshPluginsAsync();
+    private void listView_ItemChecked(object sender, ItemCheckedEventArgs e) {
+      if (suppressItemCheckedEvents) return;
+      if (e.Item.Checked) {
+        // also check all dependencies
+        suppressItemCheckedEvents = true;
+        var dependencies = GetAllDependencies(e.Item.Tag as IPluginDescription);
+        foreach (var dep in dependencies) {
+          var item = FindItemsForPlugin(dep).Single();
+          if (!item.Checked) item.Checked = true;
+        }
+        suppressItemCheckedEvents = false;
+      } else {
+        // also uncheck all dependencies
+        suppressItemCheckedEvents = true;
+        var dependents = GetAllDependents(e.Item.Tag as IPluginDescription);
+        foreach (var dep in dependents) {
+          var item = FindItemsForPlugin(dep).Single();
+          if (item.Checked) item.Checked = false;
+        }
+        suppressItemCheckedEvents = false;
+      }
+      OnItemChecked(e);
     }
 
-    #endregion
+    private IEnumerable<ListViewItem> FindItemsForPlugin(IPluginDescription plugin) {
+      return from item in listView.Items.OfType<ListViewItem>()
+             let p = item.Tag as IPluginDescription
+             where p.Name == plugin.Name
+             where p.Version == plugin.Version
+             select item;
+    }
 
-    #region item list events
-    private void listView_ItemActivate(object sender, EventArgs e) {
-      foreach (var item in listView.SelectedItems) {
-        var plugin = (IPluginDescription)((ListViewItem)item).Tag;
-        var compView = new PluginComparisonView(plugin, localAndServerPlugins[plugin]);
-        compView.Show();
+    private IEnumerable<IPluginDescription> GetAllDependents(IPluginDescription plugin) {
+      return from p in plugins
+             let matchingEntries = from dep in GetAllDependencies(p)
+                                   where dep.Name == plugin.Name
+                                   where dep.Version == plugin.Version
+                                   select dep
+             where matchingEntries.Any()
+             select p;
+    }
+
+    private IEnumerable<IPluginDescription> GetAllDependencies(IPluginDescription plugin) {
+      foreach (var dep in plugin.Dependencies) {
+        foreach (var recDep in GetAllDependencies(dep)) {
+          yield return recDep;
+        }
+        yield return dep;
       }
     }
 
-    private void listView_ItemChecked(object sender, ItemCheckedEventArgs e) {
-      // also check all dependencies
-      if (e.Item.Checked) {
-        uploadButton.Enabled = true;
-        var plugin = (IPluginDescription)e.Item.Tag;
-        foreach (var dep in plugin.Dependencies) {
-          var depItem = FindItemForPlugin(dep);
-          if (!depItem.Checked) depItem.Checked = true;
-        }
-      } else {
-        uploadButton.Enabled = (from i in listView.Items.Cast<ListViewItem>()
-                                where i.Checked
-                                select i).Any();
-        // also uncheck all dependent plugins
-        var plugin = (IPluginDescription)e.Item.Tag;
-        foreach (ListViewItem item in listView.Items) {
-          var dep = (IPluginDescription)item.Tag;
-          if (dep.Dependencies.Contains(plugin) && item.Checked) {
-            item.Checked = false;
-          }
-        }
-      }
+    private void OnItemChecked(ItemCheckedEventArgs e) {
+      if (ItemChecked != null && !suppressItemCheckedEvents) ItemChecked(this, e);
     }
-    #endregion
-
-    #region helper methods
-    private byte[] CreateZipPackage(IPluginDescription plugin) {
-      using (MemoryStream stream = new MemoryStream()) {
-        ZipFile zipFile = new ZipFile(stream);
-        zipFile.BeginUpdate();
-        foreach (var file in plugin.Files) {
-          zipFile.Add(file.Name);
-        }
-        zipFile.CommitUpdate();
-        stream.Seek(0, SeekOrigin.Begin);
-        return stream.GetBuffer();
-      }
-    }
-
-    private ListViewItem MakeListViewItem(IPluginDescription plugin) {
-      ListViewItem item;
-      if (localAndServerPlugins[plugin] != null) {
-        item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), localAndServerPlugins[plugin].Version.ToString() });
-      } else {
-        item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), string.Empty });
-      }
-      item.Tag = plugin;
-      item.Checked = false;
-      return item;
-    }
-
-    private ListViewItem FindItemForPlugin(IPluginDescription dep) {
-      return (from i in listView.Items.Cast<ListViewItem>()
-              where i.Tag == dep
-              select i).Single();
-    }
-
-    private PluginDeploymentService.PluginDescription MakePluginDescription(IPluginDescription plugin) {
-      var dependencies = from dep in plugin.Dependencies
-                         select MakePluginDescription(dep);
-      return new PluginDeploymentService.PluginDescription(plugin.Name, plugin.Version, dependencies, plugin.ContactName, plugin.ContactEmail, plugin.LicenseText);
-    }
-
-    private IEnumerable<IPluginDescription> IteratePlugins(IEnumerable<IPluginDescription> plugins) {
-      foreach (var plugin in plugins) {
-        foreach (var dependency in IteratePlugins(plugin.Dependencies)) {
-          yield return dependency;
-        }
-        yield return plugin;
-      }
-    }
-
-    // start background process to refresh the plugin list (local and server)
-    private void RefreshPluginsAsync() {
-      Cursor = Cursors.AppStarting;
-      DisableControl();
-      updateServerPluginsWorker.RunWorkerAsync();
-    }
-
-    // is called by all methods that start a background process
-    // controls must be enabled manuall again when the backgroundworker finishes
-    private void DisableControl() {
-      MainFormManager.GetMainForm<MainForm>().ShowProgressBar();
-      foreach (Control ctrl in Controls)
-        ctrl.Enabled = false;
-    }
-
-    private void UpdateControlsDisconnectedState() {
-      refreshButton.Enabled = false;
-
-      localAndServerPlugins.Clear();
-      listView.Items.Clear();
-      listView.Enabled = false;
-      uploadButton.Enabled = false;
-      MainFormManager.GetMainForm<MainForm>().HideProgressBar();
-    }
-
-    private void UpdateControlsConnectedState() {
-      refreshButton.Enabled = true;
-      listView.Enabled = true;
-      uploadButton.Enabled = false;
-      MainFormManager.GetMainForm<MainForm>().HideProgressBar();
-    }
-    #endregion
   }
 }
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.Designer.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.Designer.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.Designer.cs	(revision 3045)
@@ -29,4 +29,9 @@
       this.newProductButton = new System.Windows.Forms.Button();
       this.splitContainer = new System.Windows.Forms.SplitContainer();
+      this.productsListView = new System.Windows.Forms.ListView();
+      this.productNameHeader = new System.Windows.Forms.ColumnHeader();
+      this.productVersionHeader = new System.Windows.Forms.ColumnHeader();
+      this.productImageList = new System.Windows.Forms.ImageList(this.components);
+      this.pluginImageList = new System.Windows.Forms.ImageList(this.components);
       this.pluginsLabel = new System.Windows.Forms.Label();
       this.versionTextBox = new System.Windows.Forms.TextBox();
@@ -35,12 +40,5 @@
       this.nameLabel = new System.Windows.Forms.Label();
       this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
-      this.productsListView = new System.Windows.Forms.ListView();
-      this.productNameHeader = new System.Windows.Forms.ColumnHeader();
-      this.productVersionHeader = new System.Windows.Forms.ColumnHeader();
-      this.productImageList = new System.Windows.Forms.ImageList(this.components);
-      this.pluginImageList = new System.Windows.Forms.ImageList(this.components);
-      this.pluginsListView = new System.Windows.Forms.ListView();
-      this.pluginNameHeader = new System.Windows.Forms.ColumnHeader();
-      this.pluginVersionHeader = new System.Windows.Forms.ColumnHeader();
+      this.pluginListView = new HeuristicLab.DeploymentService.AdminClient.PluginListView();
       this.splitContainer.Panel1.SuspendLayout();
       this.splitContainer.Panel2.SuspendLayout();
@@ -61,5 +59,6 @@
       // saveButton
       // 
-      this.saveButton.Location = new System.Drawing.Point(84, 3);
+      this.saveButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.saveButton.Location = new System.Drawing.Point(3, 365);
       this.saveButton.Name = "saveButton";
       this.saveButton.Size = new System.Drawing.Size(96, 23);
@@ -71,6 +70,5 @@
       // newProductButton
       // 
-      this.newProductButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.newProductButton.Location = new System.Drawing.Point(3, 365);
+      this.newProductButton.Location = new System.Drawing.Point(84, 3);
       this.newProductButton.Name = "newProductButton";
       this.newProductButton.Size = new System.Drawing.Size(91, 23);
@@ -91,9 +89,9 @@
       // 
       this.splitContainer.Panel1.Controls.Add(this.productsListView);
-      this.splitContainer.Panel1.Controls.Add(this.newProductButton);
+      this.splitContainer.Panel1.Controls.Add(this.saveButton);
       // 
       // splitContainer.Panel2
       // 
-      this.splitContainer.Panel2.Controls.Add(this.pluginsListView);
+      this.splitContainer.Panel2.Controls.Add(this.pluginListView);
       this.splitContainer.Panel2.Controls.Add(this.pluginsLabel);
       this.splitContainer.Panel2.Controls.Add(this.versionTextBox);
@@ -104,55 +102,4 @@
       this.splitContainer.SplitterDistance = 319;
       this.splitContainer.TabIndex = 4;
-      // 
-      // pluginsLabel
-      // 
-      this.pluginsLabel.AutoSize = true;
-      this.pluginsLabel.Location = new System.Drawing.Point(11, 69);
-      this.pluginsLabel.Name = "pluginsLabel";
-      this.pluginsLabel.Size = new System.Drawing.Size(44, 13);
-      this.pluginsLabel.TabIndex = 6;
-      this.pluginsLabel.Text = "Plugins:";
-      // 
-      // versionTextBox
-      // 
-      this.versionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
-      this.versionTextBox.Location = new System.Drawing.Point(68, 29);
-      this.versionTextBox.Name = "versionTextBox";
-      this.versionTextBox.Size = new System.Drawing.Size(233, 20);
-      this.versionTextBox.TabIndex = 5;
-      this.versionTextBox.TextChanged += new System.EventHandler(this.versionTextBox_TextChanged);
-      // 
-      // versionLabel
-      // 
-      this.versionLabel.AutoSize = true;
-      this.versionLabel.Location = new System.Drawing.Point(10, 32);
-      this.versionLabel.Name = "versionLabel";
-      this.versionLabel.Size = new System.Drawing.Size(45, 13);
-      this.versionLabel.TabIndex = 4;
-      this.versionLabel.Text = "Version:";
-      // 
-      // nameTextBox
-      // 
-      this.nameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
-      this.nameTextBox.Location = new System.Drawing.Point(68, 3);
-      this.nameTextBox.Name = "nameTextBox";
-      this.nameTextBox.Size = new System.Drawing.Size(233, 20);
-      this.nameTextBox.TabIndex = 3;
-      this.nameTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged);
-      // 
-      // nameLabel
-      // 
-      this.nameLabel.AutoSize = true;
-      this.nameLabel.Location = new System.Drawing.Point(17, 6);
-      this.nameLabel.Name = "nameLabel";
-      this.nameLabel.Size = new System.Drawing.Size(38, 13);
-      this.nameLabel.TabIndex = 2;
-      this.nameLabel.Text = "Name:";
-      // 
-      // errorProvider
-      // 
-      this.errorProvider.ContainerControl = this;
       // 
       // productsListView
@@ -197,31 +144,66 @@
       this.pluginImageList.TransparentColor = System.Drawing.Color.Transparent;
       // 
-      // pluginsListView
-      // 
-      this.pluginsListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+      // pluginsLabel
+      // 
+      this.pluginsLabel.AutoSize = true;
+      this.pluginsLabel.Location = new System.Drawing.Point(11, 69);
+      this.pluginsLabel.Name = "pluginsLabel";
+      this.pluginsLabel.Size = new System.Drawing.Size(44, 13);
+      this.pluginsLabel.TabIndex = 6;
+      this.pluginsLabel.Text = "Plugins:";
+      // 
+      // versionTextBox
+      // 
+      this.versionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.versionTextBox.Location = new System.Drawing.Point(68, 29);
+      this.versionTextBox.Name = "versionTextBox";
+      this.versionTextBox.Size = new System.Drawing.Size(233, 20);
+      this.versionTextBox.TabIndex = 5;
+      this.versionTextBox.TextChanged += new System.EventHandler(this.versionTextBox_TextChanged);
+      // 
+      // versionLabel
+      // 
+      this.versionLabel.AutoSize = true;
+      this.versionLabel.Location = new System.Drawing.Point(10, 32);
+      this.versionLabel.Name = "versionLabel";
+      this.versionLabel.Size = new System.Drawing.Size(45, 13);
+      this.versionLabel.TabIndex = 4;
+      this.versionLabel.Text = "Version:";
+      // 
+      // nameTextBox
+      // 
+      this.nameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                  | System.Windows.Forms.AnchorStyles.Right)));
+      this.nameTextBox.Location = new System.Drawing.Point(68, 3);
+      this.nameTextBox.Name = "nameTextBox";
+      this.nameTextBox.Size = new System.Drawing.Size(233, 20);
+      this.nameTextBox.TabIndex = 3;
+      this.nameTextBox.TextChanged += new System.EventHandler(this.nameTextBox_TextChanged);
+      // 
+      // nameLabel
+      // 
+      this.nameLabel.AutoSize = true;
+      this.nameLabel.Location = new System.Drawing.Point(17, 6);
+      this.nameLabel.Name = "nameLabel";
+      this.nameLabel.Size = new System.Drawing.Size(38, 13);
+      this.nameLabel.TabIndex = 2;
+      this.nameLabel.Text = "Name:";
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // pluginListView
+      // 
+      this.pluginListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                   | System.Windows.Forms.AnchorStyles.Left)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.pluginsListView.CheckBoxes = true;
-      this.pluginsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
-            this.pluginNameHeader,
-            this.pluginVersionHeader});
-      this.pluginsListView.Location = new System.Drawing.Point(3, 85);
-      this.pluginsListView.Name = "pluginsListView";
-      this.pluginsListView.Size = new System.Drawing.Size(333, 303);
-      this.pluginsListView.SmallImageList = this.pluginImageList;
-      this.pluginsListView.TabIndex = 7;
-      this.pluginsListView.UseCompatibleStateImageBehavior = false;
-      this.pluginsListView.View = System.Windows.Forms.View.Details;
-      this.pluginsListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.pluginsListView_ItemChecked);
-      // 
-      // pluginNameHeader
-      // 
-      this.pluginNameHeader.Text = "Name";
-      this.pluginNameHeader.Width = 220;
-      // 
-      // pluginVersionHeader
-      // 
-      this.pluginVersionHeader.Text = "Version";
-      this.pluginVersionHeader.Width = 120;
+      this.pluginListView.Location = new System.Drawing.Point(3, 85);
+      this.pluginListView.Name = "pluginListView";
+      this.pluginListView.Plugins = null;
+      this.pluginListView.Size = new System.Drawing.Size(330, 303);
+      this.pluginListView.TabIndex = 7;
+      this.pluginListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.pluginListView_ItemChecked);
       // 
       // ProductEditor
@@ -230,5 +212,5 @@
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
       this.Controls.Add(this.splitContainer);
-      this.Controls.Add(this.saveButton);
+      this.Controls.Add(this.newProductButton);
       this.Controls.Add(this.refreshButton);
       this.Name = "ProductEditor";
@@ -260,7 +242,5 @@
     private System.Windows.Forms.ImageList productImageList;
     private System.Windows.Forms.ImageList pluginImageList;
-    private System.Windows.Forms.ListView pluginsListView;
-    private System.Windows.Forms.ColumnHeader pluginNameHeader;
-    private System.Windows.Forms.ColumnHeader pluginVersionHeader;
+    private PluginListView pluginListView;
 
   }
Index: /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.cs
===================================================================
--- /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.cs	(revision 3044)
+++ /branches/DeploymentServer Prototype/HeuristicLab.Services/HeuristicLab.DeploymentService.AdminClient/ProductEditor.cs	(revision 3045)
@@ -100,30 +100,5 @@
       versionTextBox.Text = activeProduct.Version.ToString();
 
-      pluginsListView.Items.Clear();
-      foreach (PluginDeploymentService.PluginDescription pluginDesc in plugins) {
-        var matching = from p in activeProduct.Plugins
-                       where p.Name == pluginDesc.Name
-                       where p.Version == pluginDesc.Version
-                       select p;
-
-        if (matching.Any()) pluginsListView.Items.Add(CreateCheckedListViewItem(pluginDesc));
-        else pluginsListView.Items.Add(CreateUncheckedListViewItem(pluginDesc));
-      }
-    }
-
-    private ListViewItem CreateUncheckedListViewItem(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.PluginDescription pluginDesc) {
-      ListViewItem item = new ListViewItem(new string[] { pluginDesc.Name, pluginDesc.Version.ToString() });
-      item.Checked = false;
-      item.Tag = pluginDesc;
-      item.ImageIndex = 0;
-      return item;
-    }
-
-    private ListViewItem CreateCheckedListViewItem(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.PluginDescription pluginDesc) {
-      ListViewItem item = new ListViewItem(new string[] { pluginDesc.Name, pluginDesc.Version.ToString() });
-      item.Checked = true;
-      item.Tag = pluginDesc;
-      item.ImageIndex = 0;
-      return item;
+      UpdatePluginsListView();
     }
 
@@ -135,16 +110,12 @@
     }
 
-    private void refreshButton_Click(object sender, EventArgs e) {
-      SetControlsEnabled(false);
-      Cursor = Cursors.AppStarting;
-      refreshProductsWorker.RunWorkerAsync();
-    }
-
     private void SetControlsEnabled(bool enabled) {
       saveButton.Enabled = enabled;
       refreshButton.Enabled = enabled;
+      newProductButton.Enabled = enabled;
       splitContainer.Enabled = enabled;
     }
 
+    #region button event handlers
     private void newProductButton_Click(object sender, EventArgs e) {
       var newProduct = new PluginDeploymentService.ProductDescription("New product", new Version("0.0.0.0"));
@@ -158,5 +129,13 @@
       uploadChangedProductsWorker.RunWorkerAsync(dirtyProducts);
     }
-
+    private void refreshButton_Click(object sender, EventArgs e) {
+      SetControlsEnabled(false);
+      Cursor = Cursors.AppStarting;
+      refreshProductsWorker.RunWorkerAsync();
+    }
+
+    #endregion
+
+    #region textbox changed event handlers
     private void nameTextBox_TextChanged(object sender, EventArgs e) {
       ListViewItem activeItem = (ListViewItem)productsListView.SelectedItems[0];
@@ -198,18 +177,22 @@
       }
     }
-
-    private void pluginsListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
-      var pluginItem = e.Item;
-      var activePlugin = (IPluginDescription)pluginItem.Tag;
-      ListViewItem activeItem = (ListViewItem)productsListView.SelectedItems[0];
-      PluginDeploymentService.ProductDescription activeProduct = (PluginDeploymentService.ProductDescription)activeItem.Tag;
-      if (pluginItem.Checked && !activeProduct.Plugins.Contains(activePlugin)) {
-        activeProduct.AddPlugin(activePlugin);
-        MarkProductDirty(activeProduct);
-      } else if (!pluginItem.Checked && activeProduct.Plugins.Contains(activePlugin)) {
-        activeProduct.RemovePlugin(activePlugin);
-        MarkProductDirty(activeProduct);
-      }
-    }
+    #endregion
+
+
+    #region plugin list view
+    private void UpdatePluginsListView() {
+      ListViewItem activeItem = (ListViewItem)productsListView.SelectedItems[0];
+      PluginDeploymentService.ProductDescription activeProduct = (PluginDeploymentService.ProductDescription)activeItem.Tag;
+      pluginListView.Plugins = plugins.OfType<IPluginDescription>();
+      foreach (var plugin in activeProduct.Plugins) pluginListView.CheckPlugin(plugin);
+    }
+
+    private void pluginListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
+      ListViewItem activeItem = (ListViewItem)productsListView.SelectedItems[0];
+      PluginDeploymentService.ProductDescription activeProduct = (PluginDeploymentService.ProductDescription)activeItem.Tag;
+      activeProduct.Plugins = pluginListView.CheckedPlugins.Cast<PluginDeploymentService.PluginDescription>().ToArray();
+      MarkProductDirty(activeProduct);
+    }
+    #endregion
 
     private void MarkProductDirty(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.ProductDescription activeProduct) {
@@ -220,5 +203,4 @@
       }
     }
-
     private ListViewItem FindItemForProduct(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.ProductDescription activeProduct) {
       return (from item in productsListView.Items.OfType<ListViewItem>()
