Free cookie consent management tool by TermsFeed Policy Generator

source: branches/gp-crossover/HeuristicLab.PluginInfrastructure/3.3/Advanced/AvailablePluginsView.cs @ 7461

Last change on this file since 7461 was 6413, checked in by gkronber, 13 years ago

#1536 implemented feature that checks for plugin updates on each application start and allows to install plugin updates easily. Removed more advanced plugin management features for all users except if it is manually reenabled in the HeuristicLab.config file.

File size: 15.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.Linq;
25using System.Windows.Forms;
26using HeuristicLab.PluginInfrastructure.Manager;
27
28namespace HeuristicLab.PluginInfrastructure.Advanced {
29  internal partial class AvailablePluginsView : InstallationManagerControl {
30    private class RefreshBackgroundWorkerResult {
31      public IEnumerable<IPluginDescription> RemotePlugins { get; set; }
32      public IEnumerable<DeploymentService.ProductDescription> RemoteProducts { get; set; }
33    }
34    private class UpdateOrInstallPluginsBackgroundWorkerArgument {
35      public IEnumerable<IPluginDescription> PluginsToUpdate { get; set; }
36      public IEnumerable<IPluginDescription> PluginsToInstall { get; set; }
37    }
38    private const string PluginDiscoveryMessage = "Looking for new plugins...";
39    private BackgroundWorker refreshServerPluginsBackgroundWorker;
40    private BackgroundWorker updateOrInstallPluginsBackgroundWorker;
41
42    private IEnumerable<DeploymentService.ProductDescription> products;
43    private IEnumerable<IPluginDescription> plugins;
44
45    private IEnumerable<IPluginDescription> CheckedPlugins {
46      get {
47        return (from item in pluginsListView.Items.OfType<ListViewItem>()
48                where item.Checked
49                let plugin = item.Tag as IPluginDescription
50                where plugin != null
51                select plugin).ToList();
52      }
53    }
54
55    private InstallationManager installationManager;
56    public InstallationManager InstallationManager {
57      get { return installationManager; }
58      set { installationManager = value; }
59    }
60    private PluginManager pluginManager;
61    public PluginManager PluginManager {
62      get { return pluginManager; }
63      set { pluginManager = value; }
64    }
65    public AvailablePluginsView() {
66      InitializeComponent();
67      productImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Setup_Install);
68      productLargeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Setup_Install);
69      pluginsImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Plugin);
70      refreshServerPluginsBackgroundWorker = new BackgroundWorker();
71      refreshServerPluginsBackgroundWorker.DoWork += new DoWorkEventHandler(refreshServerPluginsBackgroundWorker_DoWork);
72      refreshServerPluginsBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(refreshServerPluginsBackgroundWorker_RunWorkerCompleted);
73
74      updateOrInstallPluginsBackgroundWorker = new BackgroundWorker();
75      updateOrInstallPluginsBackgroundWorker.DoWork += new DoWorkEventHandler(updateOrInstallPluginsBackgroundWorker_DoWork);
76      updateOrInstallPluginsBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(updateOrInstallPluginsBackgroundWorker_RunWorkerCompleted);
77    }
78
79
80    #region event handlers for refresh server plugins background worker
81    void refreshServerPluginsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
82      if (e.Error != null) {
83        StatusView.ShowError("Connection Error",
84          "There was an error while connecting to the server." + Environment.NewLine +
85          "Please check your connection settings and user credentials.");
86      } else {
87        RefreshBackgroundWorkerResult refreshResult = (RefreshBackgroundWorkerResult)e.Result;
88        products = refreshResult.RemoteProducts;
89        plugins = refreshResult.RemotePlugins;
90        UpdateControl();
91      }
92      StatusView.UnlockUI();
93      StatusView.RemoveMessage(PluginDiscoveryMessage);
94      StatusView.HideProgressIndicator();
95    }
96
97    void refreshServerPluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
98      RefreshBackgroundWorkerResult result = new RefreshBackgroundWorkerResult();
99      result.RemotePlugins = installationManager.GetRemotePluginList();
100      result.RemoteProducts = installationManager.GetRemoteProductList();
101      e.Result = result;
102    }
103    #endregion
104    #region event handlers for plugin update background worker
105    void updateOrInstallPluginsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
106      if (e.Error != null) {
107        StatusView.ShowError("Connection Error",
108          "There was an error while connecting to the server." + Environment.NewLine +
109          "Please check your connection settings and user credentials.");
110      } else {
111        UpdateControl();
112      }
113      StatusView.UnlockUI();
114      StatusView.HideProgressIndicator();
115    }
116
117    void updateOrInstallPluginsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
118      UpdateOrInstallPluginsBackgroundWorkerArgument info = (UpdateOrInstallPluginsBackgroundWorkerArgument)e.Argument;
119      bool cancelled = false;
120      if (info.PluginsToInstall.Count() > 0)
121        installationManager.Install(info.PluginsToInstall, out cancelled);
122      if (info.PluginsToUpdate.Count() > 0)
123        installationManager.Update(info.PluginsToUpdate, out cancelled);
124
125      if (!cancelled && (info.PluginsToInstall.Count() > 0 || info.PluginsToUpdate.Count() > 0))
126        pluginManager.DiscoverAndCheckPlugins();
127    }
128    #endregion
129
130
131    #region button events
132    private void refreshRemoteButton_Click(object sender, EventArgs e) {
133      StatusView.LockUI();
134      StatusView.ShowProgressIndicator();
135      StatusView.ShowMessage(PluginDiscoveryMessage);
136      refreshServerPluginsBackgroundWorker.RunWorkerAsync();
137    }
138    private void installPluginsButton_Click(object sender, EventArgs e) {
139      StatusView.LockUI();
140      StatusView.ShowProgressIndicator();
141      var updateOrInstallInfo = new UpdateOrInstallPluginsBackgroundWorkerArgument();
142      // if there is a local plugin with same name and same major and minor version then it's an update
143      var pluginsToUpdate = from remotePlugin in CheckedPlugins
144                            let matchingLocalPlugins = from localPlugin in pluginManager.Plugins
145                                                       where localPlugin.Name == remotePlugin.Name
146                                                       where localPlugin.Version.Major == remotePlugin.Version.Major
147                                                       where localPlugin.Version.Minor == remotePlugin.Version.Minor
148                                                       where IsNewerThan(remotePlugin, localPlugin)
149                                                       select localPlugin
150                            where matchingLocalPlugins.Count() > 0
151                            select remotePlugin;
152
153      // otherwise install a new plugin
154      var pluginsToInstall = CheckedPlugins.Except(pluginsToUpdate);
155
156      updateOrInstallInfo.PluginsToInstall = pluginsToInstall;
157      updateOrInstallInfo.PluginsToUpdate = pluginsToUpdate;
158      updateOrInstallPluginsBackgroundWorker.RunWorkerAsync(updateOrInstallInfo);
159    }
160    private void installProductsButton_Click(object sender, EventArgs e) {
161      StatusView.LockUI();
162      StatusView.ShowProgressIndicator();
163      var updateOrInstallInfo = new UpdateOrInstallPluginsBackgroundWorkerArgument();
164      var selectedProduct = (DeploymentService.ProductDescription)productsListView.SelectedItems[0].Tag;
165      // if there is a local plugin with same name and same major and minor version then it's an update
166      var pluginsToUpdate = from plugin in selectedProduct.Plugins
167                            let matchingLocalPlugins = from localPlugin in pluginManager.Plugins
168                                                       where localPlugin.Name == plugin.Name
169                                                       where localPlugin.Version.Major == plugin.Version.Major
170                                                       where localPlugin.Version.Minor == plugin.Version.Minor
171                                                       where IsNewerThan(plugin, localPlugin)
172                                                       select localPlugin
173                            where matchingLocalPlugins.Count() > 0
174                            select plugin;
175
176      // otherwise install a new plugin
177      var pluginsToInstall = selectedProduct.Plugins.Except(pluginsToUpdate);
178
179      updateOrInstallInfo.PluginsToInstall =
180        pluginsToInstall
181        .Cast<IPluginDescription>()
182        .ToList();
183      updateOrInstallInfo.PluginsToUpdate =
184        pluginsToUpdate
185        .Cast<IPluginDescription>()
186        .ToList();
187      updateOrInstallPluginsBackgroundWorker.RunWorkerAsync(updateOrInstallInfo);
188    }
189
190    private void showLargeIconsButton_CheckedChanged(object sender, EventArgs e) {
191      productsListView.View = View.LargeIcon;
192    }
193
194    private void showDetailsButton_CheckedChanged(object sender, EventArgs e) {
195      productsListView.View = View.Details;
196    }
197
198    #endregion
199
200    private void UpdateControl() {
201      // clear products view
202      List<ListViewItem> productItemsToDelete = new List<ListViewItem>(productsListView.Items.OfType<ListViewItem>());
203      productItemsToDelete.ForEach(item => productsListView.Items.Remove(item));
204
205      // populate products list view
206      foreach (var product in products) {
207        var item = CreateListViewItem(product);
208        productsListView.Items.Add(item);
209      }
210      var allPluginsListViewItem = new ListViewItem();
211      allPluginsListViewItem.Text = "All Plugins";
212      allPluginsListViewItem.ImageIndex = 0;
213      productsListView.Items.Add(allPluginsListViewItem);
214      Util.ResizeColumns(productsListView.Columns.OfType<ColumnHeader>());
215    }
216
217    private void UpdatePluginsList() {
218      pluginsListView.Items.Clear();
219
220      // populate plugins list
221      if (productsListView.SelectedItems.Count > 0) {
222        pluginsListView.SuppressItemCheckedEvents = true;
223
224        var selectedItem = productsListView.SelectedItems[0];
225        if (selectedItem.Text == "All Plugins") {
226          foreach (var plugin in plugins) {
227            var item = CreateListViewItem(plugin);
228            pluginsListView.Items.Add(item);
229          }
230        } else {
231          var selectedProduct = (DeploymentService.ProductDescription)productsListView.SelectedItems[0].Tag;
232          foreach (var plugin in selectedProduct.Plugins) {
233            var item = CreateListViewItem(plugin);
234            pluginsListView.Items.Add(item);
235          }
236        }
237
238        Util.ResizeColumns(pluginsListView.Columns.OfType<ColumnHeader>());
239        pluginsListView.SuppressItemCheckedEvents = false;
240      }
241    }
242
243    private ListViewItem CreateListViewItem(DeploymentService.ProductDescription product) {
244      ListViewItem item = new ListViewItem(new string[] { product.Name, product.Version.ToString() });
245      item.Tag = product;
246      item.ImageIndex = 0;
247      return item;
248    }
249
250    private ListViewItem CreateListViewItem(IPluginDescription plugin) {
251      ListViewItem item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(), plugin.Description });
252      item.Tag = plugin;
253      item.ImageIndex = 0;
254      return item;
255    }
256
257    #region products list view events
258    private void productsListView_SelectedIndexChanged(object sender, EventArgs e) {
259      UpdatePluginsList();
260      installProductsButton.Enabled = (productsListView.SelectedItems.Count > 0 &&
261        productsListView.SelectedItems[0].Text != "All Plugins");
262    }
263    #endregion
264
265    #region item checked event handler
266    private void remotePluginsListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
267      foreach (ListViewItem item in pluginsListView.SelectedItems) {
268        IPluginDescription plugin = (IPluginDescription)item.Tag;
269        if (e.Item.Checked)
270          HandlePluginChecked(plugin);
271        else
272          HandlePluginUnchecked(plugin);
273      }
274      installPluginsButton.Enabled = pluginsListView.CheckedItems.Count > 0;
275    }
276
277    private void HandlePluginUnchecked(IPluginDescription plugin) {
278      // also uncheck all dependent plugins
279      List<ListViewItem> modifiedItems = new List<ListViewItem>();
280      modifiedItems.AddRange(FindItemsForPlugin(plugin));
281      var dependentPlugins = Util.GetAllDependents(plugin, plugins);
282      foreach (var dependentPlugin in dependentPlugins) {
283        // there can be multiple entries for a single plugin in different groups
284        foreach (var item in FindItemsForPlugin(dependentPlugin)) {
285          if (item != null && item.Checked) {
286            if (!modifiedItems.Contains(item))
287              modifiedItems.Add(item);
288          }
289        }
290      }
291      pluginsListView.UncheckItems(modifiedItems);
292    }
293
294    private void HandlePluginChecked(IPluginDescription plugin) {
295      // also check all dependencies
296      List<ListViewItem> modifiedItems = new List<ListViewItem>();
297      modifiedItems.AddRange(FindItemsForPlugin(plugin));
298      foreach (var dep in Util.GetAllDependencies(plugin)) {
299        // there can be multiple entries for a single plugin in different groups
300        foreach (ListViewItem item in FindItemsForPlugin(dep)) {
301          if (item != null && !item.Checked) {
302            if (!modifiedItems.Contains(item))
303              modifiedItems.Add(item);
304          }
305        }
306      }
307      pluginsListView.CheckItems(modifiedItems);
308    }
309
310    #endregion
311
312    #region helper methods
313    private IEnumerable<ListViewItem> FindItemsForPlugin(IPluginDescription plugin) {
314      return (from item in pluginsListView.Items.OfType<ListViewItem>()
315              let otherPlugin = item.Tag as IPluginDescription
316              where otherPlugin != null && otherPlugin.Name == plugin.Name && otherPlugin.Version == plugin.Version
317              select item);
318    }
319
320    // compares for two plugins with same major and minor version if plugin1 is newer than plugin2
321    private static bool IsNewerThan(IPluginDescription plugin1, IPluginDescription plugin2) {
322      // newer: build version is higher, or if build version is the same revision is higher
323      return plugin1.Version.Build > plugin2.Version.Build ||
324        (plugin1.Version.Build == plugin2.Version.Build && plugin1.Version.Revision > plugin2.Version.Revision);
325    }
326    #endregion
327
328  }
329}
Note: See TracBrowser for help on using the repository browser.