diff --git a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin index 85e416c3d2..f406f447f4 100644 --- a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin +++ b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin @@ -15,7 +15,7 @@ + class="ICSharpCode.AddInManager2.ShowAddInManagerCommand"/> @@ -36,4 +36,8 @@ + + + diff --git a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj index f68588b24a..126a60a00e 100644 --- a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj +++ b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj @@ -116,6 +116,7 @@ + diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs index 816ec82048..eeb7959e5e 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs @@ -7,24 +7,16 @@ using ICSharpCode.AddInManager2.View; namespace ICSharpCode.AddInManager2 { - public class ShowCommand : SimpleCommand + public class ShowAddInManagerCommand : SimpleCommand { public override void Execute(object parameter) { // Open AddInManager2 main dialog - using (AddInManagerView view = CreateManagerView()) + using (AddInManagerView view = AddInManagerView.Create()) { view.ShowDialog(); } } - - private AddInManagerView CreateManagerView() - { - return new AddInManagerView() - { - Owner = SD.Workbench.MainWindow - }; - } } public class AddInManagerInitializationCommand : SimpleCommand @@ -35,4 +27,14 @@ namespace ICSharpCode.AddInManager2 AddInManagerServices.Setup.RemoveUnreferencedNuGetPackages(); } } + + public class AddInManagerVisualInitializationCommand : SimpleCommand + { + public override void Execute(object parameter) + { + // Initialize UpdateNotifier and let it check for available updates + UpdateNotifier updateNotifier = new UpdateNotifier(); + updateNotifier.StartUpdateLookup(); + } + } } diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs index 8c08465da8..55829a26b0 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs @@ -32,6 +32,37 @@ namespace ICSharpCode.AddInManager2.Model } } + public event EventHandler AddInManagerViewOpened; + + public void OnAddInManagerViewOpened(EventArgs e) + { + if (AddInManagerViewOpened != null) + { + SD.Log.DebugFormatted("[AddInManager2.Events] AddInManagerView opened."); + AddInManagerViewOpened(this, e); + } + } + + public void OnAddInManagerViewOpened() + { + if (AddInManagerViewOpened != null) + { + SD.Log.DebugFormatted("[AddInManager2.Events] AddInManagerView opened."); + AddInManagerViewOpened(this, new EventArgs()); + } + } + + public event EventHandler PackageListDownloadEnded; + + public void OnPackageListDownloadEnded(object sender, PackageListDownloadEndedEventArgs e) + { + if (PackageListDownloadEnded != null) + { + SD.Log.DebugFormatted("[AddInManager2.Events] Package list download ended (success: {0}).", e.WasSuccessful); + PackageListDownloadEnded(sender, e); + } + } + public event EventHandler AddInInstalled; public void OnAddInInstalled(AddInInstallationEventArgs e) diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs index d774903567..8aa2ba62af 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs @@ -15,6 +15,13 @@ namespace ICSharpCode.AddInManager2.Model void OnOperationStarted(EventArgs e); void OnOperationStarted(); + event EventHandler AddInManagerViewOpened; + void OnAddInManagerViewOpened(EventArgs e); + void OnAddInManagerViewOpened(); + + event EventHandler PackageListDownloadEnded; + void OnPackageListDownloadEnded(object sender, PackageListDownloadEndedEventArgs e); + event EventHandler AddInInstalled; void OnAddInInstalled(AddInInstallationEventArgs e); diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageListDownloadEndedEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageListDownloadEndedEventArgs.cs new file mode 100644 index 0000000000..e776f6ee7a --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageListDownloadEndedEventArgs.cs @@ -0,0 +1,28 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.AddInManager2.Model +{ + public class PackageListDownloadEndedEventArgs : EventArgs + { + public PackageListDownloadEndedEventArgs(bool wasSuccessful, bool wasCancelled) + { + this.WasSuccessful = wasSuccessful; + this.WasCancelled = wasCancelled; + } + + public bool WasSuccessful + { + get; + set; + } + + public bool WasCancelled + { + get; + set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/UpdateNotifier.cs b/src/AddIns/Misc/AddInManager2/Project/Src/UpdateNotifier.cs index a5cc41c062..ee4d0bbafb 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/UpdateNotifier.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/UpdateNotifier.cs @@ -2,10 +2,14 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Drawing; using System.Linq; +using System.Reflection; +using System.Windows.Forms; using ICSharpCode.SharpDevelop; using ICSharpCode.AddInManager2.Model; using ICSharpCode.AddInManager2.ViewModel; +using ICSharpCode.AddInManager2.View; namespace ICSharpCode.AddInManager2 { @@ -17,6 +21,9 @@ namespace ICSharpCode.AddInManager2 private IAddInManagerServices _services; private UpdatedAddInsViewModel _updatedAddInViewModel; private bool _isDetached; + private NotifyIcon _notifyIcon; + private bool _hasNotified; + private PackageRepository _firstRepositoryWithUpdates; public UpdateNotifier() : this(AddInManagerServices.Services) @@ -28,38 +35,106 @@ namespace ICSharpCode.AddInManager2 _isDetached = false; _services = services; _updatedAddInViewModel = new UpdatedAddInsViewModel(services); - _updatedAddInViewModel.PackageListDownloadEnded += UpdatedAddInViewModel_PackageListDownloadEnded; + _services.Events.PackageListDownloadEnded += Events_PackageListDownloadEnded; } - public void Detach() + private void NotifyIcon_Click(object sender, EventArgs e) + { + // Remove the notify icon + DestroyIcon(); + + // Show AddInManager window on click + using (AddInManagerView view = AddInManagerView.Create()) + { + var viewModel = view.ViewModel; + if (viewModel != null) + { + // Activate update view explicitly + viewModel.UpdatedAddInsViewModel.IsExpandedInView = true; + var firstRepositoryWithUpdates = + viewModel.UpdatedAddInsViewModel.PackageRepositories.FirstOrDefault(pr => pr.SourceUrl == _firstRepositoryWithUpdates.SourceUrl); + if (firstRepositoryWithUpdates != null) + { + // Directly go to first repository containing an update + viewModel.UpdatedAddInsViewModel.SelectedPackageSource = firstRepositoryWithUpdates; + } + } + _firstRepositoryWithUpdates = null; + view.ShowDialog(); + } + } + + private void DestroyIcon() + { + if (_notifyIcon != null) + { + _notifyIcon.Dispose(); + _notifyIcon = null; + + _services.Events.AddInManagerViewOpened -= Events_AddInManagerViewOpened; + } + } + + private void Detach() { if (!_isDetached) { - _updatedAddInViewModel.PackageListDownloadEnded -= UpdatedAddInViewModel_PackageListDownloadEnded; + _services.Events.PackageListDownloadEnded -= Events_PackageListDownloadEnded; _isDetached = true; } } public void StartUpdateLookup() { - if (!_isDetached) + if (!_isDetached && !_hasNotified) { // Start getting updates _updatedAddInViewModel.ReadPackages(); } } - public void UpdatedAddInViewModel_PackageListDownloadEnded(object sender, EventArgs e) + private void Events_AddInManagerViewOpened(object sender, EventArgs e) + { + // AddInManager dialog has been opened through menu, not through the NotifyIcon -> hide the icon + DestroyIcon(); + } + + private void Events_PackageListDownloadEnded(object sender, PackageListDownloadEndedEventArgs e) { + if (sender != _updatedAddInViewModel) + { + return; + } + + if (e.WasCancelled) + { + return; + } + // Do we have any new updates? Collect this information from all configured repositories - var allRepositories = _updatedAddInViewModel.PackageRepositories; - if (allRepositories != null) + if (e.WasSuccessful) { - if (allRepositories.Any(rep => rep.HasHighlightCount)) + _firstRepositoryWithUpdates = _updatedAddInViewModel.PackageRepositories.FirstOrDefault(pr => pr.HasHighlightCount); + if (_firstRepositoryWithUpdates != null) { - // TODO There must be updates, show an update notification + // There must be updates, show an update notification + _hasNotified = true; Detach(); - SD.MessageService.ShowWarning("There are updates!"); + + _services.Events.AddInManagerViewOpened += Events_AddInManagerViewOpened; + + _notifyIcon = new NotifyIcon(); + _notifyIcon.Icon = Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location); + _notifyIcon.Click += NotifyIcon_Click; + _notifyIcon.BalloonTipClicked += NotifyIcon_Click; + + _notifyIcon.Text = "Updates for SharpDevelop are available"; + _notifyIcon.BalloonTipTitle = "Updates for SharpDevelop are available"; + _notifyIcon.BalloonTipText = "Click here to see the updates"; + + _notifyIcon.Visible = true; + _notifyIcon.ShowBalloonTip(40000); + return; } } diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml.cs b/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml.cs index 3c1c055739..ee1177d139 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml.cs @@ -3,6 +3,7 @@ using System; using System.Windows; +using ICSharpCode.SharpDevelop; using ICSharpCode.AddInManager2.ViewModel; namespace ICSharpCode.AddInManager2.View @@ -16,6 +17,26 @@ namespace ICSharpCode.AddInManager2.View ICSharpCode.SharpDevelop.Gui.FormLocationHelper.ApplyWindow(this, "AddInManager2.WindowBounds", true); } + /// + /// Creates a new instance. + /// + /// New instance. + public static AddInManagerView Create() + { + return new AddInManagerView() + { + Owner = SD.Workbench.MainWindow + }; + } + + public AddInManagerViewModel ViewModel + { + get + { + return DataContext as AddInManagerViewModel; + } + } + public void Dispose() { var viewModel = DataContext as AddInManagerViewModel; diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs index f4b67d66d9..2be93f6687 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs @@ -59,6 +59,8 @@ namespace ICSharpCode.AddInManager2.ViewModel viewModel.PropertyChanged += ViewModel_PropertyChanged; } + AddInManager.Events.OnAddInManagerViewOpened(); + // Expand the first view InstalledAddInsViewModel.IsExpandedInView = true; diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs index 6f2272f438..3156dd7d24 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs @@ -494,7 +494,7 @@ namespace ICSharpCode.AddInManager2.ViewModel } set { - SD.Log.Debug("[AddInManager2] AddInsViewModelBase: Changed package source"); + SD.Log.DebugFormatted("[AddInManager2] AddInsViewModelBase: Changed package source to {0}", (value != null) ? value.Name : ""); _activePackageSource = value; if (_activePackageSource != null) diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs index 98a985af08..0682d62999 100644 --- a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; +using ICSharpCode.SharpDevelop; using ICSharpCode.AddInManager2.Model; using NuGet; @@ -18,8 +19,6 @@ namespace ICSharpCode.AddInManager2.ViewModel private AddInManagerTask _task; private IEnumerable _allPackages; - public event EventHandler PackageListDownloadEnded; - public NuGetAddInsViewModelBase() : base() { @@ -73,8 +72,8 @@ namespace ICSharpCode.AddInManager2.ViewModel private void CreateReadPackagesTask() { _task = AddInManagerTask.Create( - () => GetPackagesForSelectedPageResult(), - (result) => OnPackagesReadForSelectedPage(result)); + GetPackagesForSelectedPageResult, + OnPackagesReadForSelectedPage); // SD.Log.Debug("[AddInManager2] NuGetAddInsViewModelBase: Created task"); } @@ -89,6 +88,8 @@ namespace ICSharpCode.AddInManager2.ViewModel // SD.Log.Debug("[AddInManager2] NuGetAddInsViewModelBase: Task has returned"); IsReadingPackages = false; + bool wasSuccessful = false; + bool wasCancelled = false; if (task.IsFaulted) { SaveError(task.Exception); @@ -97,14 +98,17 @@ namespace ICSharpCode.AddInManager2.ViewModel { // Ignore // SD.Log.Debug("[AddInManager2] NuGetAddInsViewModelBase: Task ignored, because cancelled"); + wasCancelled = true; } else { +// SD.Log.Debug("[AddInManager2] NuGetAddInsViewModelBase: Task successfully finished."); UpdatePackagesForSelectedPage(task.Result); + wasSuccessful = true; } base.OnPropertyChanged(null); - OnPackageListDownloadEnded(); + AddInManager.Events.OnPackageListDownloadEnded(this, new PackageListDownloadEndedEventArgs(wasSuccessful, wasCancelled)); } private void UpdatePackagesForSelectedPage(ReadPackagesResult result) @@ -230,13 +234,5 @@ namespace ICSharpCode.AddInManager2.ViewModel } } } - - private void OnPackageListDownloadEnded() - { - if (PackageListDownloadEnded != null) - { - PackageListDownloadEnded(this, new EventArgs()); - } - } } }