#region License Information /* HeuristicLab * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using HeuristicLab.PluginInfrastructure.Advanced; using HeuristicLab.PluginInfrastructure.Manager; using HeuristicLab.PluginInfrastructure.Properties; namespace HeuristicLab.PluginInfrastructure.Starter { /// /// The starter form is responsible for initializing the plugin infrastructure /// and shows a list of installed applications. /// public partial class StarterForm : Form { private const string pluginManagerItemName = "Plugin Manager"; private const string updatePluginsItemName = "Updates Available"; private const string optimizerItemName = "Optimizer"; private readonly ICommandLineArgument[] arguments; private ListViewItem pluginManagerListViewItem; private bool abortRequested; private PluginManager pluginManager; private SplashScreen splashScreen; private bool updatesAvailable = false; /// /// Initializes an instance of the starter form. /// The starter form shows a splashscreen and initializes the plugin infrastructure. /// public StarterForm() : base() { InitializeComponent(); largeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.HeuristicLab.ToBitmap()); largeImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.UpdateAvailable.ToBitmap()); smallImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.HeuristicLab.ToBitmap()); smallImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.UpdateAvailable.ToBitmap()); Text = "HeuristicLab " + AssemblyHelpers.GetFileVersion(GetType().Assembly); string pluginPath = Path.GetFullPath(Application.StartupPath); pluginManager = new PluginManager(pluginPath); splashScreen = new SplashScreen(pluginManager, 1000); splashScreen.VisibleChanged += new EventHandler(splashScreen_VisibleChanged); splashScreen.Show(this, "Loading HeuristicLab..."); if (CheckSavedStarterFormSettings()) { Location = Settings.Default.StarterFormLocation; Size = Settings.Default.StarterFormSize; WindowState = Settings.Default.StarterFormWindowState; } pluginManager.DiscoverAndCheckPlugins(); UpdateApplicationsList(); CheckUpdatesAvailableAsync(); } /// /// Creates a new StarterForm and passes the arguments in . /// /// The arguments that should be processed public StarterForm(string[] args) : this() { arguments = CommandLineArgumentHandling.GetArguments(args); } protected override void SetVisibleCore(bool value) { value &= !(arguments.OfType().Any() || arguments.OfType().Any()); if (!value) HandleArguments(); base.SetVisibleCore(value); } #region Events private void StarterForm_Load(object sender, EventArgs e) { HandleArguments(); } private void StarterForm_FormClosing(object sender, FormClosingEventArgs e) { splashScreen.Close(); abortRequested = true; if (WindowState != FormWindowState.Minimized) Settings.Default.StarterFormWindowState = WindowState; if (WindowState != FormWindowState.Normal) { Settings.Default.StarterFormLocation = RestoreBounds.Location; Settings.Default.StarterFormSize = RestoreBounds.Size; } else if (WindowState == FormWindowState.Normal) { Settings.Default.StarterFormLocation = Location; Settings.Default.StarterFormSize = Size; } Settings.Default.Save(); } private void applicationsListView_SelectedIndexChanged(object sender, EventArgs e) { startButton.Enabled = applicationsListView.SelectedItems.Count > 0; } private void applicationsListView_ItemActivate(object sender, EventArgs e) { if (applicationsListView.SelectedItems.Count > 0) { ListViewItem selected = applicationsListView.SelectedItems[0]; if (selected.Text == pluginManagerItemName) { if (pluginManager.Plugins.Any(x => x.PluginState == PluginState.Loaded)) { MessageBox.Show("Installation Manager cannot be started while another HeuristicLab application is active." + Environment.NewLine + "Please stop all active HeuristicLab applications and try again.", "Plugin Manager", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { try { Cursor = Cursors.AppStarting; using (InstallationManagerForm form = new InstallationManagerForm(pluginManager)) { form.ShowDialog(this); } UpdateApplicationsList(); } finally { Cursor = Cursors.Arrow; } } } else if (selected.Text == updatePluginsItemName) { if (pluginManager.Plugins.Any(x => x.PluginState == PluginState.Loaded)) { MessageBox.Show("Updating is not possible while another HeuristicLab application is active." + Environment.NewLine + "Please stop all active HeuristicLab applications and try again.", "Update plugins", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { try { Cursor = Cursors.AppStarting; using (PluginUpdaterForm form = new PluginUpdaterForm(pluginManager)) { form.ShowDialog(this); } updatesAvailable = false; CheckUpdatesAvailableAsync(); UpdateApplicationsList(); } finally { Cursor = Cursors.Arrow; } } } else { ApplicationDescription app = (ApplicationDescription)applicationsListView.SelectedItems[0].Tag; StartApplication(app, arguments); } } } private void largeIconsButton_Click(object sender, EventArgs e) { applicationsListView.View = View.LargeIcon; } private void detailsButton_Click(object sender, EventArgs e) { applicationsListView.View = View.Details; foreach (ColumnHeader column in applicationsListView.Columns) { if (applicationsListView.Items.Count > 0) column.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); else column.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize); } } private void aboutButton_Click(object sender, EventArgs e) { List plugins = new List(pluginManager.Plugins.OfType()); using (var dialog = new AboutDialog(plugins)) { dialog.ShowDialog(); } } private void splashScreen_VisibleChanged(object sender, EventArgs e) { // close hidden starter form if (!splashScreen.Visible && arguments != null && (arguments.OfType().Any() || arguments.OfType().Any())) Close(); } #endregion #region Helpers private bool CheckSavedStarterFormSettings() { var formArea = new Rectangle(Settings.Default.StarterFormLocation, Settings.Default.StarterFormSize); var screenArea = Screen.FromRectangle(formArea).WorkingArea; var overlappingArea = Rectangle.Intersect(formArea, screenArea); bool offLimits = overlappingArea.IsEmpty || overlappingArea.Width * overlappingArea.Height < formArea.Width * formArea.Height * 0.25; return !formArea.IsEmpty && !offLimits; } private void UpdateApplicationsList() { if (InvokeRequired) Invoke((Action)UpdateApplicationsList); else { applicationsListView.Items.Clear(); AddPluginManagerItem(); AddUpdatePluginsItem(); foreach (ApplicationDescription info in pluginManager.Applications) { ListViewItem item = new ListViewItem(info.Name, 0); item.Tag = info; item.Group = applicationsListView.Groups["Applications"]; item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Version.ToString())); item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.Description)); item.ToolTipText = info.Description; applicationsListView.Items.Add(item); } foreach (ColumnHeader column in applicationsListView.Columns) { if (applicationsListView.Items.Count > 0) column.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); else column.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize); } } } private void AddPluginManagerItem() { pluginManagerListViewItem = new ListViewItem(pluginManagerItemName, 0); pluginManagerListViewItem.Group = applicationsListView.Groups["Plugin Management"]; pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, AssemblyHelpers.GetFileVersion(GetType().Assembly))); pluginManagerListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(pluginManagerListViewItem, "Install, upgrade or delete plugins")); pluginManagerListViewItem.ToolTipText = "Install, upgrade or delete plugins"; applicationsListView.Items.Add(pluginManagerListViewItem); } private void AddUpdatePluginsItem() { if (updatesAvailable) { var updateListViewItem = new ListViewItem(updatePluginsItemName, 1); updateListViewItem.Group = applicationsListView.Groups["Plugin Management"]; updateListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(updateListViewItem, "")); updateListViewItem.SubItems.Add(new ListViewItem.ListViewSubItem(updateListViewItem, "Download and install updates")); updateListViewItem.ToolTipText = "Download and install updates"; applicationsListView.Items.Add(updateListViewItem); } } private void CheckUpdatesAvailableAsync() { string pluginPath = Path.GetFullPath(Application.StartupPath); var task = Task.Factory.StartNew(() => { var installationManager = new InstallationManager(pluginPath); IEnumerable installedPlugins = pluginManager.Plugins.OfType(); var remotePlugins = installationManager.GetRemotePluginList(); // if there is a local plugin with same name and same major and minor version then it's an update var pluginsToUpdate = from remotePlugin in remotePlugins let matchingLocalPlugins = from installedPlugin in installedPlugins where installedPlugin.Name == remotePlugin.Name where installedPlugin.Version.Major == remotePlugin.Version.Major where installedPlugin.Version.Minor == remotePlugin.Version.Minor where Util.IsNewerThan(remotePlugin, installedPlugin) select installedPlugin where matchingLocalPlugins.Count() > 0 select remotePlugin; return pluginsToUpdate.Count() > 0; }); task.ContinueWith(t => { try { t.Wait(); updatesAvailable = t.Result; UpdateApplicationsList(); } catch (AggregateException ae) { ae.Handle(ex => { if (ex is InstallationManagerException) { // this is expected when no internet connection is available => do nothing return true; } else { return false; } }); } }); } private void HandleArguments() { try { if (arguments.OfType().Any() && !arguments.OfType().Any()) { InitiateApplicationStart(optimizerItemName); } foreach (var argument in arguments) { if (argument is StartArgument) { var arg = (StartArgument)argument; InitiateApplicationStart(arg.Value); } } } catch (AggregateException ex) { ErrorHandling.ShowErrorDialog(this, "One or more errors occurred while initializing the application.", ex); } } private void InitiateApplicationStart(string appName) { var appDesc = (from desc in pluginManager.Applications where desc.Name.Equals(appName) select desc).SingleOrDefault(); if (appDesc != null) { StartApplication(appDesc, arguments); } else { MessageBox.Show("Cannot start application " + appName + ".", "HeuristicLab", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void StartApplication(ApplicationDescription app, ICommandLineArgument[] args) { splashScreen.Show("Loading " + app.Name); Thread t = new Thread(delegate() { bool stopped = false; do { try { if (!abortRequested) { pluginManager.Run(app, args); } stopped = true; } catch (Exception ex) { stopped = false; ThreadPool.QueueUserWorkItem(delegate(object exception) { ErrorHandling.ShowErrorDialog(this, (Exception)exception); }, ex); Thread.Sleep(5000); // sleep 5 seconds before autorestart } } while (!abortRequested && !stopped && app.AutoRestart); }); t.SetApartmentState(ApartmentState.STA); // needed for the AdvancedOptimizationFrontent t.Start(); } #endregion } }