using System; using System.Threading.Tasks; using MonoDevelop.ConnectedServices.Gui.ServicesTab; using MonoDevelop.Core; using MonoDevelop.Components; using System.Threading; using System.Linq; namespace MonoDevelop.ConnectedServices { /// /// Builtin section object that displays the dependencies for the service /// sealed class DependenciesSection: IConfigurationSection { bool isAdded; bool initialized; /// /// Initializes a new instance of the class. /// public DependenciesSection (IConnectedService service) { this.Service = service; this.DisplayName = GettextCatalog.GetString ("Dependencies"); // dependencies are added when the service is added, therefore it's not really optional this.CanBeAdded = false; this.isAdded = this.Service.AreDependenciesInstalled; Service.StatusChanged += HandleServiceStatusChanged; } /// /// Gets the service for this section /// public IConnectedService Service { get; private set; } /// /// Gets the name of the section to display to the user. /// public string DisplayName { get; private set; } /// /// Gets the description of the section to display to the user. /// public string Description { get; private set; } /// /// Gets a value indidating if this section represents something that can be added to the project. /// public bool CanBeAdded { get; private set; } /// /// Gets a value indicating that whatever changes to the project that can be added by this section have been added. /// public bool IsAdded { get { if (!initialized) { isAdded = this.Service.AreDependenciesInstalled; initialized = true; } return isAdded; } private set { if (isAdded != value) { isAdded = value; if (isAdded) NotifyAddedToProject (); else NotifyRemovedFromProject (); } } } /// /// Occurs when the status of the section changes /// public event EventHandler StatusChanged; /// /// Gets the widget to display to the user /// public Control GetSectionWidget () { return new DependenciesSectionWidget (this); } /// /// Adds the service dependencies to the project /// public async Task AddToProject (CancellationToken token) { this.NotifyAddingToProject (); // ask all the dependencies to add themselves to the project // we'll do them one at a time in case there are interdependencies between them // we are going to short circuit package dependencies though and install them in one go var packages = this.Service.Dependencies.OfType ().Cast().ToList(); await this.Service.Project.AddPackageDependencies (packages).ConfigureAwait (false); try { foreach (var dependency in Service.Dependencies) { if (packages.Contains (dependency)) { continue; } await dependency.AddToProject (token).ConfigureAwait (false); } } catch (Exception ex) { LoggingService.LogError ("Could not add dependency", ex); NotifyAddingToProjectFailed (); return IsAdded = false; } return IsAdded = true; } void HandleServiceStatusChanged (object sender, StatusChangedEventArgs e) { // update the status when the service is removed if (e.WasRemoved) { IsAdded = this.Service.AreDependenciesInstalled; } } /// /// Invokes the Adding event on the main thread /// void NotifyAddingToProject () { this.NotifyStatusChange (Status.Adding, Status.NotAdded); } /// /// Notifies subscribers that adding the dependencies to the project has failed /// void NotifyAddingToProjectFailed () { this.NotifyStatusChange (Status.NotAdded, Status.Adding); } /// /// Notifies subscribers that all dependencies have been added to the project /// void NotifyAddedToProject () { this.NotifyStatusChange (Status.Added, Status.Adding); } /// /// Notifies subscribers that a dependency has been removed from the project /// void NotifyRemovedFromProject () { this.NotifyStatusChange (Status.NotAdded, Status.Removing); } void NotifyStatusChange(Status newStatus, Status oldStatus) { var handler = this.StatusChanged; if (handler != null) { // make sure this gets called on the main thread in case we have async calls for adding a nuget Xwt.Application.Invoke (() => { handler (this, new StatusChangedEventArgs (newStatus, oldStatus, null)); }); } } internal void HandleDependenciesChanged () { IsAdded = this.Service.AreDependenciesInstalled; } } }