Refactoring and addressing comments

This commit is contained in:
Michael Bucari-Tovo 2022-05-23 21:20:26 -06:00
parent 4a82541ffd
commit d71cdecd35
13 changed files with 218 additions and 205 deletions

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<Version>7.7.0.14</Version> <Version>7.7.1.1</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -98,7 +98,7 @@
// filterBtn // filterBtn
// //
this.filterBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.filterBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.filterBtn.Location = new System.Drawing.Point(748, 3); this.filterBtn.Location = new System.Drawing.Point(916, 3);
this.filterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.filterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.filterBtn.Name = "filterBtn"; this.filterBtn.Name = "filterBtn";
this.filterBtn.Size = new System.Drawing.Size(88, 27); this.filterBtn.Size = new System.Drawing.Size(88, 27);
@ -114,7 +114,7 @@
this.filterSearchTb.Location = new System.Drawing.Point(196, 7); this.filterSearchTb.Location = new System.Drawing.Point(196, 7);
this.filterSearchTb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.filterSearchTb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.filterSearchTb.Name = "filterSearchTb"; this.filterSearchTb.Name = "filterSearchTb";
this.filterSearchTb.Size = new System.Drawing.Size(544, 23); this.filterSearchTb.Size = new System.Drawing.Size(712, 23);
this.filterSearchTb.TabIndex = 1; this.filterSearchTb.TabIndex = 1;
this.filterSearchTb.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress); this.filterSearchTb.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress);
// //
@ -132,7 +132,7 @@
this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Padding = new System.Windows.Forms.Padding(7, 2, 0, 2); this.menuStrip1.Padding = new System.Windows.Forms.Padding(7, 2, 0, 2);
this.menuStrip1.Size = new System.Drawing.Size(893, 24); this.menuStrip1.Size = new System.Drawing.Size(1061, 24);
this.menuStrip1.TabIndex = 0; this.menuStrip1.TabIndex = 0;
this.menuStrip1.Text = "menuStrip1"; this.menuStrip1.Text = "menuStrip1";
// //
@ -396,7 +396,7 @@
this.statusStrip1.Location = new System.Drawing.Point(0, 618); this.statusStrip1.Location = new System.Drawing.Point(0, 618);
this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0); this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0);
this.statusStrip1.Size = new System.Drawing.Size(893, 22); this.statusStrip1.Size = new System.Drawing.Size(1061, 22);
this.statusStrip1.TabIndex = 6; this.statusStrip1.TabIndex = 6;
this.statusStrip1.Text = "statusStrip1"; this.statusStrip1.Text = "statusStrip1";
// //
@ -410,7 +410,7 @@
// springLbl // springLbl
// //
this.springLbl.Name = "springLbl"; this.springLbl.Name = "springLbl";
this.springLbl.Size = new System.Drawing.Size(379, 17); this.springLbl.Size = new System.Drawing.Size(547, 17);
this.springLbl.Spring = true; this.springLbl.Spring = true;
// //
// backupsCountsLbl // backupsCountsLbl
@ -452,8 +452,8 @@
// splitContainer1.Panel2 // splitContainer1.Panel2
// //
this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1); this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1);
this.splitContainer1.Size = new System.Drawing.Size(1231, 640); this.splitContainer1.Size = new System.Drawing.Size(1463, 640);
this.splitContainer1.SplitterDistance = 893; this.splitContainer1.SplitterDistance = 1061;
this.splitContainer1.SplitterWidth = 8; this.splitContainer1.SplitterWidth = 8;
this.splitContainer1.TabIndex = 7; this.splitContainer1.TabIndex = 7;
// //
@ -470,7 +470,7 @@
this.panel1.Location = new System.Drawing.Point(0, 24); this.panel1.Location = new System.Drawing.Point(0, 24);
this.panel1.Margin = new System.Windows.Forms.Padding(0); this.panel1.Margin = new System.Windows.Forms.Padding(0);
this.panel1.Name = "panel1"; this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(893, 594); this.panel1.Size = new System.Drawing.Size(1061, 594);
this.panel1.TabIndex = 7; this.panel1.TabIndex = 7;
// //
// productsDisplay // productsDisplay
@ -482,16 +482,16 @@
this.productsDisplay.Location = new System.Drawing.Point(15, 36); this.productsDisplay.Location = new System.Drawing.Point(15, 36);
this.productsDisplay.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.productsDisplay.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.productsDisplay.Name = "productsDisplay"; this.productsDisplay.Name = "productsDisplay";
this.productsDisplay.Size = new System.Drawing.Size(863, 555); this.productsDisplay.Size = new System.Drawing.Size(1031, 555);
this.productsDisplay.TabIndex = 9; this.productsDisplay.TabIndex = 9;
this.productsDisplay.LiberateClicked += new System.EventHandler<DataLayer.LibraryBook>(this.ProductsDisplay_LiberateClicked);
this.productsDisplay.VisibleCountChanged += new System.EventHandler<int>(this.productsDisplay_VisibleCountChanged); this.productsDisplay.VisibleCountChanged += new System.EventHandler<int>(this.productsDisplay_VisibleCountChanged);
this.productsDisplay.LiberateClicked += new System.EventHandler<DataLayer.LibraryBook>(this.ProductsDisplay_LiberateClicked);
this.productsDisplay.InitialLoaded += new System.EventHandler(this.productsDisplay_InitialLoaded); this.productsDisplay.InitialLoaded += new System.EventHandler(this.productsDisplay_InitialLoaded);
// //
// toggleQueueHideBtn // toggleQueueHideBtn
// //
this.toggleQueueHideBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.toggleQueueHideBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.toggleQueueHideBtn.Location = new System.Drawing.Point(845, 3); this.toggleQueueHideBtn.Location = new System.Drawing.Point(1013, 3);
this.toggleQueueHideBtn.Margin = new System.Windows.Forms.Padding(4, 3, 15, 3); this.toggleQueueHideBtn.Margin = new System.Windows.Forms.Padding(4, 3, 15, 3);
this.toggleQueueHideBtn.Name = "toggleQueueHideBtn"; this.toggleQueueHideBtn.Name = "toggleQueueHideBtn";
this.toggleQueueHideBtn.Size = new System.Drawing.Size(33, 27); this.toggleQueueHideBtn.Size = new System.Drawing.Size(33, 27);
@ -507,14 +507,14 @@
this.processBookQueue1.Location = new System.Drawing.Point(0, 0); this.processBookQueue1.Location = new System.Drawing.Point(0, 0);
this.processBookQueue1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.processBookQueue1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.processBookQueue1.Name = "processBookQueue1"; this.processBookQueue1.Name = "processBookQueue1";
this.processBookQueue1.Size = new System.Drawing.Size(330, 640); this.processBookQueue1.Size = new System.Drawing.Size(394, 640);
this.processBookQueue1.TabIndex = 0; this.processBookQueue1.TabIndex = 0;
// //
// Form1 // Form1
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1231, 640); this.ClientSize = new System.Drawing.Size(1463, 640);
this.Controls.Add(this.splitContainer1); this.Controls.Add(this.splitContainer1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1; this.MainMenuStrip = this.menuStrip1;

View File

@ -57,12 +57,48 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<metadata name="filterHelpBtn.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="filterBtn.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="filterSearchTb.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<metadata name="menuStrip1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>132, 17</value> <value>132, 17</value>
</metadata> </metadata>
<metadata name="statusStrip1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="addQuickFilterBtn.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="splitContainer1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="panel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="productsDisplay.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="toggleQueueHideBtn.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="processBookQueue1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>

View File

@ -46,24 +46,31 @@ namespace LibationWinForms.ProcessQueue
public ProcessQueueControl() public ProcessQueueControl()
{ {
InitializeComponent(); InitializeComponent();
Logger = LogMe.RegisterForm(this);
runningTimeLbl.Text = string.Empty;
popoutBtn.DisplayStyle = ToolStripItemDisplayStyle.Text; popoutBtn.DisplayStyle = ToolStripItemDisplayStyle.Text;
popoutBtn.Name = "popoutBtn"; popoutBtn.Name = "popoutBtn";
popoutBtn.Text = "Pop Out"; popoutBtn.Text = "Pop Out";
popoutBtn.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; popoutBtn.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
popoutBtn.Alignment = ToolStripItemAlignment.Right; popoutBtn.Alignment = ToolStripItemAlignment.Right;
popoutBtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; popoutBtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
statusStrip1.Items.Add(popoutBtn); statusStrip1.Items.Add(popoutBtn);
Logger = LogMe.RegisterForm(this);
virtualFlowControl2.RequestData += VirtualFlowControl1_RequestData; virtualFlowControl2.RequestData += VirtualFlowControl1_RequestData;
virtualFlowControl2.ButtonClicked += VirtualFlowControl2_ButtonClicked; virtualFlowControl2.ButtonClicked += VirtualFlowControl2_ButtonClicked;
Queue.QueuededCountChanged += Queue_QueuededCountChanged; Queue.QueuededCountChanged += Queue_QueuededCountChanged;
Queue.CompletedCountChanged += Queue_CompletedCountChanged; Queue.CompletedCountChanged += Queue_CompletedCountChanged;
Load += ProcessQueueControl_Load;
}
private void ProcessQueueControl_Load(object sender, EventArgs e)
{
if (DesignMode) return;
runningTimeLbl.Text = string.Empty;
QueuedCount = 0; QueuedCount = 0;
ErrorCount = 0; ErrorCount = 0;
CompletedCount = 0; CompletedCount = 0;

View File

@ -114,9 +114,6 @@ namespace LibationWinForms.ProcessQueue
BookControls.Add(control); BookControls.Add(control);
panel1.Controls.Add(control); panel1.Controls.Add(control);
if (DesignMode)
return;
for (int i = 1; i < NUM_ACTUAL_CONTROLS; i++) for (int i = 1; i < NUM_ACTUAL_CONTROLS; i++)
{ {
control = InitControl(VirtualControlHeight * i); control = InitControl(VirtualControlHeight * i);

View File

@ -5,37 +5,12 @@ using LibationFileManager;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
namespace LibationWinForms namespace LibationWinForms
{ {
public interface IHierarchical<T> where T : class public abstract class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable
{
T Parent { get; }
}
public class LiberateButtonStatus : IComparable
{
public LiberatedStatus BookStatus;
public LiberatedStatus? PdfStatus;
public bool IsSeries;
public bool Expanded;
public int CompareTo(object obj)
{
if (obj is not LiberateButtonStatus second) return -1;
if (IsSeries && !second.IsSeries) return -1;
else if (!IsSeries && second.IsSeries) return 1;
else if (IsSeries && second.IsSeries) return 0;
else if (BookStatus == LiberatedStatus.Liberated && second.BookStatus != LiberatedStatus.Liberated) return -1;
else if (BookStatus != LiberatedStatus.Liberated && second.BookStatus == LiberatedStatus.Liberated) return 1;
else return BookStatus.CompareTo(second.BookStatus);
}
}
public abstract class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable, IHierarchical<GridEntry>
{ {
protected abstract Book Book { get; } protected abstract Book Book { get; }
@ -50,12 +25,7 @@ namespace LibationWinForms
NotifyPropertyChanged(); NotifyPropertyChanged();
} }
} }
[Browsable(false)]
public new bool InvokeRequired => base.InvokeRequired; public new bool InvokeRequired => base.InvokeRequired;
[Browsable(false)]
public GridEntry Parent { get; set; }
[Browsable(false)]
public abstract DateTime DateAdded { get; } public abstract DateTime DateAdded { get; }
public abstract string ProductRating { get; protected set; } public abstract string ProductRating { get; protected set; }
public abstract string PurchaseDate { get; protected set; } public abstract string PurchaseDate { get; protected set; }
@ -116,9 +86,16 @@ namespace LibationWinForms
internal static class GridEntryExtensions internal static class GridEntryExtensions
{ {
#nullable enable
public static IEnumerable<SeriesEntry> Series(this IEnumerable<GridEntry> gridEntries) public static IEnumerable<SeriesEntry> Series(this IEnumerable<GridEntry> gridEntries)
=> gridEntries.Where(i => i is SeriesEntry).Cast<SeriesEntry>(); => gridEntries.Where(i => i is SeriesEntry).Cast<SeriesEntry>();
public static IEnumerable<LibraryBookEntry> LibraryBooks(this IEnumerable<GridEntry> gridEntries) public static IEnumerable<LibraryBookEntry> LibraryBooks(this IEnumerable<GridEntry> gridEntries)
=> gridEntries.Where(i => i is LibraryBookEntry).Cast<LibraryBookEntry>(); => gridEntries.Where(i => i is LibraryBookEntry).Cast<LibraryBookEntry>();
public static LibraryBookEntry? FindBookByAsin(this IEnumerable<LibraryBookEntry> gridEntries, string audibleProductID)
=> gridEntries.FirstOrDefault(i => i.AudibleProductId == audibleProductID);
public static SeriesEntry? FindBookSeriesEntry(this IEnumerable<GridEntry> gridEntries, IEnumerable<SeriesBook> matchSeries)
=> gridEntries.Series().FirstOrDefault(i => matchSeries.Any(s => s.Series.Name == i.Series));
public static IEnumerable<SeriesEntry> EmptySeries(this IEnumerable<GridEntry> gridEntries)
=> gridEntries.Series().Where(i => i.Children.Count == 0);
} }
} }

View File

@ -8,7 +8,7 @@ using System.Linq;
namespace LibationWinForms namespace LibationWinForms
{ {
/* /*
* Allows filtering of the underlying SortableBindingList<GridEntry> * Allows filtering and sorting of the underlying BindingList<GridEntry>
* by implementing IBindingListView and using SearchEngineCommands * by implementing IBindingListView and using SearchEngineCommands
* *
* When filtering is applied, the filtered-out items are removed * When filtering is applied, the filtered-out items are removed
@ -19,19 +19,34 @@ namespace LibationWinForms
* Remove is overridden to ensure that removed items are removed from * Remove is overridden to ensure that removed items are removed from
* the base list (visible items) as well as the FilterRemoved list. * the base list (visible items) as well as the FilterRemoved list.
*/ */
internal class FilterableSortableBindingList : SortableBindingList1<GridEntry>, IBindingListView internal class GridEntryBindingList : BindingList<GridEntry>, IBindingListView
{ {
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
public GridEntryBindingList() : base(new List<GridEntry>()) { }
public GridEntryBindingList(IEnumerable<GridEntry> enumeration) : base(new List<GridEntry>(enumeration)) { }
/// <returns>All items in the list, including those filtered out.</returns>
public List<GridEntry> AllItems() => Items.Concat(FilterRemoved).ToList();
protected MemberComparer<GridEntry> Comparer { get; } = new();
protected override bool SupportsSortingCore => true;
protected override bool SupportsSearchingCore => true;
protected override bool IsSortedCore => isSorted;
protected override PropertyDescriptor SortPropertyCore => propertyDescriptor;
protected override ListSortDirection SortDirectionCore => listSortDirection;
public bool SupportsFiltering => true;
public string Filter { get => FilterString; set => ApplyFilter(value); }
/// <summary> /// <summary>
/// Items that were removed from the base list due to filtering /// Items that were removed from the base list due to filtering
/// </summary> /// </summary>
private readonly List<GridEntry> FilterRemoved = new(); private readonly List<GridEntry> FilterRemoved = new();
private string FilterString; private string FilterString;
private LibationSearchEngine.SearchResultSet SearchResults; private LibationSearchEngine.SearchResultSet SearchResults;
public FilterableSortableBindingList(IEnumerable<GridEntry> enumeration) : base(enumeration) { }
public FilterableSortableBindingList() : base(new List<GridEntry>()) { }
public bool SupportsFiltering => true;
public string Filter { get => FilterString; set => ApplyFilter(value); }
#region Unused - Advanced Filtering #region Unused - Advanced Filtering
public bool SupportsAdvancedSorting => false; public bool SupportsAdvancedSorting => false;
@ -49,9 +64,6 @@ namespace LibationWinForms
base.Remove(entry); base.Remove(entry);
} }
/// <returns>All items in the list, including those filtered out.</returns>
public List<GridEntry> AllItems() => Items.Concat(FilterRemoved).ToList();
private void ApplyFilter(string filterString) private void ApplyFilter(string filterString)
{ {
if (filterString != FilterString) if (filterString != FilterString)
@ -88,7 +100,7 @@ namespace LibationWinForms
public void CollapseItem(SeriesEntry sEntry) public void CollapseItem(SeriesEntry sEntry)
{ {
foreach (var episode in Items.Where(b => b.Parent == sEntry).Cast<LibraryBookEntry>().ToList()) foreach (var episode in Items.LibraryBooks().Where(b => b.Parent == sEntry).ToList())
{ {
FilterRemoved.Add(episode); FilterRemoved.Add(episode);
base.Remove(episode); base.Remove(episode);
@ -101,7 +113,7 @@ namespace LibationWinForms
{ {
var sindex = Items.IndexOf(sEntry); var sindex = Items.IndexOf(sEntry);
foreach (var episode in FilterRemoved.Where(b => b.Parent == sEntry).Cast<LibraryBookEntry>().ToList()) foreach (var episode in FilterRemoved.LibraryBooks().Where(b => b.Parent == sEntry).ToList())
{ {
if (SearchResults is null || SearchResults.Docs.Any(d => d.ProductId == episode.AudibleProductId)) if (SearchResults is null || SearchResults.Docs.Any(d => d.ProductId == episode.AudibleProductId))
{ {
@ -120,23 +132,19 @@ namespace LibationWinForms
int visibleCount = Items.Count; int visibleCount = Items.Count;
SuspendSorting = true;
foreach (var item in FilterRemoved.ToList()) foreach (var item in FilterRemoved.ToList())
{ {
if (item.Parent is null || item.Parent.Liberate.Expanded) if (item is SeriesEntry || (item is LibraryBookEntry lbe && (lbe.Parent is null || lbe.Parent.Liberate.Expanded)))
{ {
FilterRemoved.Remove(item); FilterRemoved.Remove(item);
base.InsertItem(visibleCount++, item); base.InsertItem(visibleCount++, item);
} }
} }
SuspendSorting = false;
if (IsSortedCore) if (IsSortedCore)
Sort(); Sort();
else else
//No user sort is applied, so do default sorting by PurchaseDate, descending //No user sort is applied, so do default sorting by DateAdded, descending
{ {
Comparer.PropertyName = nameof(GridEntry.DateAdded); Comparer.PropertyName = nameof(GridEntry.DateAdded);
Comparer.Direction = ListSortDirection.Descending; Comparer.Direction = ListSortDirection.Descending;
@ -148,5 +156,64 @@ namespace LibationWinForms
FilterString = null; FilterString = null;
SearchResults = null; SearchResults = null;
} }
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
Comparer.PropertyName = property.Name;
Comparer.Direction = direction;
Sort();
propertyDescriptor = property;
listSortDirection = direction;
isSorted = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected void Sort()
{
var itemsList = (List<GridEntry>)Items;
var sortedItems = Items.OrderBy(ge => ge, Comparer).ToList();
var children = sortedItems.LibraryBooks().Where(i => i.Parent is not null).ToList();
itemsList.Clear();
//Only add parentless items at this stage. After these items are added in the
//correct sorting order, go back and add the children beneath their parents.
itemsList.AddRange(sortedItems.Except(children));
foreach (var parent in children.Select(c => c.Parent).Distinct())
{
var pIndex = itemsList.IndexOf(parent);
foreach (var c in children.Where(c => c.Parent == parent))
itemsList.Insert(++pIndex, c);
}
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (isSorted && e.ListChangedType == ListChangedType.ItemChanged && e.PropertyDescriptor == SortPropertyCore)
{
var item = Items[e.NewIndex];
Sort();
var newIndex = Items.IndexOf(item);
base.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemMoved, newIndex, e.NewIndex));
}
else
base.OnListChanged(e);
}
protected override void RemoveSortCore()
{
isSorted = false;
propertyDescriptor = base.SortPropertyCore;
listSortDirection = base.SortDirectionCore;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
} }
} }

View File

@ -0,0 +1,28 @@
using DataLayer;
using System;
namespace LibationWinForms
{
public class LiberateButtonStatus : IComparable
{
public LiberatedStatus BookStatus { get; set; }
public LiberatedStatus? PdfStatus { get; set; }
public bool IsSeries { get; init; }
public bool Expanded { get; set; }
/// <summary>
/// Defines the Liberate column's sorting behavior
/// </summary>
public int CompareTo(object obj)
{
if (obj is not LiberateButtonStatus second) return -1;
if (IsSeries && !second.IsSeries) return -1;
else if (!IsSeries && second.IsSeries) return 1;
else if (IsSeries && second.IsSeries) return 0;
else if (BookStatus == LiberatedStatus.Liberated && second.BookStatus != LiberatedStatus.Liberated) return -1;
else if (BookStatus != LiberatedStatus.Liberated && second.BookStatus == LiberatedStatus.Liberated) return 1;
else return BookStatus.CompareTo(second.BookStatus);
}
}
}

View File

@ -1,16 +1,10 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Drawing;
using System.Linq; using System.Linq;
using ApplicationServices; using ApplicationServices;
using DataLayer; using DataLayer;
using Dinah.Core.DataBinding;
using Dinah.Core; using Dinah.Core;
using Dinah.Core.Drawing;
using LibationFileManager;
using System.Threading.Tasks;
namespace LibationWinForms namespace LibationWinForms
{ {
@ -30,7 +24,6 @@ namespace LibationWinForms
public string LongDescription { get; private set; } public string LongDescription { get; private set; }
#endregion #endregion
// alias
protected override Book Book => LibraryBook.Book; protected override Book Book => LibraryBook.Book;
#region Model properties exposed to the view #region Model properties exposed to the view
@ -69,9 +62,9 @@ namespace LibationWinForms
} }
#endregion #endregion
public LibraryBookEntry(LibraryBook libraryBook) => setLibraryBook(libraryBook); public LibraryBookEntry(LibraryBook libraryBook) => setLibraryBook(libraryBook);
public SeriesEntry Parent { get; init; }
public void UpdateLibraryBook(LibraryBook libraryBook) public void UpdateLibraryBook(LibraryBook libraryBook)
{ {
if (AudibleProductId != libraryBook.Book.AudibleProductId) if (AudibleProductId != libraryBook.Book.AudibleProductId)

View File

@ -47,10 +47,8 @@
this.tagAndDetailsGVColumn = new LibationWinForms.EditTagsDataGridViewImageButtonColumn(); this.tagAndDetailsGVColumn = new LibationWinForms.EditTagsDataGridViewImageButtonColumn();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.syncBindingSource = new LibationWinForms.SyncBindingSource(this.components); this.syncBindingSource = new LibationWinForms.SyncBindingSource(this.components);
this.bindingSource = new System.Windows.Forms.BindingSource(this.components);
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.bindingSource)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// gridEntryDataGridView // gridEntryDataGridView
@ -216,11 +214,7 @@
// //
// syncBindingSource // syncBindingSource
// //
this.syncBindingSource.DataSource = this.bindingSource; this.syncBindingSource.DataSource = typeof(LibationWinForms.GridEntry);
//
// bindingSource
//
this.bindingSource.DataSource = typeof(LibationWinForms.GridEntry);
// //
// ProductsGrid // ProductsGrid
// //
@ -233,7 +227,6 @@
this.Load += new System.EventHandler(this.ProductsGrid_Load); this.Load += new System.EventHandler(this.ProductsGrid_Load);
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.bindingSource)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
} }
@ -257,6 +250,5 @@
private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn; private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn;
private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn; private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn;
private SyncBindingSource syncBindingSource; private SyncBindingSource syncBindingSource;
private System.Windows.Forms.BindingSource bindingSource;
} }
} }

View File

@ -23,7 +23,7 @@ namespace LibationWinForms.grid
public event LibraryBookEntryRectangleClickedEventHandler DescriptionClicked; public event LibraryBookEntryRectangleClickedEventHandler DescriptionClicked;
public new event EventHandler<ScrollEventArgs> Scroll; public new event EventHandler<ScrollEventArgs> Scroll;
private FilterableSortableBindingList bindingList; private GridEntryBindingList bindingList;
internal IEnumerable<LibraryBookEntry> GetVisible() internal IEnumerable<LibraryBookEntry> GetVisible()
=> bindingList => bindingList
.LibraryBooks(); .LibraryBooks();
@ -89,20 +89,15 @@ namespace LibationWinForms.grid
var episodes = dbBooks.Where(b => b.Book.ContentType is ContentType.Episode).ToList(); var episodes = dbBooks.Where(b => b.Book.ContentType is ContentType.Episode).ToList();
var series = episodes.Select(lb => lb.Book.SeriesLink.First()).DistinctBy(s => s.Series).ToList(); foreach (var series in episodes.Select(lb => lb.Book.SeriesLink.First()).DistinctBy(s => s.Series))
foreach (var s in series)
{ {
var seriesEntry = new SeriesEntry(); var seriesEntry = new SeriesEntry(series, episodes.Where(lb => lb.Book.SeriesLink.First().Series == series.Book.SeriesLink.First().Series));
seriesEntry.Children = episodes.Where(lb => lb.Book.SeriesLink.First().Series == s.Book.SeriesLink.First().Series).Select(lb => new LibraryBookEntry(lb) { Parent = seriesEntry }).ToList();
seriesEntry.setSeriesBook(s);
geList.Add(seriesEntry); geList.Add(seriesEntry);
geList.AddRange(seriesEntry.Children); geList.AddRange(seriesEntry.Children);
} }
bindingList = new FilterableSortableBindingList(geList.OrderByDescending(e => e.DateAdded)); bindingList = new GridEntryBindingList(geList.OrderByDescending(e => e.DateAdded));
bindingList.CollapseAll(); bindingList.CollapseAll();
syncBindingSource.DataSource = bindingList; syncBindingSource.DataSource = bindingList;
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count()); VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
@ -116,39 +111,36 @@ namespace LibationWinForms.grid
//Add absent books to grid, or update current books //Add absent books to grid, or update current books
var allItmes = bindingList.AllItems().LibraryBooks(); var allItmes = bindingList.AllItems().LibraryBooks();
for (var i = dbBooks.Count - 1; i >= 0; i--) foreach (var libraryBook in dbBooks)
{ {
var libraryBook = dbBooks[i]; var existingItem = allItmes.FindBookByAsin(libraryBook.Book.AudibleProductId);
var existingItem = allItmes.FirstOrDefault(i => i.AudibleProductId == libraryBook.Book.AudibleProductId);
// add new to top // add new to top
if (existingItem is null) if (existingItem is null)
{ {
var lb = new LibraryBookEntry(libraryBook);
if (libraryBook.Book.ContentType is ContentType.Episode) if (libraryBook.Book.ContentType is ContentType.Episode)
{ {
LibraryBookEntry lbe;
//Find the series that libraryBook belongs to, if it exists //Find the series that libraryBook belongs to, if it exists
var series = bindingList.AllItems().Series().FirstOrDefault(i => libraryBook.Book.SeriesLink.Any(s => s.Series.Name == i.Series)); var series = bindingList.AllItems().FindBookSeriesEntry(libraryBook.Book.SeriesLink);
if (series is null) if (series is null)
{ {
//Series doesn't exist yet, so create and add it //Series doesn't exist yet, so create and add it
var newSeries = new SeriesEntry { Children = new List<LibraryBookEntry> { lb } }; var newSeries = new SeriesEntry(libraryBook.Book.SeriesLink.First(), libraryBook);
newSeries.setSeriesBook(libraryBook.Book.SeriesLink.First()); lbe = newSeries.Children[0];
lb.Parent = newSeries;
newSeries.Liberate.Expanded = true; newSeries.Liberate.Expanded = true;
bindingList.Insert(0, newSeries); bindingList.Insert(0, newSeries);
series = newSeries; series = newSeries;
} }
else else
{ {
lb.Parent = series; lbe = new(libraryBook) { Parent = series };
series.Children.Add(lb); series.Children.Add(lbe);
} }
//Add episode beneath the parent //Add episode beneath the parent
int seriesIndex = bindingList.IndexOf(series); int seriesIndex = bindingList.IndexOf(series);
bindingList.Insert(seriesIndex + 1, lb); bindingList.Insert(seriesIndex + 1, lbe);
if (series.Liberate.Expanded) if (series.Liberate.Expanded)
bindingList.ExpandItem(series); bindingList.ExpandItem(series);
@ -159,7 +151,7 @@ namespace LibationWinForms.grid
} }
else else
//Add the new product //Add the new product
bindingList.Insert(0, lb); bindingList.Insert(0, new LibraryBookEntry(libraryBook));
} }
// update existing // update existing
else else
@ -168,6 +160,9 @@ namespace LibationWinForms.grid
} }
} }
//Re-filter after updating existing / adding new books to capture any changes
Filter(existingFilter);
// remove deleted from grid. // remove deleted from grid.
// note: actual deletion from db must still occur via the RemoveBook feature. deleting from audible will not trigger this // note: actual deletion from db must still occur via the RemoveBook feature. deleting from audible will not trigger this
var removedBooks = var removedBooks =
@ -176,26 +171,23 @@ namespace LibationWinForms.grid
.LibraryBooks() .LibraryBooks()
.ExceptBy(dbBooks.Select(lb => lb.Book.AudibleProductId), ge => ge.AudibleProductId); .ExceptBy(dbBooks.Select(lb => lb.Book.AudibleProductId), ge => ge.AudibleProductId);
//Remove books in series from their parents' Children list
foreach (var removed in removedBooks.Where(b => b.Parent is not null)) foreach (var removed in removedBooks.Where(b => b.Parent is not null))
{ {
var series = removed.Parent as SeriesEntry; removed.Parent.Children.Remove(removed);
series.Children.Remove(removed); removed.Parent.NotifyPropertyChanged();
series.NotifyPropertyChanged();
} }
//Remove series that have no children //Remove series that have no children
var removedSeries = var removedSeries =
bindingList bindingList
.AllItems() .AllItems()
.Series() .EmptySeries();
.Where(i => i.Children.Count == 0);
foreach (var removed in removedBooks.Cast<GridEntry>().Concat(removedSeries)) foreach (var removed in removedBooks.Cast<GridEntry>().Concat(removedSeries))
//no need to re-filter for removed books //no need to re-filter for removed books
bindingList.Remove(removed); bindingList.Remove(removed);
Filter(existingFilter);
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count()); VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
} }

View File

@ -6,9 +6,9 @@ using System.Linq;
namespace LibationWinForms namespace LibationWinForms
{ {
internal class SeriesEntry : GridEntry public class SeriesEntry : GridEntry
{ {
public List<LibraryBookEntry> Children { get; set; } public List<LibraryBookEntry> Children { get; init; }
public override DateTime DateAdded => Children.Max(c => c.DateAdded); public override DateTime DateAdded => Children.Max(c => c.DateAdded);
public override string ProductRating public override string ProductRating
{ {
@ -55,7 +55,18 @@ namespace LibationWinForms
private LiberateButtonStatus _liberate = new LiberateButtonStatus { IsSeries = true }; private LiberateButtonStatus _liberate = new LiberateButtonStatus { IsSeries = true };
public void setSeriesBook(SeriesBook seriesBook) public SeriesEntry(SeriesBook seriesBook, IEnumerable<LibraryBook> children)
{
Children = children.Select(c=>new LibraryBookEntry(c) { Parent = this }).ToList();
SetSeriesBook(seriesBook);
}
public SeriesEntry(SeriesBook seriesBook, LibraryBook child)
{
Children = new() { new LibraryBookEntry(child) { Parent = this } };
SetSeriesBook(seriesBook);
}
private void SetSeriesBook(SeriesBook seriesBook)
{ {
SeriesBook = seriesBook; SeriesBook = seriesBook;
_memberValues = CreateMemberValueDictionary(); _memberValues = CreateMemberValueDictionary();

View File

@ -1,87 +0,0 @@
using Dinah.Core.DataBinding;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace LibationWinForms
{
internal class SortableBindingList1<T> : BindingList<T> where T : class, IMemberComparable, IHierarchical<T>
{
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
public SortableBindingList1() : base(new List<T>()) { }
public SortableBindingList1(IEnumerable<T> enumeration) : base(new List<T>(enumeration)) { }
protected bool SuspendSorting { get; set; }
protected MemberComparer<T> Comparer { get; } = new();
protected override bool SupportsSortingCore => true;
protected override bool SupportsSearchingCore => true;
protected override bool IsSortedCore => isSorted;
protected override PropertyDescriptor SortPropertyCore => propertyDescriptor;
protected override ListSortDirection SortDirectionCore => listSortDirection;
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
Comparer.PropertyName = property.Name;
Comparer.Direction = direction;
Sort();
propertyDescriptor = property;
listSortDirection = direction;
isSorted = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected void Sort()
{
List<T> itemsList = (List<T>)Items;
var sortedItems = Items.OrderBy(ge => ge, Comparer).ToList();
var children = sortedItems.Where(i => i.Parent is not null).ToList();
itemsList.Clear();
//Only add parentless items at this stage. After these items are added in the
//correct sorting order, go back and add the children beneath their parents.
itemsList.AddRange(sortedItems.Except(children));
foreach (var parent in children.Select(c => c.Parent).Distinct())
{
var pIndex = itemsList.IndexOf(parent);
foreach (var c in children.Where(c=> c.Parent == parent))
itemsList.Insert(++pIndex, c);
}
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (isSorted && !SuspendSorting &&
((e.ListChangedType == ListChangedType.ItemChanged && e.PropertyDescriptor == SortPropertyCore) ||
e.ListChangedType == ListChangedType.ItemAdded))
{
var item = Items[e.NewIndex];
Sort();
var newIndex = Items.IndexOf(item);
base.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemMoved, newIndex, e.NewIndex));
}
else
base.OnListChanged(e);
}
protected override void RemoveSortCore()
{
isSorted = false;
propertyDescriptor = base.SortPropertyCore;
listSortDirection = base.SortDirectionCore;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
}