diff --git a/SharpDevelop.sln b/SharpDevelop.sln index 71430b65a8..976826c80b 100644 --- a/SharpDevelop.sln +++ b/SharpDevelop.sln @@ -105,6 +105,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SharpDevelop.EnvDTE", "src\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageManagement.Cmdlets", "src\AddIns\Misc\PackageManagement\Cmdlets\Project\PackageManagement.Cmdlets.csproj", "{E0A5E80A-003B-4335-A9DC-A76E2E46D38D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddInManager2", "src\AddIns\Misc\AddInManager2\Project\AddInManager2.csproj", "{60480C2F-F228-4D86-B98F-AF75A7DCEC34}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Display Bindings", "Display Bindings", "{11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvalonEdit.AddIn", "src\AddIns\DisplayBindings\AvalonEdit.AddIn\AvalonEdit.AddIn.csproj", "{0162E499-42D0-409B-AA25-EED21F75336B}" @@ -701,6 +703,14 @@ Global {0CD86A0B-73BB-4E7E-B476-AB84389164B1}.Release|Any CPU.Build.0 = Release|Any CPU {0CD86A0B-73BB-4E7E-B476-AB84389164B1}.Release|x86.ActiveCfg = Release|x86 {0CD86A0B-73BB-4E7E-B476-AB84389164B1}.Release|x86.Build.0 = Release|x86 + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Debug|x86.Build.0 = Debug|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Debug|x86.ActiveCfg = Debug|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Release|Any CPU.Build.0 = Release|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Release|x86.Build.0 = Release|Any CPU + {60480C2F-F228-4D86-B98F-AF75A7DCEC34}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -754,6 +764,9 @@ Global {752BD058-5517-48A1-BB27-5ED186FA052B} = {87D549AF-8FCD-4E84-9C33-3DB6E42FEF6D} {E0A5E80A-003B-4335-A9DC-A76E2E46D38D} = {87D549AF-8FCD-4E84-9C33-3DB6E42FEF6D} {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} = {39327899-ED91-4F7F-988C-4FE4E17C014D} + {60480C2F-F228-4D86-B98F-AF75A7DCEC34} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} + {6B1CFE35-DA17-4DEB-9C6E-227E5E251DA0} = {59A30AA6-D600-41AB-B7A1-9543469DBE36} + {0008FCE9-9EB4-4E2E-979B-553278E5BBA6} = {59A30AA6-D600-41AB-B7A1-9543469DBE36} {0162E499-42D0-409B-AA25-EED21F75336B} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {E618A9CD-A39F-4925-A538-E8A3FEF24E54} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {DCA2703D-250A-463E-A68A-07ED105AE6BD} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} diff --git a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin new file mode 100644 index 0000000000..8182d49efa --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.addin @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj new file mode 100644 index 0000000000..a4153aa8e5 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/AddInManager2.csproj @@ -0,0 +1,189 @@ + + + + {60480C2F-F228-4D86-B98F-AF75A7DCEC34} + Debug + AnyCPU + Library + ICSharpCode.AddInManager2 + ICSharpCode.AddInManager2 + v4.5 + False + False + OnBuildSuccess + False + False + 4 + false + False + Auto + 4194304 + AnyCPU + 4096 + False + C:\Users\WheizWork\AppData\Roaming\ICSharpCode/SharpDevelop4\Settings.SourceAnalysis + + + + ..\..\..\..\..\AddIns\Misc\AddInManager2\ + true + Full + False + True + DEBUG;TRACE + Project + + + ..\..\..\..\..\AddIns\Misc\OnlineUpdate\ + false + None + True + False + TRACE + Project + + + + ..\RequiredLibraries\ICSharpCode.SharpZipLib.dll + + + ..\..\PackageManagement\RequiredLibraries\NuGet.Core.dll + True + + + + + + 3.5 + + + + 3.5 + + + + + + + 3.5 + + + + + + Always + + + + + + + + + + + + + + Configuration\GlobalAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AddInManagerView.xaml + + + AddInsView.xaml + + + Code + LicenseAcceptanceView.xaml + + + PagedResultsView.xaml + + + PackageRepositoriesView.xaml + Code + + + + + {2748AD25-9C63-4E12-877B-4DCE96FBED54} + ICSharpCode.SharpDevelop + False + + + {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} + ICSharpCode.Core + False + + + {7E4A7172-7FF5-48D0-B719-7CD959DD1AC9} + ICSharpCode.Core.Presentation + False + + + {857CA1A3-FC88-4BE0-AB6A-D1EE772AB288} + ICSharpCode.Core.WinForms + False + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/AddInManager2/Project/Configuration/AssemblyInfo.cs b/src/AddIns/Misc/AddInManager2/Project/Configuration/AssemblyInfo.cs new file mode 100644 index 0000000000..0af1cd427d --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Configuration/AssemblyInfo.cs @@ -0,0 +1,15 @@ +// 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; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AddInManager2")] +[assembly: AssemblyDescription("AddInManager 2nd Generation for ICSharpCode.Core")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/StringResources.resx b/src/AddIns/Misc/AddInManager2/Project/Resources/StringResources.resx new file mode 100644 index 0000000000..cb0baca542 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Resources/StringResources.resx @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Following installed AddIns are dependent from "{0}": + +{1} + +They will stop working after disabling this AddIn! Are you sure you want to continue? + + + You cannot uninstall the AddInManager because you need it to re-install AddIns! + + + The following packages require a click-to-accept license: + + + Following installed AddIns are dependent from "{0}": + +{1} + +They will stop working after removing this AddIn! Are you sure you want to continue? + + + The following package requires a click-to-accept license: + + + By clicking "I Accept" you agree to the license terms for the packages listed above. +If you do not agree to the license terms click "I Decline". + + + By clicking "I Accept" you agree to the license terms for the package listed above. +If you do not agree to the license terms click "I Decline". + + + I &Accept + + + I &Decline + + + View License Terms + + + Created by: + + + Version: + + + Installed version: + + + New version: + + + Last updated: + + + Downloads: + + + Rating: + + + Report abuse + + + Dependencies: + + + Show preinstalled AddIns + + + Show prereleases + + + Install from archive... + + + Installed + + + Updates + + + Available + + + More information + + + AddIns + + + Repositories + + + Move Up + + + Move Down + + + Remove + + + Add + + + Name: + + + Source: + + + Default Repository + + + License Agreements + + + SharpDevelop AddIns|*.sdaddin|All files|*.* + + + Package "{0}" needs at least one additional package: + +{1} + +The application will try to download and install them, as well. Do you want to continue? + + \ No newline at end of file diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/accept.png b/src/AddIns/Misc/AddInManager2/Project/Resources/accept.png new file mode 100644 index 0000000000..a7d7a96be3 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/accept.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/exclamation.png b/src/AddIns/Misc/AddInManager2/Project/Resources/exclamation.png new file mode 100644 index 0000000000..91f855308f Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/exclamation.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/license.txt b/src/AddIns/Misc/AddInManager2/Project/Resources/license.txt new file mode 100644 index 0000000000..8d4862392a --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Resources/license.txt @@ -0,0 +1,7 @@ +NuGet Package Icon: +License: Apache 2.0 +http://www.apache.org/licenses/LICENSE-2.0 + +Fugue Icons: +License: Creative Commons Attribution 3.0 License +http://p.yusukekamiyamane.com/ \ No newline at end of file diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/magnifier.png b/src/AddIns/Misc/AddInManager2/Project/Resources/magnifier.png new file mode 100644 index 0000000000..1b289ed04b Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/magnifier.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon.png b/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon.png new file mode 100644 index 0000000000..ef5435eb03 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon_small.png b/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon_small.png new file mode 100644 index 0000000000..517705401d Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/packageicon_small.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_next.png b/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_next.png new file mode 100644 index 0000000000..1799620988 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_next.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_previous.png b/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_previous.png new file mode 100644 index 0000000000..cdf1fb0779 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/resultset_previous.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Resources/sd_packageicon.png b/src/AddIns/Misc/AddInManager2/Project/Resources/sd_packageicon.png new file mode 100644 index 0000000000..28730c30d5 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/Project/Resources/sd_packageicon.png differ diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/AddInManager.cs b/src/AddIns/Misc/AddInManager2/Project/Src/AddInManager.cs new file mode 100644 index 0000000000..2de7c532d5 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/AddInManager.cs @@ -0,0 +1,59 @@ +// 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; +using ICSharpCode.AddInManager2.Model; + +namespace ICSharpCode.AddInManager2 +{ + /// + /// Container for public services of AddInManager AddIn. + /// + public class AddInManager + { + private static readonly AddInManagerEvents _events; + private static readonly PackageRepositories _repositories; + private static readonly AddInSetup _setup; + private static readonly NuGetPackageManager _nuGet; + + static AddInManager() + { + _events = new AddInManagerEvents(); + _repositories = new PackageRepositories(); + _nuGet = new NuGetPackageManager(_repositories, _events); + _setup = new AddInSetup(_events, _nuGet); + } + + public static IAddInManagerEvents Events + { + get + { + return _events; + } + } + + public static IPackageRepositories Repositories + { + get + { + return _repositories; + } + } + + public static IAddInSetup Setup + { + get + { + return _setup; + } + } + + public static INuGetPackageManager NuGet + { + get + { + return _nuGet; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/AddInManagerTask.cs b/src/AddIns/Misc/AddInManager2/Project/Src/AddInManagerTask.cs new file mode 100644 index 0000000000..2f692e7775 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/AddInManagerTask.cs @@ -0,0 +1,89 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; + +namespace ICSharpCode.AddInManager2 +{ + public class AddInManagerTask + { + public static AddInManagerTask Create( + Func function, + Action> continueWith) + { + return new AddInManagerTask(function, continueWith); + } + } + + public class AddInManagerTask + { + Task task; + Action> continueWith; + CancellationTokenSource cancellationTokenSource; + + public AddInManagerTask( + Func function, + Action> continueWith) + { + this.continueWith = continueWith; + CreateTask(function); + } + + private void CreateTask(Func function) + { + TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext(); + cancellationTokenSource = new CancellationTokenSource(); + task = new Task(function, cancellationTokenSource.Token); + task.ContinueWith(result => OnContinueWith(result), scheduler); + } + + private void OnContinueWith(Task task) + { + continueWith(this); + } + + public void Start() + { + task.Start(); + } + + public TResult Result + { + get + { + return task.Result; + } + } + + public void Cancel() + { + cancellationTokenSource.Cancel(); + } + + public bool IsCancelled + { + get + { + return task.IsCanceled; + } + } + + public bool IsFaulted + { + get + { + return task.IsFaulted; + } + } + + public AggregateException Exception + { + get + { + return task.Exception; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/BooleanToFontWeightConverter.cs b/src/AddIns/Misc/AddInManager2/Project/Src/BooleanToFontWeightConverter.cs new file mode 100644 index 0000000000..ca3d89a06e --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/BooleanToFontWeightConverter.cs @@ -0,0 +1,48 @@ +// 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; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace ICSharpCode.AddInManager2 +{ + [ValueConversion(typeof(Boolean), typeof(FontWeight))] + public class BooleanToFontWeightConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is Boolean) + { + Boolean fontIsBold = (Boolean)value; + return ConvertToFontWeight(fontIsBold); + } + return DependencyProperty.UnsetValue; + } + + FontWeight ConvertToFontWeight(Boolean bold) + { + if (bold) + { + return FontWeights.Bold; + } + return FontWeights.Normal; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is FontWeight) + { + FontWeight fontWeight = (FontWeight)value; + return ConvertToBoolean(fontWeight); + } + return DependencyProperty.UnsetValue; + } + + bool ConvertToBoolean(FontWeight fontWeight) + { + return fontWeight == FontWeights.Bold; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs new file mode 100644 index 0000000000..7bf44b4967 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Commands.cs @@ -0,0 +1,44 @@ +// 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; +using System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.AddInManager2.View; + +namespace ICSharpCode.AddInManager2 +{ + public class ShowCommand : SimpleCommand + { + public override void Execute(object parameter) + { + // Open AddInManager2 main dialog + using (AddInManagerView view = CreateManagerView()) + { + view.ShowDialog(); + } + } + + private AddInManagerView CreateManagerView() + { + return new AddInManagerView() + { + Owner = SD.Workbench.MainWindow + }; + } + } + + public class AddInManagerInitializationCommand : SimpleCommand + { + public override void Execute(object parameter) + { + // Load string resources needed by AddInManager2 + SD.ResourceService.RegisterStrings("ICSharpCode.AddInManager2.Resources.StringResources", GetType().Assembly); + + // Remove all unreferenced NuGet packages + AddInManager.Setup.RemoveUnreferencedNuGetPackages(); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/DelegateCommand.cs b/src/AddIns/Misc/AddInManager2/Project/Src/DelegateCommand.cs new file mode 100644 index 0000000000..4aac34ed8e --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/DelegateCommand.cs @@ -0,0 +1,51 @@ +// 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; +using System.Windows.Input; + +namespace ICSharpCode.AddInManager2 +{ + public class DelegateCommand : ICommand + { + Action execute; + Predicate canExecute; + + public DelegateCommand(Action execute, Predicate canExecute) + { + this.execute = execute; + this.canExecute = canExecute; + } + + public DelegateCommand(Action execute) + : this(execute, null) + { + } + + public event EventHandler CanExecuteChanged + { + add + { + CommandManager.RequerySuggested += value; + } + remove + { + CommandManager.RequerySuggested -= value; + } + } + + public void Execute(object parameter) + { + execute(parameter); + } + + public bool CanExecute(object parameter) + { + if (canExecute != null) + { + return canExecute(parameter); + } + return true; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/EnumerableExtensions.cs b/src/AddIns/Misc/AddInManager2/Project/Src/EnumerableExtensions.cs new file mode 100644 index 0000000000..ad8188a621 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/EnumerableExtensions.cs @@ -0,0 +1,34 @@ +// 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; +using System.Collections.Generic; +using NuGet; + +namespace ICSharpCode.AddInManager2 +{ + public static class EnumerableExtensions + { + public static IEnumerable DistinctLast(this IEnumerable source, IEqualityComparer comparer) + { + T previousItem = default(T); + + foreach (T currentItem in source) + { + if (previousItem != null) + { + if (!comparer.Equals(previousItem, currentItem)) + { + yield return previousItem; + } + } + previousItem = currentItem; + } + + if (previousItem != null) + { + yield return previousItem; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AcceptLicensesEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AcceptLicensesEventArgs.cs new file mode 100644 index 0000000000..8eed36b553 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AcceptLicensesEventArgs.cs @@ -0,0 +1,29 @@ +// 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; +using System.Collections.Generic; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public class AcceptLicensesEventArgs : EventArgs + { + public AcceptLicensesEventArgs(IEnumerable packages) + { + this.Packages = packages; + } + + public IEnumerable Packages + { + get; + private set; + } + + public bool IsAccepted + { + get; + set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInDependency.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInDependency.cs new file mode 100644 index 0000000000..fcc6ed124a --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInDependency.cs @@ -0,0 +1,143 @@ +// 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; +using System.Text; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Object describing a dependency constraint of an AddIn. + /// + public class AddInDependency + { + public AddInDependency() + { + } + + public AddInDependency(PackageDependency packageDependency) + { + if (packageDependency != null) + { + IVersionSpec versionSpec = packageDependency.VersionSpec; + + Id = packageDependency.Id; + if (versionSpec.MinVersion != null) + { + MinimumVersion = versionSpec.MinVersion.Version; + } + if (versionSpec.MaxVersion != null) + { + MaximumVersion = versionSpec.MaxVersion.Version; + } + IncludeMinimumVersion = packageDependency.VersionSpec.IsMinInclusive; + IncludeMaximumVersion = packageDependency.VersionSpec.IsMaxInclusive; + } + } + + public AddInDependency(AddInReference reference) + { + if (reference != null) + { + Id = reference.Name; + + // Hint: An absolutely minimal or maximal version means no version constraint at all! + Version absMinimumVersion = new Version(0, 0, 0, 0); + Version absMaximumVersion = new Version(Int32.MaxValue, Int32.MaxValue); + + if ((reference.MinimumVersion != null) && (reference.MinimumVersion != absMinimumVersion)) + { + MinimumVersion = reference.MinimumVersion; + } + if ((reference.MaximumVersion != null) && (reference.MaximumVersion != absMaximumVersion)) + { + MaximumVersion = reference.MaximumVersion; + } + + IncludeMinimumVersion = true; + IncludeMaximumVersion = true; + } + } + + public string Id + { + get; + set; + } + + public Version MinimumVersion + { + get; + set; + } + + public bool IncludeMinimumVersion + { + get; + set; + } + + public Version MaximumVersion + { + get; + set; + } + + public bool IncludeMaximumVersion + { + get; + set; + } + + public override string ToString() + { + string printedMinimalDependency = FormatVersionConstraint(MinimumVersion, IncludeMinimumVersion, true); + string printedMaximalDependency = FormatVersionConstraint(MaximumVersion, IncludeMaximumVersion, false); + + StringBuilder formattedDependency = new StringBuilder(); + if (Id != null) + { + formattedDependency.Append(Id); + } + if ((printedMinimalDependency != null) || (printedMaximalDependency != null)) + { + formattedDependency.Append(" ("); + } + if (printedMinimalDependency != null) + { + formattedDependency.Append(printedMinimalDependency); + } + if ((printedMinimalDependency != null) && (printedMaximalDependency != null)) + { + formattedDependency.Append(" && "); + } + if (printedMaximalDependency != null) + { + formattedDependency.Append(printedMaximalDependency); + } + if ((printedMinimalDependency != null) || (printedMaximalDependency != null)) + { + formattedDependency.Append(")"); + } + + return formattedDependency.ToString(); + } + + + private string FormatVersionConstraint(Version version, bool includeVersion, bool isMinimum) + { + if (version == null) + { + return null; + } + else + { + string constraintOperator = isMinimum ? ">" : "<"; + string equalityOperator = includeVersion ? "=" : ""; + return String.Format("{0}{1} {2}", constraintOperator, equalityOperator, version.ToString()); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInExceptionEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInExceptionEventArgs.cs new file mode 100644 index 0000000000..9cc0a54d2b --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInExceptionEventArgs.cs @@ -0,0 +1,24 @@ +// 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 +{ + /// + /// Data for events indicating an exception during package-related operations. + /// + public class AddInExceptionEventArgs : EventArgs + { + public AddInExceptionEventArgs(Exception exception) + { + Exception = exception; + } + + public Exception Exception + { + get; + private set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInInstallationEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInInstallationEventArgs.cs new file mode 100644 index 0000000000..06f61f679f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInInstallationEventArgs.cs @@ -0,0 +1,32 @@ +// 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; +using ICSharpCode.Core; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// EventArgs for local AddIn installation events. + /// + public class AddInInstallationEventArgs : EventArgs + { + public AddInInstallationEventArgs(AddIn addIn) + { + AddIn = addIn; + PreviousVersionRemains = false; + } + + public AddIn AddIn + { + get; + private set; + } + + public bool PreviousVersionRemains + { + get; + set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs new file mode 100644 index 0000000000..5500a1cd91 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInManagerEvents.cs @@ -0,0 +1,104 @@ +// 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; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Catches and broadcasts package-related events. + /// + public class AddInManagerEvents : IAddInManagerEvents + { + public event EventHandler OperationStarted; + + public void OnOperationStarted(EventArgs e) + { + if (OperationStarted != null) + { + OperationStarted(this, e); + } + } + + public event EventHandler AddInInstalled; + + public void OnAddInInstalled(AddInInstallationEventArgs e) + { + if (AddInInstalled != null) + { + AddInInstalled(this, e); + } + } + + public event EventHandler AddInUninstalled; + + public void OnAddInUninstalled(AddInInstallationEventArgs e) + { + if (AddInUninstalled != null) + { + AddInUninstalled(this, e); + } + } + + public event EventHandler AddInOperationError; + + public void OnAddInOperationError(AddInExceptionEventArgs e) + { + if (AddInOperationError != null) + { + AddInOperationError(this, e); + } + } + + public event EventHandler AddInPackageDownloaded; + + public void OnAddInPackageDownloaded(PackageOperationEventArgs e) + { + if (AddInPackageDownloaded != null) + { + AddInPackageDownloaded(this, e); + } + } + + public event EventHandler AddInPackageRemoved; + + public void OnAddInPackageRemoved(PackageOperationEventArgs e) + { + if (AddInPackageRemoved != null) + { + AddInPackageRemoved(this, e); + } + } + + public event EventHandler AddInStateChanged; + + public void OnAddInStateChanged(AddInInstallationEventArgs e) + { + if (AddInStateChanged != null) + { + AddInStateChanged(this, e); + } + } + + public event EventHandler PackageMessageLogged; + + public void OnPackageMessageLogged(PackageMessageLoggedEventArgs e) + { + if (PackageMessageLogged != null) + { + PackageMessageLogged(this, e); + } + } + + public event EventHandler AcceptLicenses; + + public void OnAcceptLicenses(AcceptLicensesEventArgs e) + { + if (AcceptLicenses != null) + { + AcceptLicenses(this, e); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs new file mode 100644 index 0000000000..be4168d45f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/AddInSetup.cs @@ -0,0 +1,655 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpZipLib.Zip; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Helper class for AddIn setup operations. + /// + public class AddInSetup : IAddInSetup + { + private IAddInManagerEvents _events = null; + private INuGetPackageManager _nuGet = null; + + private List _addInsMarkedForInstall; + + public AddInSetup(IAddInManagerEvents events, INuGetPackageManager nuGet) + { + _events = events; + _nuGet = nuGet; + + _addInsMarkedForInstall = new List(); + + // Register event handlers + _events.AddInPackageDownloaded += events_AddInPackageDownloaded; + } + + public IEnumerable AddInsWithMarkedForInstallation + { + get + { + return SD.AddInTree.AddIns.Select(a => new ManagedAddIn(a) { IsTemporary = false, IsUpdate = false }) + .GroupJoin( + _addInsMarkedForInstall, + installedAddIn => installedAddIn.AddIn.Manifest.PrimaryIdentity, + markedAddIn => markedAddIn.AddIn.Manifest.PrimaryIdentity, + (installedAddIn, e) => e.ElementAtOrDefault(0) ?? installedAddIn); + } + } + + private void events_AddInPackageDownloaded(object sender, PackageOperationEventArgs e) + { + try + { + InstallAddIn(e.Package, e.InstallPath); + } + catch (Exception ex) + { + _events.OnAddInOperationError(new AddInExceptionEventArgs(ex)); + } + } + + private AddIn LoadAddInFromZip(ZipFile file) + { + AddIn resultAddIn = null; + ZipEntry addInEntry = null; + foreach (ZipEntry entry in file) + { + if (entry.Name.EndsWith(".addin")) + { + if (addInEntry != null) + { + throw new AddInLoadException("The package may only contain one .addin file."); + } + addInEntry = entry; + } + } + if (addInEntry == null) + { + throw new AddInLoadException("The package must contain one .addin file."); + } + using (Stream s = file.GetInputStream(addInEntry)) + { + using (StreamReader r = new StreamReader(s)) + { + resultAddIn = AddIn.Load(SD.AddInTree, r); + } + } + + return resultAddIn; + } + + public AddIn InstallAddIn(string archiveFileName) + { + if (archiveFileName != null) + { + // Try to load the *.sdaddin file as ZIP archive + AddIn addIn = null; + ZipFile zipFile = new ZipFile(archiveFileName); + try + { + addIn = LoadAddInFromZip(zipFile); + } + finally + { + zipFile.Close(); + } + + if (addIn != null) + { + if (addIn.Manifest.PrimaryIdentity == null) + { + throw new AddInLoadException(ResourceService.GetString("AddInManager.AddInMustHaveIdentity")); + } + + // Try to find this AddIn in current registry + string identity = addIn.Manifest.PrimaryIdentity; + AddIn foundAddIn = null; + foreach (AddIn treeAddIn in SD.AddInTree.AddIns) + { + if (treeAddIn.Manifest.Identities.ContainsKey(identity)) + { + foundAddIn = treeAddIn; + break; + } + } + + // Prevent this AddIn from being uninstalled, if marked for deinstallation + foreach (string installedIdentity in addIn.Manifest.Identities.Keys) + { + ICSharpCode.Core.AddInManager.AbortRemoveUserAddInOnNextStart(installedIdentity); + } + + // Create target directory for AddIn in user profile & copy package contents there + CopyAddInFromZip(addIn, archiveFileName); + + // Install the AddIn using manifest + if (foundAddIn != null) + { + addIn.Action = AddInAction.Update; + } + else + { + addIn.Action = AddInAction.Install; + ((AddInTreeImpl)SD.AddInTree).InsertAddIn(addIn); + } + + // Mark this AddIn + ManagedAddIn markedAddIn = new ManagedAddIn(addIn) + { + IsTemporary = true, + IsUpdate = (foundAddIn != null), + OldVersion = (foundAddIn != null) ? foundAddIn.Version : null + }; + _addInsMarkedForInstall.Add(markedAddIn); + + // Successful installation + AddInInstallationEventArgs eventArgs = new AddInInstallationEventArgs(addIn); + _events.OnAddInInstalled(eventArgs); + _events.OnAddInStateChanged(eventArgs); + + return addIn; + } + else + { + // This is not a valid SharpDevelop AddIn package! + // TODO Throw something. + } + } + + return null; + } + + public AddIn InstallAddIn(IPackage package, string packageDirectory) + { + // Lookup for .addin file in package output + var addInManifestFile = Directory.EnumerateFiles(packageDirectory, "*.addin", SearchOption.TopDirectoryOnly).FirstOrDefault(); + if (addInManifestFile != null) + { + AddIn addIn = AddIn.Load(SD.AddInTree, addInManifestFile); + if (addIn.Manifest.PrimaryIdentity == null) + { + throw new AddInLoadException(ResourceService.GetString("AddInManager.AddInMustHaveIdentity")); + } + + // Try to find this AddIn in current registry + string identity = addIn.Manifest.PrimaryIdentity; + AddIn foundAddIn = null; + foreach (AddIn treeAddIn in SD.AddInTree.AddIns) + { + if (treeAddIn.Manifest.Identities.ContainsKey(identity)) + { + foundAddIn = treeAddIn; + break; + } + } + + // Prevent this AddIn from being uninstalled, if marked for deinstallation + foreach (string installedIdentity in addIn.Manifest.Identities.Keys) + { + ICSharpCode.Core.AddInManager.AbortRemoveUserAddInOnNextStart(installedIdentity); + } + + // Create target directory for AddIn in user profile & copy package contents there + CopyAddInFromPackage(addIn, packageDirectory); + + // Install the AddIn using manifest + if (foundAddIn != null) + { + addIn.Action = AddInAction.Update; + } + else + { + addIn.Action = AddInAction.Install; + ((AddInTreeImpl)SD.AddInTree).InsertAddIn(addIn); + } + + // Mark this AddIn + ManagedAddIn markedAddIn = new ManagedAddIn(addIn) + { + IsTemporary = true, + IsUpdate = (foundAddIn != null), + OldVersion = (foundAddIn != null) ? foundAddIn.Version : null + }; + _addInsMarkedForInstall.Add(markedAddIn); + + // Successful installation + AddInInstallationEventArgs eventArgs = new AddInInstallationEventArgs(addIn); + _events.OnAddInInstalled(eventArgs); + _events.OnAddInStateChanged(eventArgs); + + return addIn; + } + else + { + // This is not a valid SharpDevelop AddIn package! + // TODO Throw something. + } + + return null; + } + + private bool CopyAddInFromZip(AddIn addIn, string zipFile) + { + try + { + string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.AddInInstallTemp, + addIn.Manifest.PrimaryIdentity); + if (Directory.Exists(targetDir)) + { + Directory.Delete(targetDir, true); + } + Directory.CreateDirectory(targetDir); + FastZip fastZip = new FastZip(); + fastZip.CreateEmptyDirectories = true; + fastZip.ExtractZip(zipFile, targetDir, null); + + return true; + } + catch (Exception) + { + return false; + } + } + + private bool CopyAddInFromPackage(AddIn addIn, string packageDirectory) + { + try + { + string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.AddInInstallTemp, + addIn.Manifest.PrimaryIdentity); + if (Directory.Exists(targetDir)) + { + Directory.Delete(targetDir, true); + } + Directory.CreateDirectory(targetDir); + var packageContentsFiles = Directory.EnumerateFiles(packageDirectory, "*.*", SearchOption.TopDirectoryOnly); + if (packageContentsFiles != null) + { + foreach (var file in packageContentsFiles) + { + // Don't copy the .nupkg file + FileInfo fileInfo = new FileInfo(file); + if (fileInfo.Extension != ".nupkg") + { + File.Copy(file, Path.Combine(targetDir, fileInfo.Name)); + } + } + } + + return true; + } + catch (Exception) + { + return false; + } + } + + public void CancelUpdate(AddIn addIn) + { + if (addIn != null) + { + CancelPendingUpdate(addIn); + + // If there is also a NuGet package installed for this, delete it as well + IPackage addInPackage = GetNuGetPackageForAddIn(addIn, true); + if (addInPackage != null) + { + _nuGet.Packages.UninstallPackage(addInPackage, true, false); + } + + AddInInstallationEventArgs eventArgs = new AddInInstallationEventArgs(addIn); + eventArgs.PreviousVersionRemains = true; + _events.OnAddInUninstalled(eventArgs); + _events.OnAddInStateChanged(eventArgs); + } + } + + private void CancelPendingUpdate(AddIn addIn) + { + if (addIn != null) + { + foreach (string identity in addIn.Manifest.Identities.Keys) + { + // Delete from installation temp (if installation or update is pending) + string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.AddInInstallTemp, identity); + if (Directory.Exists(targetDir)) + { + Directory.Delete(targetDir, true); + } + } + + _addInsMarkedForInstall.RemoveAll(markedAddIn => markedAddIn.AddIn == addIn); + } + } + + public void CancelInstallation(AddIn addIn) + { + if (addIn != null) + { + _addInsMarkedForInstall.RemoveAll(markedAddIn => markedAddIn.AddIn == addIn); + UninstallAddIn(addIn); + + // If there is also a NuGet package installed for this, delete it as well + IPackage addInPackage = GetNuGetPackageForAddIn(addIn, true); + if (addInPackage != null) + { + _nuGet.Packages.UninstallPackage(addInPackage, true, false); + } + } + } + + public void CancelUninstallation(AddIn addIn) + { + if (addIn != null) + { + // Abort uninstallation of this AddIn + foreach (string identity in addIn.Manifest.Identities.Keys) + { + ICSharpCode.Core.AddInManager.AbortRemoveUserAddInOnNextStart(identity); + } + ICSharpCode.Core.AddInManager.Enable(new AddIn[] { addIn }); + _events.OnAddInStateChanged(new AddInInstallationEventArgs(addIn)); + } + } + + public void UninstallAddIn(AddIn addIn) + { + if (addIn != null) + { + List addInList = new List(); + addInList.Add(addIn); + ICSharpCode.Core.AddInManager.RemoveExternalAddIns(addInList); + + CancelPendingUpdate(addIn); + foreach (string identity in addIn.Manifest.Identities.Keys) + { + // Remove the user AddIn + string targetDir = Path.Combine(ICSharpCode.Core.AddInManager.UserAddInPath, identity); + if (Directory.Exists(targetDir)) + { + if (!addIn.Enabled) + { + try + { + Directory.Delete(targetDir, true); + continue; + } + catch + { + // TODO Throw something? + } + } + + ICSharpCode.Core.AddInManager.RemoveUserAddInOnNextStart(identity); + } + } + + // Successfully uninstalled + AddInInstallationEventArgs eventArgs = new AddInInstallationEventArgs(addIn); + _events.OnAddInUninstalled(eventArgs); + _events.OnAddInStateChanged(eventArgs); + } + } + + public void SwitchAddInActivation(AddIn addIn) + { + if (addIn != null) + { + // Decide whether to enable or to disable the AddIn + bool disable = addIn.Enabled; + if (addIn.Action == AddInAction.Disable) + { + disable = false; + } + else if (addIn.Action == AddInAction.Enable) + { + disable = true; + } + + if (disable) + { + ICSharpCode.Core.AddInManager.Disable(new AddIn[] { addIn }); + } + else + { + ICSharpCode.Core.AddInManager.Enable(new AddIn[] { addIn }); + } + + _events.OnAddInStateChanged(new AddInInstallationEventArgs(addIn)); + } + } + + public AddIn GetInstalledAddInByIdentity(string identity) + { + if (!String.IsNullOrEmpty(identity)) + { + return SD.AddInTree.AddIns + .Where(a => (a.Manifest != null) && a.Manifest.Identities.ContainsKey(identity)) + .FirstOrDefault(); + } + else + { + return null; + } + } + + public bool IsAddInInstalled(AddIn addIn) + { + if ((addIn == null) || (addIn.Manifest == null)) + { + // Without a valid AddIn instance or a manifest we can't do anything... + return false; + } + + string identity = addIn.Manifest.PrimaryIdentity; + if (!String.IsNullOrEmpty(identity)) + { + return (SD.AddInTree.AddIns + .Where(a => (addIn == a) || ((a.Manifest != null) && a.Manifest.Identities.ContainsKey(identity))) + .FirstOrDefault() != null); + } + else + { + return false; + } + } + + public bool IsAddInPreinstalled(AddIn addIn) + { + if (addIn != null) + { + return + String.Equals(addIn.Properties["addInManagerHidden"], "preinstalled", StringComparison.OrdinalIgnoreCase) + && FileUtility.IsBaseDirectory(FileUtility.ApplicationRootPath, addIn.FileName); + } + else + { + return false; + } + } + + public IPackage GetNuGetPackageForAddIn(AddIn addIn, bool getLatest) + { + if (addIn == null) + { + throw new ArgumentNullException("addIn"); + } + + IPackage package = null; + string nuGetPackageID = null; + if (addIn.Properties.Contains("nuGetPackageID")) + { + nuGetPackageID = addIn.Properties["nuGetPackageID"]; + } + string primaryIdentity = null; + if (addIn.Manifest != null) + { + primaryIdentity = addIn.Manifest.PrimaryIdentity; + } + + if (!String.IsNullOrEmpty(nuGetPackageID)) + { + // Find installed package with mapped NuGet package ID + var matchingPackages = _nuGet.Packages.LocalRepository.GetPackages() + .Where(p => (p.Id == primaryIdentity) || (p.Id == nuGetPackageID)) + .OrderBy(p => p.Version); + if (getLatest) + { + // Return latest package version + package = matchingPackages.LastOrDefault(); + } + else + { + // Return oldest installed package version + package = matchingPackages.FirstOrDefault(); + } + } + + return package; + } + + public AddIn GetAddInForNuGetPackage(IPackage package) + { + return GetAddInForNuGetPackage(package, false); + } + + public AddIn GetAddInForNuGetPackage(IPackage package, bool withAddInsMarkedForInstallation) + { + if (withAddInsMarkedForInstallation) + { + return GetInstalledOrMarkedAddInForNuGetPackage(package); + } + else + { + return GetInstalledAddInForNuGetPackage(package); + } + } + + private AddIn GetInstalledAddInForNuGetPackage(IPackage package) + { + if (package == null) + { + throw new ArgumentNullException("package"); + } + + AddIn foundAddIn = SD.AddInTree.AddIns.Where( + a => ((a.Manifest != null) && (a.Manifest.PrimaryIdentity == package.Id)) + || (a.Properties.Contains("nuGetPackageID") && (a.Properties["nuGetPackageID"] == package.Id))) + .FirstOrDefault(); + + return foundAddIn; + } + + private AddIn GetInstalledOrMarkedAddInForNuGetPackage(IPackage package) + { + if (package == null) + { + throw new ArgumentNullException("package"); + } + + ManagedAddIn foundAddIn = AddInsWithMarkedForInstallation.Where( + a => ((a.AddIn.Manifest != null) && (a.AddIn.Manifest.PrimaryIdentity == package.Id)) + || (a.AddIn.Properties.Contains("nuGetPackageID") && (a.AddIn.Properties["nuGetPackageID"] == package.Id))) + .FirstOrDefault(); + + return (foundAddIn != null) ? foundAddIn.AddIn : null; + } + + public IEnumerable GetDependentAddIns(AddIn addIn) + { + if ((addIn != null) && (addIn.Manifest != null) && (addIn.Manifest.PrimaryIdentity != null)) + { + // Get all AddIns which are dependent from given AddIn + var dependentAddIns = AddInsWithMarkedForInstallation.Where( + a => (a.AddIn.Manifest != null) && a.AddIn.Manifest.Dependencies.Any( + reference => reference.Name == addIn.Manifest.PrimaryIdentity)); + return dependentAddIns; + } + + return null; + } + + public void RemoveUnreferencedNuGetPackages() + { + // Get list of installed NuGet packages + var localRepositoryPackages = _nuGet.Packages.LocalRepository.GetPackages(); + if (localRepositoryPackages != null) + { + List installedNuGetPackages = new List(localRepositoryPackages); + foreach (var installedPackage in installedNuGetPackages) + { + bool removeThisPackage = false; + AddIn addIn = GetAddInForNuGetPackage(installedPackage); + if (addIn == null) + { + // There is no AddIn for this package -> remove it + removeThisPackage = true; + } + else + { + // Try to get the most recent (= with highest version) package for this AddIn + IPackage latestPackage = installedNuGetPackages + .Where(p => p.Id == installedPackage.Id) + .OrderBy(p => p.Version) + .LastOrDefault(); + if (latestPackage.Version != installedPackage.Version) + { + // This is not the most recent installed package for this AddIn -> remove it + removeThisPackage = true; + } + } + + if (removeThisPackage) + { + // We decided to remove this package + LoggingService.InfoFormatted("Removing unreferenced NuGet package {0} {1}.", + installedPackage.Id, installedPackage.Version.ToString()); + _nuGet.Packages.UninstallPackage(installedPackage, true, false); + } + } + } + } + +// private void LoadMappings() +// { +// var savedMappings = PropertyService.Get("AddInManager2.AddInPackageMappings", null); +// if (savedMappings != null) +// { +// foreach (var mapping in savedMappings) +// { +// string[] mappingParts = mapping.Split(new char[] { '|' }, 2); +// if ((mappingParts != null) && (mappingParts.Length == 2)) +// { +// _addInToNuGetMapping[mappingParts[0]] = mappingParts[1]; +// } +// } +// } +// else +// { +// // Save empty mapping +// SaveMappings(); +// } +// } +// +// private void SaveMappings() +// { +// List mappingList = new List(); +// foreach (var mapping in _addInToNuGetMapping) +// { +// mappingList.Add(mapping.Key + "|" + mapping.Value); +// } +// +// PropertyService.Set("AddInManager2.AddInPackageMappings", mappingList.ToArray()); +// } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs new file mode 100644 index 0000000000..8828207538 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInManagerEvents.cs @@ -0,0 +1,41 @@ +// 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; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Interface for AddInManager event service. + /// + public interface IAddInManagerEvents + { + event EventHandler OperationStarted; + void OnOperationStarted(EventArgs e); + + event EventHandler AddInInstalled; + void OnAddInInstalled(AddInInstallationEventArgs e); + + event EventHandler AddInUninstalled; + void OnAddInUninstalled(AddInInstallationEventArgs e); + + event EventHandler AddInOperationError; + void OnAddInOperationError(AddInExceptionEventArgs e); + + event EventHandler AddInPackageDownloaded; + void OnAddInPackageDownloaded(PackageOperationEventArgs e); + + event EventHandler AddInPackageRemoved; + void OnAddInPackageRemoved(PackageOperationEventArgs e); + + event EventHandler AddInStateChanged; + void OnAddInStateChanged(AddInInstallationEventArgs e); + + event EventHandler PackageMessageLogged; + void OnPackageMessageLogged(PackageMessageLoggedEventArgs e); + + event EventHandler AcceptLicenses; + void OnAcceptLicenses(AcceptLicensesEventArgs e); + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInPackage.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInPackage.cs new file mode 100644 index 0000000000..b6f631760e --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInPackage.cs @@ -0,0 +1,130 @@ +// 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; +using System.Collections.Generic; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Describes an AddIn package entry in AddInManager. + /// + public interface IAddInPackage + { + string Name + { + get; + } + + bool HasLicenseUrl + { + get; + } + + Uri LicenseUrl + { + get; + } + + bool HasProjectUrl + { + get; + } + + Uri ProjectUrl + { + get; + } + + bool HasReportAbuseUrl + { + get; + } + + Uri ReportAbuseUrl + { + get; + } + + bool IsAdded + { + get; + } + + IEnumerable Dependencies + { + get; + } + + bool HasDependencies + { + get; + } + + bool HasNoDependencies + { + get; + } + + IEnumerable Authors + { + get; + } + + bool HasDownloadCount + { + get; + } + + string Id + { + get; + } + + Uri IconUrl + { + get; + } + + string Summary + { + get; + } + + Version Version + { + get; + } + + int DownloadCount + { + get; + } + + string Description + { + get; + } + + DateTime? LastUpdated + { + get; + } + + bool HasLastUpdated + { + get; + } + + bool HasVersion + { + get; + } + + bool IsManaged + { + get; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInSetup.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInSetup.cs new file mode 100644 index 0000000000..422258275d --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IAddInSetup.cs @@ -0,0 +1,35 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public interface IAddInSetup + { + IEnumerable AddInsWithMarkedForInstallation + { + get; + } + AddIn InstallAddIn(string archiveFileName); + AddIn InstallAddIn(IPackage package, string packageDirectory); + void UninstallAddIn(AddIn addIn); + void CancelUpdate(AddIn addIn); + void CancelInstallation(AddIn addIn); + void CancelUninstallation(AddIn addIn); + void SwitchAddInActivation(AddIn addIn); + AddIn GetInstalledAddInByIdentity(string identity); + bool IsAddInInstalled(AddIn addIn); + bool IsAddInPreinstalled(AddIn addin); + IPackage GetNuGetPackageForAddIn(AddIn addIn, bool getLatest); + AddIn GetAddInForNuGetPackage(IPackage package); + AddIn GetAddInForNuGetPackage(IPackage package, bool withAddInsMarkedForInstallation); + IEnumerable GetDependentAddIns(AddIn addIn); + void RemoveUnreferencedNuGetPackages(); + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/INuGetPackageManager.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/INuGetPackageManager.cs new file mode 100644 index 0000000000..98a5b68623 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/INuGetPackageManager.cs @@ -0,0 +1,24 @@ +// 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; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public interface INuGetPackageManager + { + IPackageManager Packages + { + get; + } + string PackageOutputDirectory + { + get; + } + bool PackageContainsAddIn(IPackage package); + IPackageOperationResolver CreateInstallPackageOperationResolver(bool allowPrereleaseVersions); + void ExecuteOperation(PackageOperation operation); + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IPackageRepositories.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IPackageRepositories.cs new file mode 100644 index 0000000000..3a2d88990f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Interfaces/IPackageRepositories.cs @@ -0,0 +1,33 @@ +// 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; +using System.Collections.Generic; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public interface IPackageRepositories + { + IPackageRepository Registered + { + get; + } + + IPackageRepository Active + { + get; + } + + PackageSource ActiveSource + { + get; + set; + } + IEnumerable RegisteredPackageSources + { + get; + set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/ManagedAddIn.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/ManagedAddIn.cs new file mode 100644 index 0000000000..59047cc264 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/ManagedAddIn.cs @@ -0,0 +1,60 @@ +// 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; +using ICSharpCode.Core; + +namespace ICSharpCode.AddInManager2.Model +{ + public enum AddInInstallationSource + { + Offline, + NuGetRepository + } + + /// + /// Extension of AddIn class used in AddInManager internally. + /// + public class ManagedAddIn + { + private AddIn _addIn; + + public ManagedAddIn(AddIn addIn) + { + _addIn = addIn; + InstallationSource = AddInInstallationSource.Offline; + } + + public bool IsTemporary + { + get; + set; + } + + public bool IsUpdate + { + get; + set; + } + + public Version OldVersion + { + get; + set; + } + + public AddInInstallationSource InstallationSource + { + get; + set; + } + + public AddIn AddIn + { + get + { + return _addIn; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Model.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Model.cs new file mode 100644 index 0000000000..582cdc104e --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Model.cs @@ -0,0 +1,43 @@ +// 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; +using System.ComponentModel; +using System.Linq.Expressions; + +namespace ICSharpCode.AddInManager2.Model +{ + public abstract class Model : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public string PropertyChangedFor(Expression> expression) + { + MemberExpression memberExpression = expression.Body as MemberExpression; + return PropertyChangedFor(memberExpression); + } + + private string PropertyChangedFor(MemberExpression memberExpression) + { + if (memberExpression != null) + { + return memberExpression.Member.Name; + } + return String.Empty; + } + + protected void OnPropertyChanged(Expression> expression) + { + string propertyName = PropertyChangedFor(expression); + OnPropertyChanged(propertyName); + } + + protected void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageManager.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageManager.cs new file mode 100644 index 0000000000..5ac153c906 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageManager.cs @@ -0,0 +1,155 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Versioning; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Wrapper around native NuGet package manager. + /// + public class NuGetPackageManager : INuGetPackageManager + { + /// + /// Helper for log messages generated by NuGet component. + /// + public class PackageMessageLogger : ILogger + { + IAddInManagerEvents _events = null; + + public PackageMessageLogger(IAddInManagerEvents events) + { + _events = events; + } + + public void Log(MessageLevel level, string message, params object[] args) + { + _events.OnPackageMessageLogged(new PackageMessageLoggedEventArgs(level, message, args)); + } + } + + private NuGetPackageManagerImplementation _packageManager = null; + private IPackageRepositories _repositories = null; + private IAddInManagerEvents _events = null; + private ILogger _logger = null; + private string _packageOutputDirectory; + + public NuGetPackageManager(IPackageRepositories repositories, IAddInManagerEvents events) + { + _repositories = repositories; + _events = events; + _packageOutputDirectory = Path.Combine(PropertyService.ConfigDirectory, "NuGet"); + + _logger = new PackageMessageLogger(_events); + + _events.PackageMessageLogged += Events_PackageMessageLogged; + } + + public IPackageManager Packages + { + get + { + // Create PackageManager instance lazily + return EnsurePackageManagerInstance(); + } + } + + public ILogger Logger + { + get + { + return _logger; + } + } + + public string PackageOutputDirectory + { + get + { + return _packageOutputDirectory; + } + } + + public bool PackageContainsAddIn(IPackage package) + { + return (package != null) && (package.Tags != null) && package.Tags.Contains("SharpDevelopAddIn"); + } + + public IPackageOperationResolver CreateInstallPackageOperationResolver(bool allowPrereleaseVersions) + { + EnsurePackageManagerInstance(); + + return new InstallWalker( + _packageManager.LocalRepository, + _packageManager.SourceRepository, + null, + _logger, + false, + allowPrereleaseVersions); + } + + public void ExecuteOperation(PackageOperation operation) + { + EnsurePackageManagerInstance(); + _packageManager.ExecuteOperation(operation); + } + + private IPackageManager EnsurePackageManagerInstance() + { + if (_packageManager != null) + { + return _packageManager; + } + + // Ensure that package directory exists + if (!Directory.Exists(_packageOutputDirectory)) + { + Directory.CreateDirectory(_packageOutputDirectory); + } + + // Create new package manager instance + _packageManager = new NuGetPackageManagerImplementation(_repositories.Registered, _packageOutputDirectory); + _packageManager.PackageInstalled += _packageEvents_NuGetPackageInstalled; + _packageManager.PackageUninstalled += _packageEvents_NuGetPackageUninstalled; + return _packageManager; + } + + private void _packageEvents_NuGetPackageInstalled(object sender, PackageOperationEventArgs e) + { + // NuGet package has been downloaded and extracted, now install the AddIn from it + // TODO Error management? + + _events.OnAddInPackageDownloaded(e); + } + + private void _packageEvents_NuGetPackageUninstalled(object sender, PackageOperationEventArgs e) + { + _events.OnAddInPackageRemoved(e); + } + + private void Events_PackageMessageLogged(object sender, PackageMessageLoggedEventArgs e) + { + LoggingService.InfoFormatted("[NuGetPackageManager] {0}", e.Message); + } + + private class NuGetPackageManagerImplementation : PackageManager + { + public NuGetPackageManagerImplementation(IPackageRepository sourceRepository, string path) + : base(sourceRepository, path) + { + } + + public void ExecuteOperation(PackageOperation operation) + { + // Allow to call this method from outside of the class + base.Execute(operation); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageOperationEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageOperationEventArgs.cs new file mode 100644 index 0000000000..65bfd12fe7 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/NuGetPackageOperationEventArgs.cs @@ -0,0 +1,25 @@ +// 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; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Event data for operations related to NuGet packages. + /// + public class NuGetPackageOperationEventArgs : EventArgs + { + public NuGetPackageOperationEventArgs(IPackage package) + { + Package = package; + } + + public IPackage Package + { + get; + private set; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageMessageLoggedEventArgs.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageMessageLoggedEventArgs.cs new file mode 100644 index 0000000000..abb6a1ff54 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageMessageLoggedEventArgs.cs @@ -0,0 +1,45 @@ +// 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; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public class PackageMessageLoggedEventArgs : EventArgs + { + public PackageMessageLoggedEventArgs(MessageLevel level, string message, params object[] args) + { + this.Message = new PackageOperationMessage(level, message, args); + } + + public PackageOperationMessage Message + { + get; + private set; + } + } + + public class PackageOperationMessage + { + string message; + object[] args; + + public PackageOperationMessage(MessageLevel level, string message, params object[] args) + { + this.Level = level; + this.message = message; + this.args = args; + } + + public MessageLevel Level + { + get; private set; + } + + public override string ToString() + { + return String.Format(message, args); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepositories.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepositories.cs new file mode 100644 index 0000000000..e42477ca84 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepositories.cs @@ -0,0 +1,136 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + /// + /// Holds reference to currently used NuGet package repositories to install AddIns from. + /// + public class PackageRepositories : IPackageRepositories + { + private IPackageRepository _currentRepository; + private IPackageRepository _activeRepository; + private PackageSource _activeSource; + private List _registeredPackageSources; + + public PackageRepositories() + { + _registeredPackageSources = new List(); + LoadPackageSources(); + UpdateCurrentRepository(); + UpdateActiveRepository(); + } + + public IPackageRepository Registered + { + get + { + return _currentRepository; + } + } + + public IPackageRepository Active + { + get + { + return _activeRepository; + } + } + + public PackageSource ActiveSource + { + get + { + return _activeSource; + } + set + { + _activeSource = value; + UpdateActiveRepository(); + } + } + + public IEnumerable RegisteredPackageSources + { + get + { + return _registeredPackageSources; + } + set + { + _registeredPackageSources.Clear(); + _registeredPackageSources.AddRange(value); + SavePackageSources(); + } + } + + private void LoadPackageSources() + { + _registeredPackageSources.Clear(); + var savedRepositories = SD.PropertyService.Get("AddInManager2.PackageRepositories", null); + if ((savedRepositories != null) && (savedRepositories.Length > 0)) + { + foreach (string repositoryEntry in savedRepositories) + { + string[] splittedEntry = repositoryEntry.Split(new char[] { '=' }, 2); + if ((splittedEntry != null) && (splittedEntry.Length == 2)) + { + // Create PackageSource from this entry + PackageSource savedPackageSource = new PackageSource(splittedEntry[1], splittedEntry[0]); + _registeredPackageSources.Add(savedPackageSource); + } + } + } + else + { + // If we don't have any repositories, so add the default one + PackageSource defaultPackageSource = + new PackageSource("https://nuget.org/api/v2", ResourceService.GetString("AddInManager2.DefaultRepository")); + _registeredPackageSources.Add(defaultPackageSource); + SavePackageSources(); + } + } + + private void SavePackageSources() + { + var savedRepositories = _registeredPackageSources.Select(ps => ps.Name + "=" + ps.Source); + PropertyService.Set("AddInManager2.PackageRepositories", savedRepositories.ToArray()); + UpdateCurrentRepository(); + } + + private void UpdateCurrentRepository() + { + var repositories = + _registeredPackageSources.Select(packageSource => PackageRepositoryFactory.Default.CreateRepository(packageSource.Source)); + if (repositories.Any()) + { + _currentRepository = new AggregateRepository(repositories); + } + } + + private void UpdateActiveRepository() + { + if ((_activeSource == null) && (_registeredPackageSources != null)) + { + _activeSource = _registeredPackageSources[0]; + } + + if (_activeSource != null) + { + _activeRepository = PackageRepositoryFactory.Default.CreateRepository(_activeSource.Source); + } + else + { + // If no active repository is set, get packages from all repositories + _activeRepository = _currentRepository; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepository.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepository.cs new file mode 100644 index 0000000000..0a06938c64 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/PackageRepository.cs @@ -0,0 +1,61 @@ +// 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; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public class PackageRepository : Model + { +// RegisteredPackageSource packageSource; + + public PackageRepository() + { + } + + public PackageRepository(PackageSource packageSource) + { +// this.packageSource = new RegisteredPackageSource(packageSource); + Name = packageSource.Name; + SourceUrl = packageSource.Source; + } + + public string Name + { +// get +// { +// return packageSource.Name; + // TODO +// return null; +// } +// set +// { +// packageSource.Name = value; +// } + get; + set; + } + + public string SourceUrl + { +// get +// { +// return packageSource.Source; + // TODO +// return null; +// } +// set +// { +// packageSource.Source = value; +// } + get; + set; + } + + public PackageSource ToPackageSource() + { + return new PackageSource(SourceUrl, Name); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Page.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Page.cs new file mode 100644 index 0000000000..6a29458d8f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Page.cs @@ -0,0 +1,18 @@ +// 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 Page + { + public int Number { get; set; } + public bool IsSelected { get; set; } + + public override string ToString() + { + return String.Format("[Page] Number={0}, IsSelected={1}", Number, IsSelected); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/Pages.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Pages.cs new file mode 100644 index 0000000000..06e5e42ac6 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/Pages.cs @@ -0,0 +1,155 @@ +// 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; +using System.Collections.ObjectModel; + +namespace ICSharpCode.AddInManager2.Model +{ + public class Pages : ObservableCollection + { + public const int DefaultPageSize = 10; + public const int DefaultMaximumSelectablePages = 5; + + int pageSize = DefaultPageSize; + int selectedPageNumber = 1; + int maximumSelectablePages = DefaultMaximumSelectablePages; + int totalItems = 0; + int itemsOnSelectedPage = 0; + + public int TotalItems { + get { return totalItems; } + set { + if (totalItems != value) { + totalItems = value; + UpdatePages(); + } + } + } + + public int SelectedPageNumber { + get { return selectedPageNumber; } + set { + if (selectedPageNumber != value) { + selectedPageNumber = value; + UpdatePages(); + } + } + } + + public int MaximumSelectablePages { + get { return maximumSelectablePages; } + set { + if (maximumSelectablePages != value) { + maximumSelectablePages = value; + UpdatePages(); + } + } + } + + public int ItemsBeforeFirstPage { + get { + return (selectedPageNumber - 1) * pageSize; + } + } + + public bool IsPaged { + get { return totalItems > pageSize; } + } + + public bool HasPreviousPage { + get { return IsPaged && !IsFirstPageSelected; } + } + + bool IsFirstPageSelected { + get { return selectedPageNumber == 1; } + } + + public bool HasNextPage { + get { return IsPaged && !IsLastPageSelected; } + } + + bool IsLastPageSelected { + get { return selectedPageNumber == TotalPages; } + } + + public int TotalPages { + get { return (totalItems + pageSize - 1) / pageSize; } + } + + public int PageSize { + get { return pageSize; } + set { + if (pageSize != value) { + pageSize = value; + UpdatePages(); + } + } + } + + void UpdatePages() + { + Clear(); + + int startPage = GetStartPage(); + for (int pageNumber = startPage; pageNumber <= TotalPages; ++pageNumber) { + if (Count >= maximumSelectablePages) { + break; + } + Page page = CreatePage(pageNumber); + Add(page); + } + } + + int GetStartPage() + { + // Less pages than can be selected? + int totalPages = TotalPages; + if (totalPages <= maximumSelectablePages) { + return 1; + } + + // First choice for start page. + int startPage = selectedPageNumber - (maximumSelectablePages / 2); + if (startPage <= 0) { + return 1; + } + + // Do we have enough pages? + int totalPagesBasedOnStartPage = totalPages - startPage + 1; + if (totalPagesBasedOnStartPage >= maximumSelectablePages) { + return startPage; + } + + // Ensure we have enough pages. + startPage -= maximumSelectablePages - totalPagesBasedOnStartPage; + if (startPage > 0) { + return startPage; + } + return 1; + } + + Page CreatePage(int pageNumber) + { + var page = new Page(); + page.Number = pageNumber; + page.IsSelected = IsSelectedPage(pageNumber); + return page; + } + + bool IsSelectedPage(int pageNumber) + { + return pageNumber == selectedPageNumber; + } + + public int TotalItemsOnSelectedPage { + get { return itemsOnSelectedPage; } + set { + itemsOnSelectedPage = value; + if (itemsOnSelectedPage < pageSize) { + TotalItems = (selectedPageNumber - 1) * pageSize + itemsOnSelectedPage; + } + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/Model/ReadPackagesResult.cs b/src/AddIns/Misc/AddInManager2/Project/Src/Model/ReadPackagesResult.cs new file mode 100644 index 0000000000..010715c4aa --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/Model/ReadPackagesResult.cs @@ -0,0 +1,25 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.AddInManager2.ViewModel; +using NuGet; + +namespace ICSharpCode.AddInManager2.Model +{ + public class ReadPackagesResult + { + public ReadPackagesResult(IEnumerable packages, int totalPackages) + { + this.Packages = packages; + this.TotalPackagesOnPage = packages.Count(); + this.TotalPackages = totalPackages; + } + + public IEnumerable Packages { get; set; } + public int TotalPackagesOnPage { get; set; } + public int TotalPackages { get; set; } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml b/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml new file mode 100644 index 0000000000..db56187271 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/View/AddInManagerView.xaml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/View/PagedResultsView.xaml.cs b/src/AddIns/Misc/AddInManager2/Project/Src/View/PagedResultsView.xaml.cs new file mode 100644 index 0000000000..1126ba7786 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/View/PagedResultsView.xaml.cs @@ -0,0 +1,16 @@ +// 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; +using System.Windows.Controls; + +namespace ICSharpCode.AddInManager2.View +{ + public partial class PagedResultsView : UserControl + { + public PagedResultsView() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs new file mode 100644 index 0000000000..4052a1b904 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInManagerViewModel.cs @@ -0,0 +1,144 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.AddInManager2.View; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class AddInManagerViewModel : Model, IDisposable + { + private string _message; + private bool _hasError; + + public AddInManagerViewModel() + { + // Visuals + this.Title = ResourceService.GetString("AddInManager.Title"); + + // Add event handlers + AddInManager.Events.OperationStarted += AddInManager_Events_OperationStarted; + AddInManager.Events.AddInOperationError += AddInManager_Events_NuGetPackageOperationError; + AddInManager.Events.AcceptLicenses += AddInManager_Events_AcceptLicenses; + + AvailableAddInsViewModel = new AvailableAddInsViewModel(); + InstalledAddInsViewModel = new InstalledAddInsViewModel(); + UpdatedAddInsViewModel = new UpdatedAddInsViewModel(); + + // Read the packages + AvailableAddInsViewModel.ReadPackages(); + InstalledAddInsViewModel.ReadPackages(); + UpdatedAddInsViewModel.ReadPackages(); + } + + public AvailableAddInsViewModel AvailableAddInsViewModel + { + get; + private set; + } + + public InstalledAddInsViewModel InstalledAddInsViewModel + { + get; + private set; + } + + public UpdatedAddInsViewModel UpdatedAddInsViewModel + { + get; + private set; + } + + public string Title + { +// get { return viewTitle.Title; } + get; + private set; + } + + public void Dispose() + { + AddInManager.Events.AddInOperationError -= AddInManager_Events_NuGetPackageOperationError; + AddInManager.Events.AcceptLicenses -= AddInManager_Events_AcceptLicenses; + } + + private void ShowErrorMessage(string message) + { + this.Message = message; + this.HasError = true; + } + + public string Message + { + get + { + return _message; + } + set + { + _message = value; + OnPropertyChanged(model => model.Message); + } + } + + public bool HasError + { + get + { + return _hasError; + } + set + { + _hasError = value; + OnPropertyChanged(model => model.HasError); + } + } + + private void AddInManager_Events_OperationStarted(object sender, EventArgs e) + { + ClearMessage(); + } + + private void ClearMessage() + { + this.Message = null; + this.HasError = false; + } + + private void AddInManager_Events_NuGetPackageOperationError(object sender, AddInExceptionEventArgs e) + { + ShowErrorMessage(e.Exception.Message); + } + + private void AddInManager_Events_AcceptLicenses(object sender, AcceptLicensesEventArgs e) + { + // Show a license acceptance prompt to the user + e.IsAccepted = ShowLicenseAcceptancePrompt(e.Packages); + } + + private bool ShowLicenseAcceptancePrompt(IEnumerable packages) + { + if (packages == null) + { + // No package -> nothing to accept + return true; + } + + // Create a license acceptance view + var viewModel = new LicenseAcceptanceViewModel(packages); + var view = new LicenseAcceptanceView(); + view.DataContext = viewModel; + view.Owner = SD.Workbench.MainWindow; + return view.ShowDialog() ?? false; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInPackageViewModelBase.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInPackageViewModelBase.cs new file mode 100644 index 0000000000..5f8b5de51f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInPackageViewModelBase.cs @@ -0,0 +1,415 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public abstract class AddInPackageViewModelBase : Model, IAddInPackage + { + private DelegateCommand addPackageCommand; + private DelegateCommand updatePackageCommand; + private DelegateCommand removePackageCommand; + private DelegateCommand disablePackageCommand; + private DelegateCommand cancelInstallationCommand; + private DelegateCommand cancelUpdateCommand; + private DelegateCommand cancelUninstallationCommand; + private DelegateCommand optionsCommand; + + public AddInPackageViewModelBase() + { + CreateCommands(); + } + + private void CreateCommands() + { + addPackageCommand = new DelegateCommand( + param => AddPackage(), + param => !IsAdded && !IsRemoved && !IsInstalled && IsInstallable + ); + updatePackageCommand = new DelegateCommand( + param => UpdatePackage(), + param => !IsAdded && !IsRemoved && IsUpdate && IsInstallable + ); + removePackageCommand = new DelegateCommand( + param => RemovePackage(), + param => !IsAdded && !IsRemoved && IsInstalled && !IsUpdate && IsUninstallable + ); + disablePackageCommand = new DelegateCommand( + param => DisablePackage(), + param => !IsAdded && !IsRemoved && IsInstalled && IsOffline + ); + cancelInstallationCommand = new DelegateCommand( + param => CancelInstallation(), + param => IsAdded && !IsUpdate + ); + cancelUpdateCommand = new DelegateCommand( + param => CancelUpdate(), + param => IsAdded && IsUpdate + ); + cancelUninstallationCommand = new DelegateCommand( + param => CancelUninstallation(), + param => IsRemoved + ); + optionsCommand = new DelegateCommand( + param => ShowOptions(), + param => HasOptions + ); + } + + public ICommand AddPackageCommand + { + get + { + return addPackageCommand; + } + } + + public ICommand UpdatePackageCommand + { + get + { + return updatePackageCommand; + } + } + + public ICommand RemovePackageCommand + { + get + { + return removePackageCommand; + } + } + + public ICommand DisablePackageCommand + { + get + { + return disablePackageCommand; + } + } + + public ICommand CancelInstallationCommand + { + get + { + return cancelInstallationCommand; + } + } + + public ICommand CancelUpdateCommand + { + get + { + return cancelUpdateCommand; + } + } + + public ICommand CancelUninstallationCommand + { + get + { + return cancelUninstallationCommand; + } + } + + public ICommand OptionsCommand + { + get + { + return optionsCommand; + } + } + + public abstract string Name + { + get; + } + + public bool HasLicenseUrl + { + get + { + return LicenseUrl != null; + } + } + + public bool HasProjectUrl + { + get + { + return ProjectUrl != null; + } + } + + public bool HasReportAbuseUrl + { + get + { + return ReportAbuseUrl != null; + } + } + + public bool HasNoDependencies + { + get + { + return !HasDependencies; + } + } + + public bool HasLastUpdated + { + get + { + return LastUpdated.HasValue; + } + } + + public abstract bool HasDependencyConflicts + { + get; + } + + public bool HasVersion + { + get + { + return !ShowSplittedVersions && (Version != null) && (Version.ToString() != "0.0.0.0"); + } + } + + public bool HasOldVersion + { + get + { + return ShowSplittedVersions && (OldVersion != null) && (OldVersion.ToString() != "0.0.0.0"); + } + } + + public bool HasNewVersion + { + get + { + return ShowSplittedVersions && (Version != null) && (Version.ToString() != "0.0.0.0"); + } + } + + public virtual bool ShowSplittedVersions + { + get + { + return false; + } + } + + public abstract bool IsOffline + { + get; + } + + public abstract bool IsPreinstalled + { + get; + } + + public abstract bool IsEnabled + { + get; + } + + public abstract bool IsRemoved + { + get; + } + + public virtual bool HasNuGetConnection + { + get + { + return false; + } + } + + public virtual void AddPackage() + { + } + + public virtual void UpdatePackage() + { + } + + public virtual void RemovePackage() + { + } + + public virtual void DisablePackage() + { + } + + public virtual void CancelInstallation() + { + } + + public virtual void CancelUpdate() + { + } + + public virtual void CancelUninstallation() + { + } + + public virtual void ShowOptions() + { + + } + + public void UpdateInstallationState() + { + OnPropertyChanged(m => m.IsAdded); + OnPropertyChanged(m => m.IsUpdate); + OnPropertyChanged(m => m.IsInstallable); + OnPropertyChanged(m => m.IsInstalled); + OnPropertyChanged(m => m.IsEnabled); + OnPropertyChanged(m => m.IsRemoved); + OnPropertyChanged(m => m.Summary); + } + + public bool IsManaged + { + get + { + // if (selectedProjects.HasMultipleProjects()) { + // return true; + // } + // return !selectedProjects.HasSingleProjectSelected(); + return false; + } + } + + public abstract Uri LicenseUrl + { + get; + } + + public abstract Uri ProjectUrl + { + get; + } + + public abstract Uri ReportAbuseUrl + { + get; + } + + public abstract bool IsAdded + { + get; + } + + public abstract bool IsUpdate + { + get; + } + + public abstract bool IsInstalled + { + get; + } + + public abstract bool IsInstallable + { + get; + } + + public abstract bool IsUninstallable + { + get; + } + + public abstract IEnumerable Dependencies + { + get; + } + + public virtual bool HasDependencies + { + get + { + return (Dependencies != null) && Dependencies.Any(); + } + } + + public abstract IEnumerable Authors + { + get; + } + + public abstract bool HasDownloadCount + { + get; + } + + public abstract string Id + { + get; + } + + public abstract Uri IconUrl + { + get; + } + + public abstract string Summary + { + get; + } + + public abstract Version Version + { + get; + } + + public virtual Version OldVersion + { + get + { + return null; + } + } + + + public virtual bool HasOptions + { + get + { + return false; + } + } + + public abstract int DownloadCount + { + get; + } + + public abstract string Description + { + get; + } + + public abstract DateTime? LastUpdated + { + get; + } + + protected string SurroundWithParantheses(string content) + { + return "(" + content + ")"; + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs new file mode 100644 index 0000000000..0529b5716a --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AddInsViewModelBase.cs @@ -0,0 +1,430 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public abstract class AddInsViewModelBase : Model, IDisposable + { + private Pages _pages; + private int _highlightCount; + private string _title; + + public AddInsViewModelBase() + { + _pages = new Pages(); + _highlightCount = 0; + AddInPackages = new ObservableCollection(); + ErrorMessage = String.Empty; + + CreateCommands(); + } + + void CreateCommands() + { + ShowNextPageCommand = new DelegateCommand(param => ShowNextPage()); + ShowPreviousPageCommand = new DelegateCommand(param => ShowPreviousPage()); + ShowPageCommand = new DelegateCommand(param => ExecuteShowPageCommand(param)); + SearchCommand = new DelegateCommand(param => Search()); + UpdatePreinstalledFilterCommand = new DelegateCommand(param => UpdatePreinstalledFilter()); + UpdatePrereleaseFilterCommand = new DelegateCommand(param => UpdatePrereleaseFilter()); + InstallFromArchiveCommand = new DelegateCommand(param => InstallFromArchive()); + } + + public ICommand ShowNextPageCommand + { + get; + private set; + } + + public ICommand ShowPreviousPageCommand + { + get; + private set; + } + + public ICommand ShowPageCommand + { + get; + private set; + } + + public ICommand SearchCommand + { + get; + private set; + } + + public ICommand UpdatePreinstalledFilterCommand + { + get; + private set; + } + + public ICommand UpdatePrereleaseFilterCommand + { + get; + private set; + } + + public ICommand InstallFromArchiveCommand + { + get; + private set; + } + + public void Dispose() + { + OnDispose(); + IsDisposed = true; + } + + protected virtual void OnDispose() + { + } + + public bool IsDisposed + { + get; + protected set; + } + + public bool HasError + { + get; + protected set; + } + + public string ErrorMessage + { + get; + protected set; + } + + public int HighlightCount + { + get + { + return _highlightCount; + } + protected set + { + _highlightCount = value; + OnPropertyChanged(vm => vm.HighlightCount); + OnPropertyChanged(vm => vm.HasHighlightCount); + OnPropertyChanged(vm => vm.TitleWithHighlight); + } + } + + public bool HasHighlightCount + { + get + { + return (_highlightCount > 0); + } + } + + public string Title + { + get + { + return _title; + } + set + { + _title = value; + OnPropertyChanged(vm => vm.HighlightCount); + OnPropertyChanged(vm => vm.HasHighlightCount); + OnPropertyChanged(vm => vm.TitleWithHighlight); + } + } + + public string TitleWithHighlight + { + get + { + if (_highlightCount > 0) + { + return String.Format("{0} ({1})", Title, _highlightCount); + } + else + { + return Title; + } + } + } + + public ObservableCollection AddInPackages + { + get; + private set; + } + + public ObservableCollection Pages + { + get + { + return _pages; + } + } + + protected Pages PagesCollection + { + get + { + return _pages; + } + } + + public bool IsReadingPackages + { + get; + protected set; + } + + public virtual void ReadPackages() + { + _pages.SelectedPageNumber = 1; + } + + protected void SaveError(AggregateException ex) + { + HasError = true; + ErrorMessage = GetErrorMessage(ex); + ICSharpCode.Core.LoggingService.Debug(ex); + } + + protected string GetErrorMessage(AggregateException ex) + { + StringBuilder errorMessage = new StringBuilder(); + BuildErrorMessage(ex.InnerExceptions, errorMessage); + return errorMessage.ToString().TrimEnd(); + } + + private void BuildErrorMessage(IEnumerable exceptions, StringBuilder errorMessage) + { + foreach (Exception ex in exceptions) + { + var aggregateEx = ex as AggregateException; + if (aggregateEx != null) + { + BuildErrorMessage(aggregateEx.InnerExceptions, errorMessage); + } + else + { + errorMessage.AppendLine(ex.Message); + } + } + } + + protected void UpdatePackageViewModels(IEnumerable newPackageViewModels) + { + ClearPackages(); + AddInPackages.AddRange(newPackageViewModels); + UpdateInstallationState(); + } + + protected void ClearPackages() + { + AddInPackages.Clear(); + } + + public virtual int SelectedPageNumber + { + get + { + return _pages.SelectedPageNumber; + } + set + { + if (_pages.SelectedPageNumber != value) + { + _pages.SelectedPageNumber = value; + } + } + } + + public int PageSize + { + get + { + return _pages.PageSize; + } + set + { + _pages.PageSize = value; + } + } + + public bool IsPaged + { + get + { + return _pages.IsPaged; + } + } + + public bool HasPreviousPage + { + get + { + return _pages.HasPreviousPage; + } + } + + public bool HasNextPage + { + get + { + return _pages.HasNextPage; + } + } + + public int MaximumSelectablePages + { + get + { + return _pages.MaximumSelectablePages; + } + set + { + _pages.MaximumSelectablePages = value; + } + } + + public int TotalItems + { + get; + protected set; + } + + public void ShowNextPage() + { + SelectedPageNumber += 1; + } + + public void ShowPreviousPage() + { + SelectedPageNumber -= 1; + } + + private void ExecuteShowPageCommand(object param) + { + int pageNumber = (int)param; + ShowPage(pageNumber); + } + + public void ShowPage(int pageNumber) + { + SelectedPageNumber = pageNumber; + } + + public bool IsSearchable + { + get; + set; + } + + public bool HasFilterForPreinstalled + { + get; + set; + } + + public bool HasFilterForPrereleases + { + get; + set; + } + + public bool AllowInstallFromArchive + { + get; + set; + } + + public string SearchTerms + { + get; + set; + } + + public void Search() + { + ReadPackages(); + OnPropertyChanged(null); + } + + protected virtual void UpdatePreinstalledFilter() + { + } + + protected virtual void UpdatePrereleaseFilter() + { + } + + protected virtual void InstallFromArchive() + { + } + + public bool ShowPackageSources + { + get; + set; + } + + public IEnumerable PackageSources + { + get + { + foreach (PackageSource packageSource in AddInManager.Repositories.RegisteredPackageSources) + { + yield return packageSource; + } + } + } + + public PackageSource SelectedPackageSource + { + get + { + return AddInManager.Repositories.ActiveSource; + } + set + { + AddInManager.Repositories.ActiveSource = value; + ReadPackages(); + } + } + + public bool ShowPreinstalledAddIns + { + get; + set; + } + + public bool ShowPrereleases + { + get; + set; + } + + public void UpdateInstallationState() + { + // Update installation-state-related properties of all AddIn items in here + foreach (var packageViewModel in AddInPackages) + { + packageViewModel.UpdateInstallationState(); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AvailableAddInsViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AvailableAddInsViewModel.cs new file mode 100644 index 0000000000..ba0e950ea4 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/AvailableAddInsViewModel.cs @@ -0,0 +1,66 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class AvailableAddInsViewModel : NuGetAddInsViewModelBase + { + public AvailableAddInsViewModel() + : base() + { + IsSearchable = true; + ShowPackageSources = true; + Title = ResourceService.GetString("AddInManager2.Views.Available"); + + AddInManager.Events.AddInInstalled += AddInInstallationStateChanged; + AddInManager.Events.AddInUninstalled += AddInInstallationStateChanged; + AddInManager.Events.AddInStateChanged += AddInInstallationStateChanged; + } + + protected override void OnDispose() + { + AddInManager.Events.AddInInstalled -= AddInInstallationStateChanged; + AddInManager.Events.AddInUninstalled -= AddInInstallationStateChanged; + AddInManager.Events.AddInStateChanged += AddInInstallationStateChanged; + } + + protected override IQueryable GetAllPackages() + { + return AddInManager.Repositories.Active.GetPackages(); + } + + protected override IEnumerable GetFilteredPackagesBeforePagingResults(IQueryable allPackages) + { + return base.GetFilteredPackagesBeforePagingResults(allPackages) + .Where(package => AddInManager.NuGet.PackageContainsAddIn(package)) + .Where(package => package.IsReleaseVersion()) + .DistinctLast(PackageEqualityComparer.Id); + } + + protected override IQueryable OrderPackages(IQueryable packages) + { + return packages.OrderByDescending(package => package.DownloadCount); + } + + protected override void UpdatePrereleaseFilter() + { + ReadPackages(); + } + + private void AddInInstallationStateChanged(object sender, AddInInstallationEventArgs e) + { + UpdateInstallationState(); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/InstalledAddInsViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/InstalledAddInsViewModel.cs new file mode 100644 index 0000000000..5359cde867 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/InstalledAddInsViewModel.cs @@ -0,0 +1,165 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.Core; +using Microsoft.Win32; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class InstalledAddInsViewModel : NuGetAddInsViewModelBase + { + public InstalledAddInsViewModel() + : base() + { + AllowInstallFromArchive = true; + HasFilterForPreinstalled = true; + Title = ResourceService.GetString("AddInManager2.Views.Installed"); + + // Load preinstalled AddIn filter + LoadPreinstalledAddInFilter(); + + AddInManager.Events.AddInInstalled += InstalledAddInsChanged; + AddInManager.Events.AddInUninstalled += InstalledAddInsChanged; + AddInManager.Events.AddInStateChanged += InstalledAddInStateChanged; + } + + protected override void OnDispose() + { + AddInManager.Events.AddInInstalled -= InstalledAddInsChanged; + AddInManager.Events.AddInUninstalled -= InstalledAddInsChanged; + AddInManager.Events.AddInStateChanged -= InstalledAddInStateChanged; + } + + protected override IQueryable GetAllPackages() + { + return AddInManager.NuGet.Packages.LocalRepository.GetPackages(); + } + + protected override IEnumerable GetFilteredPackagesBeforePagingResults(IQueryable allPackages) + { + return base.GetFilteredPackagesBeforePagingResults(allPackages) + .Where(package => package.IsReleaseVersion()) + .DistinctLast(PackageEqualityComparer.Id); + } + + protected override void UpdatePackageViewModels(IEnumerable packages) + { + IEnumerable offlineAddInViewModels = GetInstalledAddIns(packages); +// IEnumerable nuGetViewModels = ConvertToAddInViewModels(packages); + + // Merge lists of offline entries (internal AddIn objects) and online entries (installed NuGet packages) +// IEnumerable viewModels = CombineOnlineAndOfflineAddIns(nuGetViewModels, offlineAddInViewModels); +// UpdatePackageViewModels(viewModels.OrderBy(vm => vm.Name)); + + UpdatePackageViewModels(offlineAddInViewModels.OrderBy(vm => vm.Name)); + } + + private IEnumerable CombineOnlineAndOfflineAddIns( + IEnumerable onlineAddIns, IEnumerable offlineAddIns) + { + return offlineAddIns.GroupJoin( + onlineAddIns, + offlinevm => offlinevm.Id, + onlinevm => onlinevm.Id, + (offlinevm, e) => e.ElementAtOrDefault(0) ?? offlinevm); + } + + private IEnumerable GetInstalledAddIns(IEnumerable installedPackages) + { + AddInPackageViewModelBase addInPackage; + + // Fill set of ID of installed NuGet packages, so we can later quickly check, whether NuGet package is installed for an AddIn + HashSet nuGetPackageIDs = new HashSet(); + foreach (IPackage package in installedPackages) + { + if (!nuGetPackageIDs.Contains(package.Id)) + { + nuGetPackageIDs.Add(package.Id); + } + } + + List addInList = new List(AddInManager.Setup.AddInsWithMarkedForInstallation); + addInList.Sort(delegate(ManagedAddIn a, ManagedAddIn b) + { + return a.AddIn.Name.CompareTo(b.AddIn.Name); + }); + foreach (ManagedAddIn addIn in addInList) + { + if (string.Equals(addIn.AddIn.Properties["addInManagerHidden"], "true", StringComparison.OrdinalIgnoreCase)) + { + // This excludes the SharpDevelop application appearing as AddIn in the tree + continue; + } + if (!ShowPreinstalledAddIns && AddInManager.Setup.IsAddInPreinstalled(addIn.AddIn)) + { + continue; + } + + string nuGetPackageID = addIn.AddIn.Properties["nuGetPackageID"]; + if (!string.IsNullOrEmpty(nuGetPackageID)) + { + if (nuGetPackageIDs.Contains(nuGetPackageID)) + { + addIn.InstallationSource = AddInInstallationSource.NuGetRepository; + } + } + + addInPackage = new OfflineAddInsViewModelBase(addIn); + yield return addInPackage; + } + } + + protected override void UpdatePreinstalledFilter() + { + // Save the preinstalled AddIn filter + SavePreinstalledAddInFilter(); + + // Update the list + Search(); + } + + private void InstalledAddInsChanged(object sender, AddInInstallationEventArgs e) + { + ReadPackages(); + } + + private void InstalledAddInStateChanged(object sender, AddInInstallationEventArgs e) + { + UpdateInstallationState(); + } + + private void LoadPreinstalledAddInFilter() + { + ShowPreinstalledAddIns = PropertyService.Get("AddInManager2.ShowPreinstalledAddIns", false); + } + + private void SavePreinstalledAddInFilter() + { + PropertyService.Set("AddInManager2.ShowPreinstalledAddIns", ShowPreinstalledAddIns); + } + + protected override void InstallFromArchive() + { + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Filter = ResourceService.GetString("AddInManager2.SDAddInFileFilter"); + dlg.Multiselect = true; + var showDialogResult = dlg.ShowDialog(); + if (showDialogResult.HasValue && showDialogResult.Value) + { + foreach (var file in dlg.FileNames) + { + AddInManager.Setup.InstallAddIn(file); + } + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/LicenseAcceptanceViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/LicenseAcceptanceViewModel.cs new file mode 100644 index 0000000000..cc9e9bb29d --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/LicenseAcceptanceViewModel.cs @@ -0,0 +1,45 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.AddInManager2.Model; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class LicenseAcceptanceViewModel : Model + { + IList packages; + + public LicenseAcceptanceViewModel(IEnumerable packages) + { + this.packages = packages.ToList(); + } + + public IEnumerable Packages + { + get + { + return packages; + } + } + + public bool HasOnePackage + { + get + { + return packages.Count == 1; + } + } + + public bool HasMultiplePackages + { + get + { + return packages.Count > 1; + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs new file mode 100644 index 0000000000..15ce36d0c9 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetAddInsViewModelBase.cs @@ -0,0 +1,213 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class NuGetAddInsViewModelBase : AddInsViewModelBase + { + private AddInManagerTask _task; + private IEnumerable _allPackages; + + public NuGetAddInsViewModelBase() + : base() + { + } + + /// + /// Returns all the packages. + /// + protected virtual IQueryable GetAllPackages() + { + return null; + } + + public override void ReadPackages() + { + base.ReadPackages(); + _allPackages = null; + UpdateRepositoryBeforeReadPackagesTaskStarts(); + StartReadPackagesTask(); + } + + private void StartReadPackagesTask() + { + IsReadingPackages = true; + HasError = false; + ClearPackages(); + CancelReadPackagesTask(); + CreateReadPackagesTask(); + _task.Start(); + } + + protected virtual void UpdateRepositoryBeforeReadPackagesTaskStarts() + { + } + + private void CancelReadPackagesTask() + { + if (_task != null) + { + _task.Cancel(); + } + } + + private void CreateReadPackagesTask() + { + _task = AddInManagerTask.Create( + () => GetPackagesForSelectedPageResult(), + (result) => OnPackagesReadForSelectedPage(result)); + } + + private ReadPackagesResult GetPackagesForSelectedPageResult() + { + IEnumerable packages = GetPackagesForSelectedPage(); + return new ReadPackagesResult(packages, TotalItems); + } + + private void OnPackagesReadForSelectedPage(AddInManagerTask task) + { + IsReadingPackages = false; + if (task.IsFaulted) + { + SaveError(task.Exception); + } + else if (task.IsCancelled) + { + // Ignore + } + else + { + UpdatePackagesForSelectedPage(task.Result); + } + base.OnPropertyChanged(null); + } + + private void UpdatePackagesForSelectedPage(ReadPackagesResult result) + { + PagesCollection.TotalItems = result.TotalPackages; + PagesCollection.TotalItemsOnSelectedPage = result.TotalPackagesOnPage; + UpdatePackageViewModels(result.Packages); + } + + private void PagesChanged(object sender, NotifyCollectionChangedEventArgs e) + { + StartReadPackagesTask(); + base.OnPropertyChanged(null); + } + + private IEnumerable GetPackagesForSelectedPage() + { + IEnumerable filteredPackages = GetFilteredPackagesBeforePagingResults(); + return GetPackagesForSelectedPage(filteredPackages); + } + + private IEnumerable GetFilteredPackagesBeforePagingResults() + { + if (_allPackages == null) + { + IQueryable packages = GetAllPackages(); + packages = OrderPackages(packages); + packages = FilterPackagesBySearchCriteria(packages); + TotalItems = packages.Count(); + _allPackages = GetFilteredPackagesBeforePagingResults(packages); + } + return _allPackages; + } + + protected virtual IQueryable OrderPackages(IQueryable packages) + { + return packages + .OrderBy(package => package.Id); + } + + private IQueryable FilterPackagesBySearchCriteria(IQueryable packages) + { + string searchCriteria = GetSearchCriteria(); + return FilterPackagesBySearchCriteria(packages, searchCriteria); + } + + private string GetSearchCriteria() + { + if (String.IsNullOrWhiteSpace(SearchTerms)) + { + return null; + } + return SearchTerms; + } + + protected IQueryable FilterPackagesBySearchCriteria(IQueryable packages, string searchCriteria) + { + return packages.Find(searchCriteria); + } + + private IEnumerable GetPackagesForSelectedPage(IEnumerable allPackages) + { + int packagesToSkip = PagesCollection.ItemsBeforeFirstPage; + return allPackages + .Skip(packagesToSkip) + .Take(PagesCollection.PageSize); + } + + /// + /// Allows filtering of the packages before paging the results. Call base class method + /// to run default filtering. + /// + protected virtual IEnumerable GetFilteredPackagesBeforePagingResults(IQueryable allPackages) + { + return GetBufferedPackages(allPackages) + .Where(package => package.IsReleaseVersion()) + .DistinctLast(PackageEqualityComparer.Id); + } + + private IEnumerable GetBufferedPackages(IQueryable allPackages) + { + return allPackages.AsBufferedEnumerable(30); + } + + protected virtual void UpdatePackageViewModels(IEnumerable packages) + { + IEnumerable currentViewModels = ConvertToAddInViewModels(packages); + UpdatePackageViewModels(currentViewModels); + } + + protected IEnumerable ConvertToAddInViewModels(IEnumerable packages) + { + foreach (IPackage package in packages) + { + yield return CreateAddInViewModel(package); + } + } + + protected virtual AddInPackageViewModelBase CreateAddInViewModel(IPackage package) + { + return new NuGetPackageViewModel(package); + } + + public override int SelectedPageNumber + { + get + { + return base.SelectedPageNumber; + } + set + { + if (base.SelectedPageNumber != value) + { + base.SelectedPageNumber = value; + StartReadPackagesTask(); + base.OnPropertyChanged(null); + } + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs new file mode 100644 index 0000000000..e421fdf8ce --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/NuGetPackageViewModel.cs @@ -0,0 +1,464 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class NuGetPackageViewModel : AddInPackageViewModelBase + { + private IPackage _package; + private IEnumerable _packageOperations = new PackageOperation[0]; + + public NuGetPackageViewModel(IPackage package) + : base() + { + this._package = package; + } + + public IPackage Package + { + get + { + return _package; + } + } + + public override string Name + { + get + { + return _package.Id; + } + } + + public override Uri LicenseUrl + { + get + { + return _package.LicenseUrl; + } + } + + public override Uri ProjectUrl + { + get + { + return _package.ProjectUrl; + } + } + + public override Uri ReportAbuseUrl + { + get + { + return _package.ReportAbuseUrl; + } + } + + public override bool IsOffline + { + get + { + return false; + } + } + + public override bool IsPreinstalled + { + get + { + return false; + } + } + + public override bool IsAdded + { + get + { + AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package, true); + +// if (installedAddIn != null) +// LoggingService.DebugFormatted("isAdded: installedAddIn.Action = {0}", installedAddIn.Action); +// else +// LoggingService.DebugFormatted("isAdded: installedAddIn for {0} is null", _package.Id); + + return (installedAddIn != null) && ((installedAddIn.Action == AddInAction.Install) || (installedAddIn.Action == AddInAction.Update)); + } + } + + public override bool IsUpdate + { + get + { + AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); + +// if (installedAddIn != null) +// LoggingService.DebugFormatted("isUpdate: installed {0}, package {1}", installedAddIn.Version.ToString(), _package.Version.Version.ToString()); +// else +// LoggingService.DebugFormatted("isUpdate: installedAddIn for {0} is null", _package.Id); + + return (installedAddIn != null) + && AddInManager.Setup.IsAddInInstalled(installedAddIn) + && (installedAddIn.Version < _package.Version.Version); + } + } + + public override bool IsInstalled + { + get + { + AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); + return (installedAddIn != null) && AddInManager.Setup.IsAddInInstalled(installedAddIn); + } + } + + public override bool IsInstallable + { + get + { + return true; + } + } + + public override bool IsUninstallable + { + get + { + return true; + } + } + + public override bool IsEnabled + { + get + { + return true; + } + } + + public override bool IsRemoved + { + get + { + AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); + return (installedAddIn != null) && (installedAddIn.Action == AddInAction.Uninstall); + } + } + + private bool IsPackageInstalled() + { + return AddInManager.NuGet.Packages.LocalRepository.Exists(_package); + } + + public override IEnumerable Dependencies + { + get + { + if ((_package.DependencySets != null) && _package.DependencySets.Any()) + { + PackageDependencySet firstSet = _package.DependencySets.First(); + if ((firstSet != null) && (firstSet.Dependencies != null) && (firstSet.Dependencies.Count > 0)) + { + return firstSet.Dependencies.Select(d => new AddInDependency(d)); + } + } + return null; + } + } + + public override IEnumerable Authors + { + get + { + return _package.Authors; + } + } + + public override bool HasDownloadCount + { + get + { + return _package.DownloadCount >= 0; + } + } + + public override string Id + { + get + { + return _package.Id; + } + } + + public override Uri IconUrl + { + get + { + return _package.IconUrl; + } + } + + public override string Summary + { + get + { + if (IsAdded) + { + if (IsUpdate) + { + return ResourceService.GetString("AddInManager.AddInUpdated"); + } + else + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInInstalled")); + } + } + else if (IsRemoved) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInRemoved")); + } + else if (!IsEnabled) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInDisabled")); + } + else + { + return _package.Summary; + } + } + } + + public override Version Version + { + get + { + return _package.Version.Version; + } + } + + public override int DownloadCount + { + get + { + return _package.DownloadCount; + } + } + + public override string Description + { + get + { + return _package.Description; + } + } + + public override DateTime? LastUpdated + { + get + { + // TODO +// return package.LastUpdated; + return null; + } + } + + public override bool HasDependencyConflicts + { + get + { + return false; + } + } + + public override void AddPackage() + { + ClearReportedMessages(); + TryInstallingPackage(); + } + + public override void UpdatePackage() + { + ClearReportedMessages(); + TryInstallingPackage(); + } + + private void ClearReportedMessages() + { + // packageManagementEvents.OnPackageOperationsStarting(); + } + + private void GetPackageOperations() + { + var packageOperationResolver = AddInManager.NuGet.CreateInstallPackageOperationResolver(false); + _packageOperations = packageOperationResolver.ResolveOperations(_package); + } + + private bool CanInstallPackage() + { + // Ask for downloading dependent packages + if ((_packageOperations != null) && _packageOperations.Any()) + { + var operationsForDependencies = _packageOperations.Where(p => p.Package.Id != _package.Id); + if ((operationsForDependencies != null) && operationsForDependencies.Any()) + { + string addInNames = ""; + foreach (var packageOperation in operationsForDependencies) + { + addInNames += "\t " + + packageOperation.Package.Id + " " + packageOperation.Package.Version.ToString() + Environment.NewLine; + } + if (!MessageService.AskQuestionFormatted( + "${res:AddInManager.Title}", "${res:AddInManager2.InstallDependentMessage}", _package.Id, addInNames)) + { + return false; + } + } + } + + // Ask for license acceptance + IEnumerable packages = GetPackagesRequiringLicenseAcceptance(); + if (packages.Any()) + { + AcceptLicensesEventArgs acceptLicenses = new AcceptLicensesEventArgs(packages); + acceptLicenses.IsAccepted = true; + AddInManager.Events.OnAcceptLicenses(acceptLicenses); + return acceptLicenses.IsAccepted; + } + return true; + } + + private IEnumerable GetPackagesRequiringLicenseAcceptance() + { + IList packagesToBeInstalled = GetPackagesToBeInstalled(); + return GetPackagesRequiringLicenseAcceptance(packagesToBeInstalled); + } + + private IEnumerable GetPackagesRequiringLicenseAcceptance(IList packagesToBeInstalled) + { + return packagesToBeInstalled.Where(package => PackageRequiresLicenseAcceptance(package)); + } + + private IList GetPackagesToBeInstalled() + { + List packages = new List(); + foreach (PackageOperation operation in _packageOperations) + { + if (operation.Action == PackageAction.Install) + { + packages.Add(operation.Package); + } + } + return packages; + } + + private bool PackageRequiresLicenseAcceptance(IPackage package) + { + return package.RequireLicenseAcceptance && !IsPackageInstalled(); + } + + private void TryInstallingPackage() + { + try + { + if (IsPackageInstalled()) + { + // Package is already installed, but seems to be not registered as SD AddIn + string assumedPackageOutputDir = + Path.Combine(AddInManager.NuGet.PackageOutputDirectory, _package.Id + "." + _package.Version.Version.ToString()); + AddInManager.Setup.InstallAddIn(_package, assumedPackageOutputDir); + } + else + { + // Perform a normal download and AddIn installation + GetPackageOperations(); + if (CanInstallPackage()) + { + InstallPackage(_packageOperations); + } + } + } + catch (Exception ex) + { + ReportError(ex); + LoggingService.Error("Error when trying to install package.", ex); + } + } + + private void InstallPackage(IEnumerable packageOperations) + { + foreach (PackageOperation operation in packageOperations) + { + AddInManager.NuGet.ExecuteOperation(operation); + } + } + + private void ReportError(Exception ex) + { + AddInManager.Events.OnAddInOperationError(new AddInExceptionEventArgs(ex)); + } + + public override void RemovePackage() + { + TryUninstallingPackage(); + } + + private void TryUninstallingPackage() + { + try + { + UninstallPackage(); + } + catch (Exception ex) + { + ReportError(ex); + LoggingService.Error("Error when trying to uninstall package.", ex); + } + } + + public void UninstallPackage() + { + ClearReportedMessages(); + + AddIn installedAddIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); + if (installedAddIn != null) + { + AddInManager.Setup.UninstallAddIn(installedAddIn); + } + } + + public override void CancelInstallation() + { + AddIn addIn = AddInManager.Setup.GetAddInForNuGetPackage(_package, true); + if (addIn != null) + { + AddInManager.Setup.CancelInstallation(addIn); + } + } + + public override void CancelUpdate() + { + AddIn addIn = AddInManager.Setup.GetAddInForNuGetPackage(_package, true); + if (addIn != null) + { + AddInManager.Setup.CancelUpdate(addIn); + } + } + + public override void CancelUninstallation() + { + AddIn addIn = AddInManager.Setup.GetAddInForNuGetPackage(_package); + if (addIn != null) + { + AddInManager.Setup.CancelUninstallation(addIn); + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OfflineAddInViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OfflineAddInViewModel.cs new file mode 100644 index 0000000000..838cc201ea --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OfflineAddInViewModel.cs @@ -0,0 +1,527 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class OfflineAddInsViewModelBase : AddInPackageViewModelBase + { + private AddIn _addIn; + private ManagedAddIn _markedAddIn; + + private string _name; + private Uri _licenseUrl; + private Uri _projectUrl; + private Uri _reportAbuseUrl; + private IEnumerable _dependencies; + private IEnumerable _authors; + private bool _hasDownloadCount; + private string _id; + private Uri _iconUrl; + private string _summary; + private Version _version; + private Version _oldVersion; + private int _downloadCount; + private string _description; + private DateTime? _lastUpdated; + + public OfflineAddInsViewModelBase(ManagedAddIn addIn) + : base() + { + _markedAddIn = addIn; + if (_markedAddIn != null) + { + _addIn = addIn.AddIn; + } + if (_addIn != null) + { + UpdateMembers(); + } + } + + public void UpdateMembers() + { + if ((_addIn == null) || (_markedAddIn == null)) + { + return; + } + + _id = _addIn.Manifest.PrimaryIdentity; + _name = _addIn.Name; + if (_addIn.Version != null) + { + _version = _addIn.Version; + } + _description = _addIn.Properties["description"]; + _summary = _addIn.Properties["description"]; + if (!String.IsNullOrEmpty(_addIn.Properties["url"])) + { + _projectUrl = new Uri(_addIn.Properties["url"]); + } + if (!String.IsNullOrEmpty(_addIn.Properties["license"])) + { + _licenseUrl = new Uri(_addIn.Properties["license"]); + } + if (!String.IsNullOrEmpty(_addIn.Properties["author"])) + { + _authors = new string[] { _addIn.Properties["author"] }; + } + + if ((_addIn.Manifest != null) && (_addIn.Manifest.Dependencies != null)) + { + _dependencies = _addIn.Manifest.Dependencies.Select(d => new AddInDependency(d)); + } + + if (_markedAddIn.IsUpdate) + { + _oldVersion = _markedAddIn.OldVersion; + } + + _iconUrl = null; + _hasDownloadCount = false; + _downloadCount = 0; + _lastUpdated = null; + _reportAbuseUrl = null; + } + + public AddIn AddIn + { + get + { + return _addIn; + } + } + + public override string Name + { + get + { + return _name; + } + } + + public override Uri LicenseUrl + { + get + { + return _licenseUrl; + } + } + + public override Uri ProjectUrl + { + get + { + return _projectUrl; + } + } + + public override Uri ReportAbuseUrl + { + get + { + return _reportAbuseUrl; + } + } + + public override bool IsOffline + { + get + { + return true; + } + } + + public override bool IsPreinstalled + { + get + { + if (_addIn != null) + { + return AddInManager.Setup.IsAddInPreinstalled(_addIn); + } + else + { + return false; + } + } + } + + public override bool IsAdded + { + get + { + if (_addIn != null) + { +// return (_addIn.Action == AddInAction.Install) || (_addIn.Action == AddInAction.Update); + return _markedAddIn.IsTemporary; + } + else + { + return false; + } + } + } + + public override bool IsUpdate + { + get + { + return _markedAddIn.IsUpdate; + } + } + + public override bool IsInstalled + { + get + { + if (_addIn != null) + { + return AddInManager.Setup.IsAddInInstalled(_addIn); + } + else + { + return false; + } + } + } + + public override bool IsInstallable + { + get + { + return false; + } + } + + public override bool IsUninstallable + { + get + { + return !IsPreinstalled; + } + } + + public override bool IsEnabled + { + get + { + if (_addIn != null) + { + return (_addIn.Action != AddInAction.Disable); + } + else + { + return false; + } + } + } + + public override bool IsRemoved + { + get + { + if (_addIn != null) + { + return !_markedAddIn.IsTemporary && (_addIn.Action == AddInAction.Uninstall); + } + else + { + return false; + } + } + } + + public override IEnumerable Dependencies + { + get + { + return _dependencies; + } + } + + public override IEnumerable Authors + { + get + { + return _authors; + } + } + + public override bool HasDownloadCount + { + get + { + return _hasDownloadCount; + } + } + + public override string Id + { + get + { + return _id; + } + } + + public override Uri IconUrl + { + get + { + return _iconUrl; + } + } + + public override string Summary + { + get + { + if (_addIn != null) + { + if (_addIn.Action == AddInAction.Install) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInInstalled")); + } + else if (_addIn.Action == AddInAction.Update) + { + return ResourceService.GetString("AddInManager.AddInUpdated"); + } + else if (HasDependencyConflicts) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInDependencyFailed")); + } + else if (IsRemoved) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInRemoved")); + } + else if (IsEnabled && !_addIn.Enabled) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInEnabled")); + } + else if (!IsEnabled) + { + if (_addIn.Enabled) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInWillBeDisabled")); + } + else + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInDisabled")); + } + } + else if (_addIn.Action == AddInAction.InstalledTwice) + { + return SurroundWithParantheses(ResourceService.GetString("AddInManager.AddInInstalledTwice")); + } + else + { + return _summary; + } + } + else + { + return null; + } + } + } + + public override Version Version + { + get + { + return _version; + } + } + + public override Version OldVersion + { + get + { + return _oldVersion; + } + } + + public override bool ShowSplittedVersions + { + get + { + return IsUpdate; + } + } + + public override int DownloadCount + { + get + { + return _downloadCount; + } + } + + public override string Description + { + get + { + return _description; + } + } + + public override DateTime? LastUpdated + { + get + { + return _lastUpdated; + } + } + + public override bool HasDependencyConflicts + { + get + { + if (_addIn != null) + { + return (_addIn.Action == AddInAction.DependencyError); + } + else + { + return false; + } + } + } + + public override bool HasNuGetConnection + { + get + { + if (_markedAddIn != null) + { + return (_markedAddIn.InstallationSource == AddInInstallationSource.NuGetRepository); + } + else + { + return false; + } + } + } + + public override void AddPackage() + { + } + + public override void RemovePackage() + { + if (_addIn.Manifest.PrimaryIdentity == "ICSharpCode.AddInManager2") + { + MessageService.ShowMessage("${res:AddInManager2.CannotRemoveAddInManager}", "${res:AddInManager.Title}"); + return; + } + + if (!this.IsRemoved) + { + var dependentAddIns = AddInManager.Setup.GetDependentAddIns(_addIn); + if ((dependentAddIns != null) && dependentAddIns.Any()) + { + string addInNames = ""; + foreach (var dependentAddIn in dependentAddIns) + { + addInNames += "\t " + dependentAddIn.AddIn.Name + Environment.NewLine; + } + if (!MessageService.AskQuestionFormatted( + "${res:AddInManager.Title}", "${res:AddInManager2.DisableDependentWarning}", _addIn.Name, addInNames)) + { + return; + } + } + } + + AddInManager.Setup.UninstallAddIn(_addIn); + } + + public override void CancelInstallation() + { + AddInManager.Setup.CancelInstallation(_addIn); + } + + public override void CancelUpdate() + { + AddInManager.Setup.CancelUpdate(_addIn); + } + + public override void CancelUninstallation() + { + AddInManager.Setup.CancelUninstallation(_addIn); + } + + public override void DisablePackage() + { + if (_addIn == null) + { + return; + } + if (_addIn.Manifest.PrimaryIdentity == "ICSharpCode.AddInManager2") + { + MessageService.ShowMessage("${res:AddInManager.CannotDisableAddInManager}", "${res:AddInManager.Title}"); + return; + } + + if (this.IsEnabled) + { + var dependentAddIns = AddInManager.Setup.GetDependentAddIns(_addIn); + if ((dependentAddIns != null) && dependentAddIns.Any()) + { + string addInNames = ""; + foreach (var dependentAddIn in dependentAddIns) + { + addInNames += "\t " + dependentAddIn.AddIn.Name + Environment.NewLine; + } + if (!MessageService.AskQuestionFormatted( + "${res:AddInManager.Title}", "${res:AddInManager2.DisableDependentWarning}", _addIn.Name, addInNames)) + { + return; + } + } + } + + AddInManager.Setup.SwitchAddInActivation(_addIn); + } + + public override bool HasOptions + { + get + { + if (_addIn.Enabled) + { + foreach (KeyValuePair pair in _addIn.Paths) + { + if (pair.Key.StartsWith("/SharpDevelop/Dialogs/OptionsDialog")) + { + return true; + } + } + } + return false; + } + } + + public override void ShowOptions() + { + AddInTreeNode dummyNode = new AddInTreeNode(); + foreach (KeyValuePair pair in _addIn.Paths) + { + if (pair.Key.StartsWith("/SharpDevelop/Dialogs/OptionsDialog")) + { + dummyNode.AddCodons(pair.Value.Codons); + } + } + ICSharpCode.SharpDevelop.Commands.OptionsCommand.ShowTabbedOptions( + _addIn.Name + " " + ResourceService.GetString("AddInManager.Options"), + dummyNode); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OpenHyperlinkCommand.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OpenHyperlinkCommand.cs new file mode 100644 index 0000000000..b35e7f7300 --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/OpenHyperlinkCommand.cs @@ -0,0 +1,52 @@ +// 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; +using System.Diagnostics; +using System.Windows.Input; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class OpenHyperlinkCommand : ICommand + { + public event EventHandler CanExecuteChanged; + + protected virtual void OnCanExecuteChanged() + { + if (CanExecuteChanged != null) + { + CanExecuteChanged(this, new EventArgs()); + } + } + + public bool CanExecute(object parameter) + { + return true; + } + + public void Execute(object parameter) + { + Uri uri = parameter as Uri; + if (uri != null) + { + StartProcess(uri.AbsoluteUri); + } + else + { + StartProcess(parameter as string); + } + } + + protected virtual void StartProcess(string fileName) + { + try + { + System.Diagnostics.Process.Start(fileName); + } + catch (Exception) + { + // TODO Show error message or ignore silently? + } + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/PackageRepositoriesViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/PackageRepositoriesViewModel.cs new file mode 100644 index 0000000000..1b0f1d4c6f --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/PackageRepositoriesViewModel.cs @@ -0,0 +1,315 @@ +// 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; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Interop; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class PackageRepositoriesViewModel : Model + { + ObservableCollection packageRepositories = + new ObservableCollection(); + ObservableCollection packageSources; + + DelegateCommand addPackageSourceCommmand; + DelegateCommand removePackageSourceCommand; + DelegateCommand movePackageSourceUpCommand; + DelegateCommand movePackageSourceDownCommand; + DelegateCommand browsePackageFolderCommand; + + PackageRepository newPackageSource = new PackageRepository(); + PackageRepository selectedPackageRepository; + + public PackageRepositoriesViewModel() + { + this.packageSources = new ObservableCollection(); + CreateCommands(); + } + + private void CreateCommands() + { + addPackageSourceCommmand = + new DelegateCommand(param => AddPackageSource(), + param => CanAddPackageSource); + + removePackageSourceCommand = + new DelegateCommand(param => RemovePackageSource(), + param => CanRemovePackageSource); + + movePackageSourceUpCommand = + new DelegateCommand(param => MovePackageSourceUp(), + param => CanMovePackageSourceUp); + + movePackageSourceDownCommand = + new DelegateCommand(param => MovePackageSourceDown(), + param => CanMovePackageSourceDown); + + browsePackageFolderCommand = + new DelegateCommand(param => BrowsePackageFolder()); + } + + public ICommand AddPackageSourceCommand + { + get + { + return addPackageSourceCommmand; + } + } + + public ICommand RemovePackageSourceCommand + { + get + { + return removePackageSourceCommand; + } + } + + public ICommand MovePackageSourceUpCommand + { + get + { + return movePackageSourceUpCommand; + } + } + + public ICommand MovePackageSourceDownCommand + { + get + { + return movePackageSourceDownCommand; + } + } + + public ICommand BrowsePackageFolderCommand + { + get + { + return browsePackageFolderCommand; + } + } + + public ObservableCollection PackageRepositories + { + get + { + return packageRepositories; + } + } + + public void Load() + { + packageSources.Clear(); +// packageSources.AddRange(AddInManager.Repositories.RegisteredPackageSources); + NuGet.CollectionExtensions.AddRange(packageSources, AddInManager.Repositories.RegisteredPackageSources); + foreach (PackageSource packageSource in packageSources) + { + AddPackageSourceToViewModel(packageSource); + } + } + + private void AddPackageSourceToViewModel(PackageSource packageSource) + { + var packageRepository = new PackageRepository(packageSource); + packageRepositories.Add(packageRepository); + } + + public void Save() + { + packageSources.Clear(); + foreach (PackageRepository packageRepository in packageRepositories) + { + PackageSource source = packageRepository.ToPackageSource(); + packageSources.Add(source); + } + AddInManager.Repositories.RegisteredPackageSources = packageSources; + } + + public string NewPackageSourceName + { + get + { + return newPackageSource.Name; + } + set + { + newPackageSource.Name = value; + OnPropertyChanged(viewModel => viewModel.NewPackageSourceName); + } + } + + public string NewPackageSourceUrl + { + get + { + return newPackageSource.SourceUrl; + } + set + { + newPackageSource.SourceUrl = value; + OnPropertyChanged(viewModel => viewModel.NewPackageSourceUrl); + } + } + + public PackageRepository SelectedPackageRepository + { + get + { + return selectedPackageRepository; + } + set + { + selectedPackageRepository = value; + OnPropertyChanged(viewModel => viewModel.SelectedPackageRepository); + OnPropertyChanged(viewModel => viewModel.CanAddPackageSource); + } + } + + public void AddPackageSource() + { + AddNewPackageSourceToViewModel(); + SelectLastPackageSourceViewModel(); + } + + private void AddNewPackageSourceToViewModel() + { + var packageSource = newPackageSource.ToPackageSource(); + AddPackageSourceToViewModel(packageSource); + } + + private void SelectLastPackageSourceViewModel() + { + SelectedPackageRepository = GetLastPackageSourceViewModel(); + } + + public bool CanAddPackageSource + { + get + { + return NewPackageSourceHasUrl && NewPackageSourceHasName; + } + } + + private bool NewPackageSourceHasUrl + { + get + { + return !String.IsNullOrEmpty(NewPackageSourceUrl); + } + } + + private bool NewPackageSourceHasName + { + get + { + return !String.IsNullOrEmpty(NewPackageSourceName); + } + } + + public void RemovePackageSource() + { + RemoveSelectedPackageSourceViewModel(); + } + + public bool CanRemovePackageSource + { + get + { + return selectedPackageRepository != null; + } + } + + private void RemoveSelectedPackageSourceViewModel() + { + packageRepositories.Remove(selectedPackageRepository); + } + + public void MovePackageSourceUp() + { + int selectedPackageSourceIndex = GetSelectedPackageSourceViewModelIndex(); + int destinationPackageSourceIndex = selectedPackageSourceIndex--; + packageRepositories.Move(selectedPackageSourceIndex, destinationPackageSourceIndex); + } + + private int GetSelectedPackageSourceViewModelIndex() + { + return packageRepositories.IndexOf(selectedPackageRepository); + } + + public bool CanMovePackageSourceUp + { + get + { + return HasAtLeastTwoPackageSources() && !IsFirstPackageSourceSelected(); + } + } + + private bool IsFirstPackageSourceSelected() + { + return selectedPackageRepository == packageRepositories[0]; + } + + public void MovePackageSourceDown() + { + int selectedPackageSourceIndex = GetSelectedPackageSourceViewModelIndex(); + int destinationPackageSourceIndex = selectedPackageSourceIndex++; + packageRepositories.Move(selectedPackageSourceIndex, destinationPackageSourceIndex); + } + + public bool CanMovePackageSourceDown + { + get + { + return HasAtLeastTwoPackageSources() && !IsLastPackageSourceSelected(); + } + } + + private bool HasAtLeastTwoPackageSources() + { + return packageRepositories.Count >= 2; + } + + private bool IsLastPackageSourceSelected() + { + PackageRepository lastViewModel = GetLastPackageSourceViewModel(); + return lastViewModel == selectedPackageRepository; + } + + private PackageRepository GetLastPackageSourceViewModel() + { + return packageRepositories.Last(); + } + + public void BrowsePackageFolder() + { + using (var dialog = new FolderBrowserDialog()) + { + var owner = SD.WinForms.MainWin32Window; + if (dialog.ShowDialog(owner) == DialogResult.OK) + { + UpdateNewPackageSourceUsingSelectedFolder(dialog.SelectedPath); + } + } + } + + private void UpdateNewPackageSourceUsingSelectedFolder(string folder) + { + NewPackageSourceUrl = folder; + NewPackageSourceName = GetPackageSourceNameFromFolder(folder); + } + + private string GetPackageSourceNameFromFolder(string folder) + { + return Path.GetFileName(folder); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/UpdatedAddInsViewModel.cs b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/UpdatedAddInsViewModel.cs new file mode 100644 index 0000000000..9ead50645c --- /dev/null +++ b/src/AddIns/Misc/AddInManager2/Project/Src/ViewModel/UpdatedAddInsViewModel.cs @@ -0,0 +1,108 @@ +// 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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Windows.Input; +using ICSharpCode.AddInManager2.Model; +using ICSharpCode.Core; +using NuGet; + +namespace ICSharpCode.AddInManager2.ViewModel +{ + public class UpdatedAddInsViewModel : NuGetAddInsViewModelBase + { + private IQueryable installedPackages; + private string errorMessage = String.Empty; + private bool hasSavedException = false; + + public UpdatedAddInsViewModel() + : base() + { + IsSearchable = true; + HasFilterForPrereleases = true; + Title = ResourceService.GetString("AddInManager2.Views.Updates");; + + AddInManager.Events.AddInInstalled += NuGetPackagesChanged; + AddInManager.Events.AddInUninstalled += NuGetPackagesChanged; + AddInManager.Events.AddInStateChanged += InstalledAddInStateChanged; + } + + protected override void OnDispose() + { + AddInManager.Events.AddInInstalled -= NuGetPackagesChanged; + AddInManager.Events.AddInUninstalled -= NuGetPackagesChanged; + AddInManager.Events.AddInStateChanged -= InstalledAddInStateChanged; + } + + protected override IQueryable GetAllPackages() + { + if (hasSavedException) + { + ThrowSavedException(); + } + return GetUpdatedPackages(); + } + + protected override void UpdateRepositoryBeforeReadPackagesTaskStarts() + { + try + { + installedPackages = GetInstalledPackages(); + } + catch (Exception ex) + { + hasSavedException = true; + errorMessage = ex.Message; + } + } + + private IQueryable GetInstalledPackages() + { + return AddInManager.NuGet.Packages.LocalRepository.GetPackages(); + } + + private IQueryable GetUpdatedPackages() + { + IQueryable localPackages = installedPackages; + localPackages = FilterPackages(localPackages); + var updatedPackages = GetUpdatedPackages(AddInManager.Repositories.Registered, localPackages); + HighlightCount = updatedPackages.Count(); + return updatedPackages.AsQueryable(); + } + + private IEnumerable GetUpdatedPackages(IPackageRepository sourceRepository, IQueryable localPackages) + { + return sourceRepository.GetUpdates(localPackages, ShowPrereleases, false); + } + + private IQueryable FilterPackages(IQueryable localPackages) + { + return localPackages.Find(SearchTerms); + } + + private void ThrowSavedException() + { + throw new ApplicationException(errorMessage); + } + + protected override void UpdatePrereleaseFilter() + { + ReadPackages(); + } + + private void NuGetPackagesChanged(object sender, AddInInstallationEventArgs e) + { + ReadPackages(); + } + + private void InstalledAddInStateChanged(object sender, AddInInstallationEventArgs e) + { + UpdateInstallationState(); + } + } +} diff --git a/src/AddIns/Misc/AddInManager2/RequiredLibraries/ICSharpCode.SharpZipLib.dll b/src/AddIns/Misc/AddInManager2/RequiredLibraries/ICSharpCode.SharpZipLib.dll new file mode 100644 index 0000000000..77bafe8ba8 Binary files /dev/null and b/src/AddIns/Misc/AddInManager2/RequiredLibraries/ICSharpCode.SharpZipLib.dll differ