diff --git a/OpenNest.WinForms.Tests/Controls/BrowsePagerTests.cs b/OpenNest.WinForms.Tests/Controls/BrowsePagerTests.cs new file mode 100644 index 00000000..e91cb98c --- /dev/null +++ b/OpenNest.WinForms.Tests/Controls/BrowsePagerTests.cs @@ -0,0 +1,135 @@ +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using OpenNest.Controls; +using OpenNest.Data; + +namespace OpenNest.WinForms.Tests.Controls; + +public class BrowsePagerTests +{ + private enum Field { Name, Size } + + private enum OtherField { Size } + + [Fact] + public void LeftClickOnASortColumnSortsOnTheServerAndReversesOnTheSameColumn() => RunSta(() => + { + using var host = new Host(); + + host.Click(host.SizeColumn, MouseButtons.Left); + + Assert.Equal(1, host.Session.Queries); + Assert.Equal(Field.Size, host.Session.Sort); + Assert.False(host.Session.Descending); + Assert.Equal(1, host.Populated); + + host.Click(host.SizeColumn, MouseButtons.Left); + + Assert.Equal(2, host.Session.Queries); + Assert.True(host.Session.Descending); + }); + + [Fact] + public void OtherButtonsDoNotSort() => RunSta(() => + { + using var host = new Host(); + + host.Click(host.SizeColumn, MouseButtons.Right); + host.Click(host.SizeColumn, MouseButtons.Middle); + + Assert.Equal(0, host.Session.Queries); + Assert.Equal(Field.Name, host.Session.Sort); + }); + + [Fact] + public void ColumnsWithoutThisListsSortFieldDoNotSort() => RunSta(() => + { + using var host = new Host(); + + host.Click(host.UntaggedColumn, MouseButtons.Left); + host.Click(host.ForeignColumn, MouseButtons.Left); + + Assert.Equal(0, host.Session.Queries); + Assert.Equal(Field.Name, host.Session.Sort); + }); + + private static void RunSta(Action action) => + StaTestThread.Run(action, TimeSpan.FromSeconds(30), "The STA test did not complete."); + + private sealed class Host : IDisposable + { + private readonly DataGridView grid = new(); + private readonly Label summary = new(); + private readonly Button previous = new(); + private readonly Button next = new(); + private readonly BrowsePager pager; + + public Host() + { + UntaggedColumn = grid.Columns.Add("untagged", "Untagged"); + SizeColumn = grid.Columns.Add("size", "Size"); + ForeignColumn = grid.Columns.Add("foreign", "Foreign"); + grid.Columns[SizeColumn].Tag = Field.Size; + grid.Columns[ForeignColumn].Tag = OtherField.Size; + pager = new BrowsePager( + Session, grid, summary, previous, next, "the test list") + { + Populate = _ => Populated++, + }; + } + + public TestSession Session { get; } = new(); + + public int UntaggedColumn { get; } + + public int SizeColumn { get; } + + public int ForeignColumn { get; } + + public int Populated { get; private set; } + + public void Click(int column, MouseButtons button) + { + var mouse = new MouseEventArgs(button, 1, 0, 0, 0); + pager.SortByHeaderAsync(new DataGridViewCellMouseEventArgs(column, -1, 0, 0, mouse)) + .GetAwaiter().GetResult(); + } + + public void Dispose() + { + Session.Dispose(); + grid.Dispose(); + summary.Dispose(); + previous.Dispose(); + next.Dispose(); + } + } + + private sealed class Page : IBrowsePage + { + public int Offset => 0; + + public int Total => 0; + + public int ItemCount => 0; + } + + private sealed class TestSession : BrowseSession + { + public TestSession() + : base(pageSize: 10, maxPageSize: 100, Field.Name) + { + } + + public int Queries { get; private set; } + + public override string Summary => ""; + + protected override Task QueryAsync(CancellationToken cancellationToken) + { + Queries++; + return Task.FromResult(new Page()); + } + } +} diff --git a/OpenNest/Controls/BrowsePager.cs b/OpenNest/Controls/BrowsePager.cs index 9206bbcd..3c9fe15d 100644 --- a/OpenNest/Controls/BrowsePager.cs +++ b/OpenNest/Controls/BrowsePager.cs @@ -84,6 +84,15 @@ namespace OpenNest.Controls } } + /// + /// Sorts by a left-clicked column whose is a sort + /// field. Sorting a page locally would misrepresent the list; the server sorts all matches. + /// + public Task SortByHeaderAsync(DataGridViewCellMouseEventArgs e) => + e.Button == MouseButtons.Left && grid.Columns[e.ColumnIndex].Tag is TSort field + ? RunAsync(() => session.SortByAsync(field)) + : Task.CompletedTask; + public void UpdateNavigation() { previous.Enabled = !session.IsLoading && session.CanGoPrevious; diff --git a/OpenNest/Controls/DrawingLibraryView.cs b/OpenNest/Controls/DrawingLibraryView.cs index be22de44..4498729f 100644 --- a/OpenNest/Controls/DrawingLibraryView.cs +++ b/OpenNest/Controls/DrawingLibraryView.cs @@ -216,12 +216,9 @@ namespace OpenNest.Controls await RunAsync(() => session.SetShowAllAsync(showAll)); } - private async void DrawingGrid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) - { - // Sorting a page locally would misrepresent the library; the server sorts all matches. - if (e.Button == MouseButtons.Left && drawingGrid.Columns[e.ColumnIndex].Tag is DrawingSortField field) - await RunAsync(() => session.SortByAsync(field)); - } + private async void DrawingGrid_ColumnHeaderMouseClick( + object sender, DataGridViewCellMouseEventArgs e) => + await pager.SortByHeaderAsync(e); private async void PreviousButton_Click(object sender, EventArgs e) => await RunAsync(session.PreviousPageAsync); diff --git a/OpenNest/Controls/DrawingSetBrowser.cs b/OpenNest/Controls/DrawingSetBrowser.cs index e3b467ba..76a430c9 100644 --- a/OpenNest/Controls/DrawingSetBrowser.cs +++ b/OpenNest/Controls/DrawingSetBrowser.cs @@ -242,9 +242,8 @@ namespace OpenNest.Controls private async void SetGrid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { - // Sorting a page locally would misrepresent the list; the server sorts all matches. - if (session != null && e.Button == MouseButtons.Left && setGrid.Columns[e.ColumnIndex].Tag is DrawingSetSortField field) - await RunAsync(() => session.SortByAsync(field)); + if (session != null) + await pager.SortByHeaderAsync(e); } private async void PreviousButton_Click(object sender, EventArgs e) => diff --git a/OpenNest/Forms/AddReleaseDrawingsForm.cs b/OpenNest/Forms/AddReleaseDrawingsForm.cs index 4674c5bb..a1ecf7aa 100644 --- a/OpenNest/Forms/AddReleaseDrawingsForm.cs +++ b/OpenNest/Forms/AddReleaseDrawingsForm.cs @@ -72,12 +72,9 @@ namespace OpenNest.Forms await RunLibraryAsync(() => librarySession.SetSearchAsync(searchBox.Text)); } - private async void LibraryGrid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) - { - // Sorting a page locally would misrepresent the library; the server sorts all matches. - if (e.Button == MouseButtons.Left && libraryGrid.Columns[e.ColumnIndex].Tag is DrawingSortField field) - await RunLibraryAsync(() => librarySession.SortByAsync(field)); - } + private async void LibraryGrid_ColumnHeaderMouseClick( + object sender, DataGridViewCellMouseEventArgs e) => + await libraryPager.SortByHeaderAsync(e); private async void PreviousButton_Click(object sender, EventArgs e) => await RunLibraryAsync(librarySession.PreviousPageAsync); diff --git a/OpenNest/Forms/EditDrawingSetForm.cs b/OpenNest/Forms/EditDrawingSetForm.cs index dbd939fd..f517b82f 100644 --- a/OpenNest/Forms/EditDrawingSetForm.cs +++ b/OpenNest/Forms/EditDrawingSetForm.cs @@ -171,12 +171,9 @@ namespace OpenNest.Forms await RunLibraryAsync(() => librarySession.SetSearchAsync(searchBox.Text)); } - private async void LibraryGrid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) - { - // Sorting a page locally would misrepresent the library; the server sorts all matches. - if (e.Button == MouseButtons.Left && libraryGrid.Columns[e.ColumnIndex].Tag is DrawingSortField field) - await RunLibraryAsync(() => librarySession.SortByAsync(field)); - } + private async void LibraryGrid_ColumnHeaderMouseClick( + object sender, DataGridViewCellMouseEventArgs e) => + await libraryPager.SortByHeaderAsync(e); private async void PreviousButton_Click(object sender, EventArgs e) => await RunLibraryAsync(librarySession.PreviousPageAsync); diff --git a/OpenNest/Forms/SavedNestsForm.cs b/OpenNest/Forms/SavedNestsForm.cs index bdd495ef..ab370b40 100644 --- a/OpenNest/Forms/SavedNestsForm.cs +++ b/OpenNest/Forms/SavedNestsForm.cs @@ -128,12 +128,7 @@ public sealed class SavedNestsForm : Form Visible = false, SortMode = DataGridViewColumnSortMode.NotSortable, }); - // Sorting a page locally would misrepresent the archive; the server sorts all matches. - nestGrid.ColumnHeaderMouseClick += async (_, e) => - { - if (e.Button == MouseButtons.Left && nestGrid.Columns[e.ColumnIndex].Tag is NestSortField field) - await RunAsync(() => session.SortByAsync(field)); - }; + nestGrid.ColumnHeaderMouseClick += async (_, e) => await pager.SortByHeaderAsync(e); nestGrid.CellDoubleClick += (_, e) => { if (e.RowIndex >= 0)