Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.PluginInfrastructure/Advanced/RemotePluginInstaller.cs @ 3624

Last change on this file since 3624 was 3624, checked in by gkronber, 14 years ago

Implemented changes in plugin infrastructure requested by reviewers. #989 (Implement review comments in plugin infrastructure)

File size: 17.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21using System;
22using System.Collections.Generic;
23using System.ComponentModel;
24using System.Drawing;
25using System.Data;
26using System.Linq;
27using System.Text;
28using System.Windows.Forms;
29using HeuristicLab.PluginInfrastructure.Manager;
30
31namespace HeuristicLab.PluginInfrastructure.Advanced {
32  internal partial class RemotePluginInstallerView : InstallationManagerControl {
33    private class RefreshBackgroundWorkerResult {
34      public IEnumerable<IPluginDescription> RemotePlugins { get; set; }
35      public IEnumerable<DeploymentService.ProductDescription> RemoteProducts { get; set; }
36    }
37    private class UpdateOrInstallPluginsBackgroundWorkerArgument {
38      public IEnumerable<IPluginDescription> PluginsToUpdate { get; set; }
39      public IEnumerable<IPluginDescription> PluginsToInstall { get; set; }
40    }
41    private const string PluginDiscoveryMessage = "Looking for new plugins...";
42    private BackgroundWorker refreshServerPluginsBackgroundWorker;
43    private BackgroundWorker updateOrInstallPluginsBackgroundWorker;
44
45    private IEnumerable<DeploymentService.ProductDescription> products;
46    private IEnumerable<IPluginDescription> plugins;
47
48    private IEnumerable<IPluginDescription> CheckedPlugins {
49      get {
50        return (from item in pluginsListView.Items.OfType<ListViewItem>()
51                where item.Checked
52                let plugin = item.Tag as IPluginDescription
53                where plugin != null
54                select plugin).ToList();
55      }
56    }
57
58    private InstallationManager installationManager;
59    public InstallationManager InstallationManager {
60      get { return installationManager; }
61      set { installationManager = value; }
62    }
63    private PluginManager pluginManager;
64    public PluginManager PluginManager {
65      get { return pluginManager; }
66      set { pluginManager = value; }
67    }
68    public RemotePluginInstallerView() {
69      InitializeComponent();
70      productImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Resources.Setup_Install);
71      productLargeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Resources.Setup_Install);
72      pluginsImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Resources.plugin_16);
73      refreshServerPluginsBackgroundWorker = new BackgroundWorker();
74      refreshServerPluginsBackgroundWorker.DoWork += new DoWorkEventHandler(refreshServerPluginsBackgroundWorker_DoWork);
75      refreshServerPluginsBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(refreshServerPluginsBackgroundWorker_RunWorkerCompleted);
76
77      updateOrInstallPluginsBackgroundWorker = new BackgroundWorker();
78      updateOrInstallPluginsBackgroundWorker.DoWork += new DoWorkEventHandler(updateOrInstallPluginsBackgroundWorker_DoWork);
79      updateOrInstallPluginsBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(updateOrInstallPluginsBackgroundWorker_RunWorkerCompleted);
80    }
81
82
83    #region event handlers for refresh server plugins background worker
84    void refreshServerPluginsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
85      if (e.Error != null) {
86        StatusView.ShowError("Connection Error",
87          "There was an error while connecting to the server." + Environment.NewLine +
88          "Please check your connection settings and user credentials.");
89      } else {
90        RefreshBackgroundWorkerResult refreshResult = (RefreshBackgroundWorkerResult)e.Result;
91        products = refreshResult.RemoteProducts;
92        plugins = refreshResult.RemotePlugins;
93        UpdateControl();
94      }
95      StatusView.UnlockUI();
96      StatusView.RemoveMessage(PluginDiscoveryMessage);
97      StatusView.HideProgressIndicator();
98    }
99
100    void refreshServerPluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
101      RefreshBackgroundWorkerResult result = new RefreshBackgroundWorkerResult();
102      result.RemotePlugins = installationManager.GetRemotePluginList();
103      result.RemoteProducts = installationManager.GetRemoteProductList();
104      e.Result = result;
105    }
106    #endregion
107    #region event handlers for plugin update background worker
108    void updateOrInstallPluginsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
109      if (e.Error != null) {
110        StatusView.ShowError("Connection Error",
111          "There was an error while connecting to the server." + Environment.NewLine +
112          "Please check your connection settings and user credentials.");
113      } else {
114        UpdateControl();
115      }
116      StatusView.UnlockUI();
117      StatusView.HideProgressIndicator();
118    }
119
120    void updateOrInstallPluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
121      UpdateOrInstallPluginsBackgroundWorkerArgument info = (UpdateOrInstallPluginsBackgroundWorkerArgument)e.Argument;
122      if (info.PluginsToInstall.Count() > 0)
123        installationManager.Install(info.PluginsToInstall);
124      if (info.PluginsToUpdate.Count() > 0)
125        installationManager.Update(info.PluginsToUpdate);
126
127      if (info.PluginsToInstall.Count() > 0 || info.PluginsToUpdate.Count() > 0)
128        pluginManager.DiscoverAndCheckPlugins();
129    }
130    #endregion
131
132
133    #region button events
134    private void refreshRemoteButton_Click(object sender, EventArgs e) {
135      StatusView.LockUI();
136      StatusView.ShowProgressIndicator();
137      StatusView.ShowMessage(PluginDiscoveryMessage);
138      refreshServerPluginsBackgroundWorker.RunWorkerAsync();
139    }
140    private void installPluginsButton_Click(object sender, EventArgs e) {
141      StatusView.LockUI();
142      StatusView.ShowProgressIndicator();
143      var updateOrInstallInfo = new UpdateOrInstallPluginsBackgroundWorkerArgument();
144      // if there is a local plugin with same name and same major and minor version then it's an update
145      var pluginsToUpdate = from remotePlugin in CheckedPlugins
146                            let matchingLocalPlugins = from localPlugin in pluginManager.Plugins
147                                                       where localPlugin.Name == remotePlugin.Name
148                                                       where localPlugin.Version.Major == remotePlugin.Version.Major
149                                                       where localPlugin.Version.Minor == remotePlugin.Version.Minor
150                                                       where IsNewerThan(remotePlugin, localPlugin)
151                                                       select localPlugin
152                            where matchingLocalPlugins.Count() > 0
153                            select remotePlugin;
154
155      // otherwise install a new plugin
156      var pluginsToInstall = CheckedPlugins.Except(pluginsToUpdate);
157
158      updateOrInstallInfo.PluginsToInstall = pluginsToInstall;
159      updateOrInstallInfo.PluginsToUpdate = pluginsToUpdate;
160      updateOrInstallPluginsBackgroundWorker.RunWorkerAsync(updateOrInstallInfo);
161    }
162    private void installProductsButton_Click(object sender, EventArgs e) {
163      StatusView.LockUI();
164      StatusView.ShowProgressIndicator();
165      var updateOrInstallInfo = new UpdateOrInstallPluginsBackgroundWorkerArgument();
166      var selectedProduct = (DeploymentService.ProductDescription)productsListView.SelectedItems[0].Tag;
167      // if there is a local plugin with same name and same major and minor version then it's an update
168      var pluginsToUpdate = from plugin in selectedProduct.Plugins
169                            let matchingLocalPlugins = from localPlugin in pluginManager.Plugins
170                                                       where localPlugin.Name == plugin.Name
171                                                       where localPlugin.Version.Major == plugin.Version.Major
172                                                       where localPlugin.Version.Minor == plugin.Version.Minor
173                                                       where IsNewerThan(plugin, localPlugin)
174                                                       select localPlugin
175                            where matchingLocalPlugins.Count() > 0
176                            select plugin;
177
178      // otherwise install a new plugin
179      var pluginsToInstall = selectedProduct.Plugins.Except(pluginsToUpdate);
180
181      updateOrInstallInfo.PluginsToInstall = (IEnumerable<IPluginDescription>)pluginsToInstall.ToList();
182      updateOrInstallInfo.PluginsToUpdate = (IEnumerable<IPluginDescription>)pluginsToUpdate.ToList();
183      updateOrInstallPluginsBackgroundWorker.RunWorkerAsync(updateOrInstallInfo);
184    }
185
186    private void showLargeIconsButton_CheckedChanged(object sender, EventArgs e) {
187      productsListView.View = View.LargeIcon;
188    }
189
190    private void showDetailsButton_CheckedChanged(object sender, EventArgs e) {
191      productsListView.View = View.Details;
192    }
193
194    #endregion
195
196    private void UpdateControl() {
197      // clear products view
198      List<ListViewItem> productItemsToDelete = new List<ListViewItem>(productsListView.Items.OfType<ListViewItem>());
199      productItemsToDelete.ForEach(item => productsListView.Items.Remove(item));
200
201      // populate products list view
202      foreach (var product in products) {
203        var item = CreateListViewItem(product);
204        productsListView.Items.Add(item);
205      }
206      var allPluginsListViewItem = new ListViewItem();
207      allPluginsListViewItem.Text = "All Plugins";
208      allPluginsListViewItem.ImageIndex = 0;
209      productsListView.Items.Add(allPluginsListViewItem);
210      Util.ResizeColumns(productsListView.Columns.OfType<ColumnHeader>());
211    }
212
213    private void UpdatePluginsList() {
214      // clear plugins list view
215      List<ListViewItem> pluginItemsToDelete = new List<ListViewItem>(pluginsListView.Items.OfType<ListViewItem>());
216      pluginItemsToDelete.ForEach(item => pluginsListView.Items.Remove(item));
217
218      // populate plugins list
219      if (productsListView.SelectedItems.Count > 0) {
220        pluginsListView.SuppressItemCheckedEvents = true;
221
222        var selectedItem = productsListView.SelectedItems[0];
223        if (selectedItem.Text == "All Plugins") {
224          foreach (var plugin in plugins) {
225            var item = CreateListViewItem(plugin);
226            pluginsListView.Items.Add(item);
227          }
228        } else {
229          var selectedProduct = (DeploymentService.ProductDescription)productsListView.SelectedItems[0].Tag;
230          foreach (var plugin in selectedProduct.Plugins) {
231            var item = CreateListViewItem(plugin);
232            pluginsListView.Items.Add(item);
233          }
234        }
235
236        Util.ResizeColumns(pluginsListView.Columns.OfType<ColumnHeader>());
237        pluginsListView.SuppressItemCheckedEvents = false;
238      }
239    }
240
241    private ListViewItem CreateListViewItem(DeploymentService.ProductDescription product) {
242      ListViewItem item = new ListViewItem(new string[] { product.Name, product.Version.ToString() });
243      item.Tag = product;
244      item.ImageIndex = 0;
245      return item;
246    }
247
248    private ListViewItem CreateListViewItem(IPluginDescription plugin) {
249      ListViewItem item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), plugin.Description });
250      item.Tag = plugin;
251      item.ImageIndex = 0;
252      return item;
253    }
254
255    #region products list view events
256    private void productsListView_SelectedIndexChanged(object sender, EventArgs e) {
257      UpdatePluginsList();
258      installProductsButton.Enabled = (productsListView.SelectedItems.Count > 0 &&
259        productsListView.SelectedItems[0].Text != "All Plugins");
260    }
261    #endregion
262
263    #region item checked event handler
264    private void remotePluginsListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
265      foreach (ListViewItem item in pluginsListView.SelectedItems) {
266        // dispatch by check state and type of item (product/plugin)
267        IPluginDescription plugin = item.Tag as IPluginDescription;
268        if (plugin != null)
269          if (e.Item.Checked)
270            HandlePluginChecked(plugin);
271          else
272            HandlePluginUnchecked(plugin);
273        else {
274          DeploymentService.ProductDescription product = item.Tag as DeploymentService.ProductDescription;
275          if (product != null)
276            if (e.Item.Checked)
277              HandleProductChecked(product);
278            else
279              HandleProductUnchecked(product);
280        }
281      }
282      installPluginsButton.Enabled = pluginsListView.CheckedItems.Count > 0;
283    }
284
285    private void HandleProductUnchecked(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.ProductDescription product) {
286      // also uncheck the plugins of the product
287      List<ListViewItem> modifiedItems = new List<ListViewItem>();
288      modifiedItems.Add(FindItemForProduct(product));
289      foreach (var plugin in product.Plugins) {
290        // there can be multiple entries for a single plugin in different groups
291        foreach (var item in FindItemsForPlugin(plugin)) {
292          if (item != null && item.Checked)
293            modifiedItems.Add(item);
294        }
295      }
296      pluginsListView.UncheckItems(modifiedItems);
297    }
298
299    private void HandleProductChecked(HeuristicLab.PluginInfrastructure.Advanced.DeploymentService.ProductDescription product) {
300      // also check all plugins of the product
301      List<ListViewItem> modifiedItems = new List<ListViewItem>();
302      modifiedItems.Add(FindItemForProduct(product));
303      foreach (var plugin in product.Plugins) {
304        // there can be multiple entries for a single plugin in different groups
305        foreach (var item in FindItemsForPlugin(plugin)) {
306          if (item != null && !item.Checked) {
307            if (!modifiedItems.Contains(item))
308              modifiedItems.Add(item);
309          }
310        }
311      }
312      pluginsListView.CheckItems(modifiedItems);
313    }
314
315    private void HandlePluginUnchecked(IPluginDescription plugin) {
316      // also uncheck all dependent plugins
317      List<ListViewItem> modifiedItems = new List<ListViewItem>();
318      modifiedItems.AddRange(FindItemsForPlugin(plugin));
319      var dependentPlugins = from otherPlugin in plugins
320                             where otherPlugin.Dependencies.Any(dep => dep.Name == plugin.Name && dep.Version == plugin.Version)
321                             select otherPlugin;
322      foreach (var dependentPlugin in dependentPlugins) {
323        // there can be multiple entries for a single plugin in different groups
324        foreach (var item in FindItemsForPlugin(dependentPlugin)) {
325          if (item != null && item.Checked) {
326            if (!modifiedItems.Contains(item))
327              modifiedItems.Add(item);
328          }
329        }
330      }
331      // also uncheck all products containing this plugin
332      var dependentProducts = from product in products
333                              where product.Plugins.Any(p => p.Name == plugin.Name && p.Version == plugin.Version)
334                              select product;
335      foreach (var dependentProduct in dependentProducts) {
336        var item = FindItemForProduct(dependentProduct);
337        if (item != null && item.Checked) {
338          if (!modifiedItems.Contains(item))
339            modifiedItems.Add(item);
340        }
341      }
342      pluginsListView.UncheckItems(modifiedItems);
343    }
344
345    private void HandlePluginChecked(IPluginDescription plugin) {
346      // also check all dependencies
347      List<ListViewItem> modifiedItems = new List<ListViewItem>();
348      modifiedItems.AddRange(FindItemsForPlugin(plugin));
349      foreach (var dep in plugin.Dependencies) {
350        // there can be multiple entries for a single plugin in different groups
351        foreach (ListViewItem item in FindItemsForPlugin(dep)) {
352          if (item != null && !item.Checked) {
353            if (!modifiedItems.Contains(item))
354              modifiedItems.Add(item);
355          }
356        }
357      }
358      pluginsListView.CheckItems(modifiedItems);
359    }
360
361    #endregion
362
363    #region helper methods
364    private IEnumerable<ListViewItem> FindItemsForPlugin(IPluginDescription plugin) {
365      return (from item in pluginsListView.Items.OfType<ListViewItem>()
366              let otherPlugin = item.Tag as IPluginDescription
367              where otherPlugin != null && otherPlugin.Name == plugin.Name && otherPlugin.Version == plugin.Version
368              select item);
369    }
370
371    private ListViewItem FindItemForProduct(DeploymentService.ProductDescription product) {
372      return (from item in pluginsListView.Items.OfType<ListViewItem>()
373              let otherProduct = item.Tag as DeploymentService.ProductDescription
374              where otherProduct != null && otherProduct.Name == product.Name && otherProduct.Version == product.Version
375              select item).SingleOrDefault();
376    }
377
378    private bool IsNewerThan(IPluginDescription plugin1, IPluginDescription plugin2) {
379      // newer: build version is higher, or if build version is the same revision is higher
380      if (plugin1.Version.Build < plugin2.Version.Build) return false;
381      else if (plugin1.Version.Build > plugin2.Version.Build) return true;
382      else return plugin1.Version.Revision > plugin2.Version.Revision;
383    }
384    #endregion
385
386  }
387}
Note: See TracBrowser for help on using the repository browser.