From c8ce1328f690fadaf6d98bd1ce7fc6609b56c855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Herceg?= Date: Sat, 7 Oct 2023 17:45:32 +0200 Subject: [PATCH] MultiCriteriaSortingOptions implemented --- .../Core/Controls/GenericGridViewDataSet.cs | 21 +++++ .../Controls/GridViewDataSetExtensions.cs | 5 +- .../Controls/IFilterableGridViewDataSet.cs | 2 +- .../Options/GridViewDataSetOptions.cs | 18 +++++ .../IPagingOptionsLoadingPostProcessor.cs | 9 +++ .../Options/MultiCriteriaSortingOptions.cs | 77 +++++++++++++++++++ .../Core/Controls/Options/PagingOptions.cs | 7 +- .../Core/Controls/Options/SortingOptions.cs | 4 +- .../Core/Controls/SortingImplementation.cs | 8 +- .../Controls/GridViewDataSetOptions.cs | 14 ---- 10 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 src/Framework/Core/Controls/Options/GridViewDataSetOptions.cs create mode 100644 src/Framework/Core/Controls/Options/IPagingOptionsLoadingPostProcessor.cs create mode 100644 src/Framework/Core/Controls/Options/MultiCriteriaSortingOptions.cs delete mode 100644 src/Framework/Framework/Controls/GridViewDataSetOptions.cs diff --git a/src/Framework/Core/Controls/GenericGridViewDataSet.cs b/src/Framework/Core/Controls/GenericGridViewDataSet.cs index 4700fb8c4f..3b405e6581 100644 --- a/src/Framework/Core/Controls/GenericGridViewDataSet.cs +++ b/src/Framework/Core/Controls/GenericGridViewDataSet.cs @@ -92,5 +92,26 @@ public void RequestRefresh() { IsRefreshRequired = true; } + + /// + /// Applies the options from the specified to this instance. + /// + public void ApplyOptions(GridViewDataSetOptions options) + { + if (options.FilteringOptions != null) + { + FilteringOptions = options.FilteringOptions; + } + + if (options.SortingOptions != null) + { + SortingOptions = options.SortingOptions; + } + + if (options.PagingOptions != null) + { + PagingOptions = options.PagingOptions; + } + } } } diff --git a/src/Framework/Core/Controls/GridViewDataSetExtensions.cs b/src/Framework/Core/Controls/GridViewDataSetExtensions.cs index 81a6774f2b..f10f2812ad 100644 --- a/src/Framework/Core/Controls/GridViewDataSetExtensions.cs +++ b/src/Framework/Core/Controls/GridViewDataSetExtensions.cs @@ -26,9 +26,9 @@ public static void LoadFromQueryable(this IGridViewDataSet dataSet, IQuery var paged = pagingOptions.ApplyToQueryable(sorted); dataSet.Items = paged.ToList(); - if (pagingOptions is IPagingTotalItemsCountCapability pagingTotalItemsCount) + if (pagingOptions is IPagingOptionsLoadingPostProcessor pagingOptionsLoadingPostProcessor) { - pagingTotalItemsCount.TotalItemsCount = filtered.Count(); + pagingOptionsLoadingPostProcessor.ProcessLoadedItems(filtered, dataSet.Items); } dataSet.IsRefreshRequired = false; @@ -63,5 +63,6 @@ public static void GoToPageAndRefresh(this IPageableGridViewDataSet IFilteringOptions FilteringOptions { get; } } -} \ No newline at end of file +} diff --git a/src/Framework/Core/Controls/Options/GridViewDataSetOptions.cs b/src/Framework/Core/Controls/Options/GridViewDataSetOptions.cs new file mode 100644 index 0000000000..1f47c50572 --- /dev/null +++ b/src/Framework/Core/Controls/Options/GridViewDataSetOptions.cs @@ -0,0 +1,18 @@ +namespace DotVVM.Framework.Controls +{ + public class GridViewDataSetOptions + where TFilteringOptions : IFilteringOptions + where TSortingOptions : ISortingOptions + where TPagingOptions : IPagingOptions + { + public TFilteringOptions? FilteringOptions { get; set; } = default; + + public TSortingOptions? SortingOptions { get; set; } = default; + + public TPagingOptions? PagingOptions { get; set; } = default; + } + + public class GridViewDataSetOptions : GridViewDataSetOptions + { + } +} diff --git a/src/Framework/Core/Controls/Options/IPagingOptionsLoadingPostProcessor.cs b/src/Framework/Core/Controls/Options/IPagingOptionsLoadingPostProcessor.cs new file mode 100644 index 0000000000..3f4a923a62 --- /dev/null +++ b/src/Framework/Core/Controls/Options/IPagingOptionsLoadingPostProcessor.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; +using System.Linq; + +namespace DotVVM.Framework.Controls; + +public interface IPagingOptionsLoadingPostProcessor +{ + void ProcessLoadedItems(IQueryable filteredQueryable, IList items); +} diff --git a/src/Framework/Core/Controls/Options/MultiCriteriaSortingOptions.cs b/src/Framework/Core/Controls/Options/MultiCriteriaSortingOptions.cs new file mode 100644 index 0000000000..49c6a0f69c --- /dev/null +++ b/src/Framework/Core/Controls/Options/MultiCriteriaSortingOptions.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DotVVM.Framework.Controls; + +public class MultiCriteriaSortingOptions : SortingOptions, ISortingMultipleCriteriaCapability +{ + public IList Criteria { get; set; } = new List(); + + public int MaxSortCriteriaCount { get; set; } = 3; + + public override IQueryable ApplyToQueryable(IQueryable queryable) + { + foreach (var criterion in Criteria.Reverse()) + { + queryable = SortingImplementation.ApplySortingToQueryable(queryable, criterion.SortExpression, criterion.SortDescending); + } + + return base.ApplyToQueryable(queryable); + } + + public override void SetSortExpression(string? sortExpression) + { + if (SortExpression == null) + { + SortExpression = sortExpression; + SortDescending = false; + } + else if (sortExpression == SortExpression) + { + if (!SortDescending) + { + SortDescending = true; + } + else if (Criteria.Any()) + { + SortExpression = Criteria[0].SortExpression; + SortDescending = Criteria[0].SortDescending; + Criteria.RemoveAt(0); + } + else + { + SortExpression = null; + SortDescending = false; + } + } + else + { + var index = Criteria.ToList().FindIndex(c => c.SortExpression == sortExpression); + if (index >= 0) + { + if (!Criteria[index].SortDescending) + { + Criteria[index].SortDescending = true; + } + else + { + Criteria.RemoveAt(index); + } + } + else + { + if (Criteria.Count < MaxSortCriteriaCount - 1) + { + Criteria.Add(new SortCriterion() { SortExpression = sortExpression }); + } + else + { + SortExpression = sortExpression; + SortDescending = false; + Criteria.Clear(); + } + } + } + } +} diff --git a/src/Framework/Core/Controls/Options/PagingOptions.cs b/src/Framework/Core/Controls/Options/PagingOptions.cs index 2027720195..0de9c546fc 100644 --- a/src/Framework/Core/Controls/Options/PagingOptions.cs +++ b/src/Framework/Core/Controls/Options/PagingOptions.cs @@ -8,7 +8,7 @@ namespace DotVVM.Framework.Controls /// /// Represents settings for paging. /// - public class PagingOptions : IPagingOptions, IPagingFirstPageCapability, IPagingLastPageCapability, IPagingPreviousPageCapability, IPagingNextPageCapability, IPagingPageIndexCapability, IPagingPageSizeCapability, IPagingTotalItemsCountCapability, IApplyToQueryable + public class PagingOptions : IPagingOptions, IPagingFirstPageCapability, IPagingLastPageCapability, IPagingPreviousPageCapability, IPagingNextPageCapability, IPagingPageIndexCapability, IPagingPageSizeCapability, IPagingTotalItemsCountCapability, IApplyToQueryable, IPagingOptionsLoadingPostProcessor { /// /// Gets or sets the object that provides a list of page indexes near the current page. @@ -114,5 +114,10 @@ public IQueryable ApplyToQueryable(IQueryable queryable) { return PagingImplementation.ApplyPagingToQueryable(queryable, this); } + + public void ProcessLoadedItems(IQueryable filteredQueryable, IList items) + { + TotalItemsCount = filteredQueryable.Count(); + } } } diff --git a/src/Framework/Core/Controls/Options/SortingOptions.cs b/src/Framework/Core/Controls/Options/SortingOptions.cs index c35a2b69a3..9d545fbe66 100644 --- a/src/Framework/Core/Controls/Options/SortingOptions.cs +++ b/src/Framework/Core/Controls/Options/SortingOptions.cs @@ -50,9 +50,9 @@ public virtual void SetSortExpression(string? sortExpression) /// /// Applies the sorting options to the specified IQueryable expression. /// - public IQueryable ApplyToQueryable(IQueryable queryable) + public virtual IQueryable ApplyToQueryable(IQueryable queryable) { - return SortingImplementation.ApplySortingToQueryable(queryable, this); + return SortingImplementation.ApplySortingToQueryable(queryable, SortExpression, SortDescending); } } } diff --git a/src/Framework/Core/Controls/SortingImplementation.cs b/src/Framework/Core/Controls/SortingImplementation.cs index dbc7ddf01b..11683505aa 100644 --- a/src/Framework/Core/Controls/SortingImplementation.cs +++ b/src/Framework/Core/Controls/SortingImplementation.cs @@ -14,16 +14,16 @@ public static class SortingImplementation /// of items is retrieved. /// /// The to modify. - public static IQueryable ApplySortingToQueryable(IQueryable queryable, ISortingSingleCriterionCapability options) + public static IQueryable ApplySortingToQueryable(IQueryable queryable, string? sortExpression, bool sortDescending) { - if (options.SortExpression == null) + if (sortExpression == null) { return queryable; } var parameterExpression = Expression.Parameter(typeof(T), "p"); Expression sortByExpression = parameterExpression; - foreach (var prop in (options.SortExpression ?? "").Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var prop in sortExpression.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)) { var property = sortByExpression.Type.GetProperty(prop); if (property == null) @@ -46,7 +46,7 @@ public static IQueryable ApplySortingToQueryable(IQueryable queryable, return queryable; } var lambdaExpression = Expression.Lambda(sortByExpression, parameterExpression); - var methodCallExpression = Expression.Call(typeof(Queryable), GetSortingMethodName(options.SortDescending), + var methodCallExpression = Expression.Call(typeof(Queryable), GetSortingMethodName(sortDescending), new[] { parameterExpression.Type, sortByExpression.Type }, queryable.Expression, Expression.Quote(lambdaExpression)); diff --git a/src/Framework/Framework/Controls/GridViewDataSetOptions.cs b/src/Framework/Framework/Controls/GridViewDataSetOptions.cs deleted file mode 100644 index ff05a123cc..0000000000 --- a/src/Framework/Framework/Controls/GridViewDataSetOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace DotVVM.Framework.Controls -{ - public class GridViewDataSetOptions - where TFilteringOptions : IFilteringOptions - where TSortingOptions : ISortingOptions - where TPagingOptions : IPagingOptions - { - public TFilteringOptions? FilteringOptions { get; init; } = default; - - public TSortingOptions? SortingOptions { get; init; } = default; - - public TPagingOptions? PagingOptions { get; init; } = default; - } -} \ No newline at end of file