diff --git a/src/DynamoCore/DynamoCore.csproj b/src/DynamoCore/DynamoCore.csproj index aefff4b48db..ba4efc28358 100644 --- a/src/DynamoCore/DynamoCore.csproj +++ b/src/DynamoCore/DynamoCore.csproj @@ -78,8 +78,8 @@ limitations under the License. ..\..\extern\Analytics.NET\Analytics.NET.Google.dll - - ..\packages\Greg.1.1.7040.19960\lib\net47\Greg.dll + + ..\packages\Greg.1.2.7121.21318\lib\net47\Greg.dll diff --git a/src/DynamoCore/packages.config b/src/DynamoCore/packages.config index 2c42b7c9a8c..66bb0a7d424 100644 --- a/src/DynamoCore/packages.config +++ b/src/DynamoCore/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/DynamoCoreWpf/DynamoCoreWpf.csproj b/src/DynamoCoreWpf/DynamoCoreWpf.csproj index af4db5ad98f..273c3983b2e 100644 --- a/src/DynamoCoreWpf/DynamoCoreWpf.csproj +++ b/src/DynamoCoreWpf/DynamoCoreWpf.csproj @@ -50,8 +50,8 @@ ..\..\extern\FontAwesome\FontAwesome.WPF.dll - - ..\packages\Greg.1.1.7040.19960\lib\net47\Greg.dll + + ..\packages\Greg.1.2.7121.21318\lib\net47\Greg.dll ..\packages\HelixToolkit.2015.1.629\lib\portable-net4+sl4+wp71+win8\HelixToolkit.dll diff --git a/src/DynamoCoreWpf/Properties/Resources.Designer.cs b/src/DynamoCoreWpf/Properties/Resources.Designer.cs index da4d608a376..90929eb0b9e 100644 --- a/src/DynamoCoreWpf/Properties/Resources.Designer.cs +++ b/src/DynamoCoreWpf/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Dynamo.Wpf.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -3710,6 +3710,33 @@ public static string PackageFolderNotAccessible { } } + /// + /// Looks up a localized string similar to Filter packages by Dynamo host application.. + /// + public static string PackageHostDependencyFilter { + get { + return ResourceManager.GetString("PackageHostDependencyFilter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Packages requires the specified host to run.. + /// + public static string PackageHostDependencyFilterContextItem { + get { + return ResourceManager.GetString("PackageHostDependencyFilterContextItem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This package requires the specified host(s) to run.. + /// + public static string PackageHostDependencyTooltip { + get { + return ResourceManager.GetString("PackageHostDependencyTooltip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Package Manager Website. /// diff --git a/src/DynamoCoreWpf/Properties/Resources.en-US.resx b/src/DynamoCoreWpf/Properties/Resources.en-US.resx index f318e623319..f77ab3bc9b0 100644 --- a/src/DynamoCoreWpf/Properties/Resources.en-US.resx +++ b/src/DynamoCoreWpf/Properties/Resources.en-US.resx @@ -2216,6 +2216,15 @@ Uninstall the following packages: {0}? Could not re-direct to the Dynamo forum page for feedback: + + This package requires the specified host(s) to run. + + + Filter packages by Dynamo host application. + + + Packages requires the specified host to run. + "The package {0} is already installed. To reinstall it, you must first uninstall it and restart to complete the uninstall. Would you like to mark {0} for uninstall?" diff --git a/src/DynamoCoreWpf/Properties/Resources.resx b/src/DynamoCoreWpf/Properties/Resources.resx index 47ac5440156..22607f860df 100644 --- a/src/DynamoCoreWpf/Properties/Resources.resx +++ b/src/DynamoCoreWpf/Properties/Resources.resx @@ -2219,6 +2219,15 @@ Uninstall the following packages: {0}? Could not re-direct to the Dynamo forum page for feedback: + + This package requires the specified host(s) to run. + + + Filter packages by Dynamo host application. + + + Packages requires the specified host to run. + "The package {0} is already installed. To reinstall it, you must first uninstall it and restart to complete the uninstall. Would you like to mark {0} for uninstall?" diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs index 5b64d1a659c..4d67ba68948 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs @@ -19,6 +19,10 @@ namespace Dynamo.PackageManager { public class PackageManagerSearchViewModel : NotificationObject { + #region enums + /// + /// Enum for the Package search state + /// public enum PackageSearchState { Syncing, @@ -27,6 +31,9 @@ public enum PackageSearchState Results }; + /// + /// Enum for the Package sort key, utilized by sorting context menu + /// public enum PackageSortingKey { Name, @@ -36,11 +43,87 @@ public enum PackageSortingKey LastUpdate }; + /// + /// Enum for the Package sort direction, utilized by sorting context menu + /// public enum PackageSortingDirection { Ascending, Descending }; + #endregion enums + + /// + /// Package Manager filter entry, binded to the host filter context menu + /// + public class FilterEntry + { + /// + /// Name of the host + /// + public string FilterName { get; set; } + + /// + /// Filter entry click command, notice this is a dynamic command + /// with command param set to FilterName so that the code is robust + /// in a way UI could handle as many hosts as possible + /// + public DelegateCommand FilterCommand { get; set; } + + /// + /// Boolean indicates if the Filter entry is checked, data binded to + /// is checked property of each filter + /// + public bool OnChecked { get; set; } + + /// + /// Private reference of PackageManagerSearchViewModel, + /// used in the FilterCommand to filter search results + /// + private PackageManagerSearchViewModel pmSearchViewModel; + + /// + /// Constructor + /// + /// Filter name, same as host name + /// a reference of the PackageManagerSearchViewModel + public FilterEntry(string filterName, PackageManagerSearchViewModel packageManagerSearchViewModel) + { + FilterName = filterName; + FilterCommand = new DelegateCommand(SetFilterHosts, CanSetFilterHosts); + pmSearchViewModel = packageManagerSearchViewModel; + OnChecked = false; + } + + /// + /// Each filter is enabled for now, we may enable more smartly in the future + /// + /// + /// + private bool CanSetFilterHosts(object arg) + { + return true; + } + + /// + /// This function will adjust the SelectedHosts in the SearchViewModel + /// Affecting search results globally + /// + /// + private void SetFilterHosts(object obj) + { + if (OnChecked) + { + pmSearchViewModel.SelectedHosts.Add(obj as string); + } + else + { + pmSearchViewModel.SelectedHosts.Remove(obj as string); + } + pmSearchViewModel.SearchAndUpdateResults(); + return; + } + } #region Properties & Fields @@ -64,6 +147,22 @@ public PackageSortingKey SortingKey } } + private List hostFilter; + + + /// + /// Dynamic Filter for package hosts, should include all Dynamo known hosts from PM backend + /// e.g. "Advance Steel", "Alias", "Civil 3D", "FormIt", "Revit" + /// + public List HostFilter + { + get { return hostFilter; } + set + { + hostFilter = value; + RaisePropertyChanged("HostFilter"); + } + } /// /// SortingDirection property @@ -89,7 +188,7 @@ public string SearchBoxPrompt { get { - if(SearchState == PackageSearchState.Syncing) + if (SearchState == PackageSearchState.Syncing) { return Resources.PackageSearchViewSearchTextBoxSyncing; } @@ -107,7 +206,7 @@ public bool ShowSearchText { get { - if(SearchState == PackageSearchState.Syncing) + if (SearchState == PackageSearchState.Syncing) { return false; } @@ -207,7 +306,10 @@ public PackageSearchState SearchState /// public PackageManagerClientViewModel PackageManagerClientViewModel { get; private set; } - + /// + /// Current selected filter hosts + /// + public List SelectedHosts { get; set; } private SearchDictionary SearchDictionary; @@ -239,7 +341,7 @@ public ObservableCollection Downloads get { return PackageManagerClientViewModel.Downloads; } } -#endregion Properties & Fields + #endregion Properties & Fields internal PackageManagerSearchViewModel() { @@ -251,9 +353,11 @@ internal PackageManagerSearchViewModel() SetSortingKeyCommand = new DelegateCommand(SetSortingKey, CanSetSortingKey); SetSortingDirectionCommand = new DelegateCommand(SetSortingDirection, CanSetSortingDirection); SearchResults.CollectionChanged += SearchResultsOnCollectionChanged; - SearchText = ""; + SearchText = string.Empty; SortingKey = PackageSortingKey.LastUpdate; SortingDirection = PackageSortingDirection.Ascending; + HostFilter = new List(); + SelectedHosts = new List(); } /// @@ -262,6 +366,7 @@ internal PackageManagerSearchViewModel() public PackageManagerSearchViewModel(PackageManagerClientViewModel client) : this() { this.PackageManagerClientViewModel = client; + HostFilter = InitializeHostFilter(); PackageManagerClientViewModel.Downloads.CollectionChanged += DownloadsOnCollectionChanged; PackageManagerClientViewModel.PackageManagerExtension.PackageLoader.ConflictingCustomNodePackageLoaded += ConflictingCustomNodePackageLoaded; @@ -294,6 +399,21 @@ public void Sort() this.SearchResults = temp; } + /// + /// Based on the known hosts received from Package Manager server, + /// initialize the host filter in Dynamo + /// + public List InitializeHostFilter() + { + var hostFilter = new List(); + foreach (var host in PackageManagerClientViewModel.Model.GetKnownHosts()) + { + hostFilter.Add(new FilterEntry(host, this)); + } + + return hostFilter; + } + /// /// Can search be performed. Used by the associated command /// @@ -348,16 +468,16 @@ public void SetSortingKey(object sortingKey) { if (sortingKey is string) { - var key = (string) sortingKey; + var key = (string)sortingKey; if (key == "NAME") { this.SortingKey = PackageSortingKey.Name; - } + } else if (key == "DOWNLOADS") { this.SortingKey = PackageSortingKey.Downloads; - } + } else if (key == "MAINTAINERS") { this.SortingKey = PackageSortingKey.Maintainers; @@ -365,16 +485,16 @@ public void SetSortingKey(object sortingKey) else if (key == "LAST_UPDATE") { this.SortingKey = PackageSortingKey.LastUpdate; - } + } else if (key == "VOTES") { this.SortingKey = PackageSortingKey.Votes; } - } + } else if (sortingKey is PackageSortingKey) { - this.SortingKey = (PackageSortingKey) sortingKey; + this.SortingKey = (PackageSortingKey)sortingKey; } this.Sort(); @@ -465,7 +585,7 @@ private void ClearSearchResults() this.SearchResults.Clear(); } - + private string JoinPackageNames(IEnumerable pkgs) { return String.Join(", ", pkgs.Select(x => x.Name + " " + x.VersionName)); @@ -477,7 +597,7 @@ private void PackageOnExecuted(PackageManagerSearchElement element, PackageVersi String.Format(Resources.MessageConfirmToInstallPackage, element.Name, version.version) : String.Format(Resources.MessageConfirmToInstallPackageToFolder, element.Name, version.version, downloadPath); - var result = MessageBox.Show(msg, + var result = MessageBox.Show(msg, Resources.PackageDownloadConfirmMessageBoxTitle, MessageBoxButton.OKCancel, MessageBoxImage.Question); @@ -581,7 +701,7 @@ private void PackageOnExecuted(PackageManagerSearchElement element, PackageVersi MessageBox.Show(String.Format(Resources.MessageUninstallToContinue, PackageManagerClientViewModel.DynamoViewModel.BrandingResourceProvider.ProductName, JoinPackageNames(uninstallRequiringUserModifications)), - Resources.CannotDownloadPackageMessageBoxTitle, + Resources.CannotDownloadPackageMessageBoxTitle, MessageBoxButton.OK, MessageBoxImage.Error); return; } @@ -595,7 +715,6 @@ private void PackageOnExecuted(PackageManagerSearchElement element, PackageVersi PackageManagerClientViewModel.DynamoViewModel.BrandingResourceProvider.ProductName, JoinPackageNames(uninstallsRequiringRestart), element.Name + " " + version.version); - // different message for the case that the user is // trying to install the same package/version they already have installed. if(uninstallsRequiringRestart.Count == 1 && @@ -604,7 +723,6 @@ private void PackageOnExecuted(PackageManagerSearchElement element, PackageVersi { message = String.Format(Resources.MessageUninstallSamePackage, element.Name + " " + version.version); } - var dialogResult = MessageBox.Show(message, Resources.CannotDownloadPackageMessageBoxTitle, MessageBoxButton.YesNo, MessageBoxImage.Error); @@ -620,10 +738,10 @@ private void PackageOnExecuted(PackageManagerSearchElement element, PackageVersi if (immediateUninstalls.Any()) { // if the package is not in use, tell the user we will be uninstall it and give them the opportunity to cancel - if (MessageBox.Show(String.Format(Resources.MessageAlreadyInstallDynamo, + if (MessageBox.Show(String.Format(Resources.MessageAlreadyInstallDynamo, PackageManagerClientViewModel.DynamoViewModel.BrandingResourceProvider.ProductName, JoinPackageNames(immediateUninstalls)), - Resources.DownloadWarningMessageBoxTitle, + Resources.DownloadWarningMessageBoxTitle, MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.Cancel) return; } @@ -675,7 +793,7 @@ private void DownloadsOnCollectionChanged(object sender, NotifyCollectionChanged { foreach (var item in args.NewItems) { - var handle = (PackageDownloadHandle) item; + var handle = (PackageDownloadHandle)item; handle.PropertyChanged += (o, eventArgs) => this.ClearCompletedCommand.RaiseCanExecuteChanged(); } } @@ -692,7 +810,7 @@ private void DownloadsOnCollectionChanged(object sender, NotifyCollectionChanged private void SearchResultsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { this.RaisePropertyChanged("HasNoResults"); - } + } public void ClearCompleted() { @@ -704,7 +822,7 @@ public bool CanClearCompleted() if (PackageManagerClientViewModel == null) return false; return PackageManagerClientViewModel.Downloads - .Any(x => x.DownloadState == PackageDownloadHandle.State.Installed + .Any(x => x.DownloadState == PackageDownloadHandle.State.Installed || x.DownloadState == PackageDownloadHandle.State.Error); } @@ -772,6 +890,24 @@ internal void SearchAndUpdateResults() SearchAndUpdateResults(SearchText); } + /// + /// Performs a filter to the assuming pre-searched results + /// + /// + /// + internal IEnumerable Filter(IEnumerable list) + { + // No need to filter by host if nothing selected + if (SelectedHosts.Count == 0) return list; + IEnumerable filteredList = null; + foreach (var host in SelectedHosts) + { + filteredList = (filteredList ?? Enumerable.Empty()).Union( + list.Where(x => x.Model.Hosts != null && x.Model.Hosts.Contains(host)) ?? Enumerable.Empty()); + } + return filteredList; + } + /// /// Performs a search using the given string as query, but does not update /// the SearchResults object. @@ -787,15 +923,17 @@ internal IEnumerable Search(string query) if (!String.IsNullOrEmpty(query)) { - list = SearchDictionary.Search(query) + list = Filter(SearchDictionary.Search(query) .Select(x => new PackageManagerSearchElementViewModel(x, canLogin)) - .Take(MaxNumSearchResults).ToList(); + .Take(MaxNumSearchResults)) + .ToList(); } else { // with null query, don't show deprecated packages - list = LastSync.Where(x => !x.IsDeprecated) - .Select(x => new PackageManagerSearchElementViewModel(x, canLogin)).ToList(); + list = Filter(LastSync.Where(x => !x.IsDeprecated) + .Select(x => new PackageManagerSearchElementViewModel(x, canLogin))) + .ToList(); Sort(list, this.SortingKey); } @@ -805,7 +943,6 @@ internal IEnumerable Search(string query) return list; } - /// /// Sort a list of search results by the given key /// @@ -868,6 +1005,6 @@ public void ExecuteSelected() SearchResults[SelectedIndex].Model.Execute(); } - + } } diff --git a/src/DynamoCoreWpf/Views/PackageManager/PackageManagerSearchView.xaml b/src/DynamoCoreWpf/Views/PackageManager/PackageManagerSearchView.xaml index 0240a04a3da..549068ccd83 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/PackageManagerSearchView.xaml +++ b/src/DynamoCoreWpf/Views/PackageManager/PackageManagerSearchView.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:ui="clr-namespace:Dynamo.UI" + xmlns:fa="http://schemas.fontawesome.io/icons/" xmlns:p="clr-namespace:Dynamo.Wpf.Properties" xmlns:controls="clr-namespace:Dynamo.Controls" xmlns:viewModels="clr-namespace:Dynamo.PackageManager.ViewModels" @@ -127,6 +128,7 @@ + + +