Refactoring and addressing comments
This commit is contained in:
parent
4a82541ffd
commit
d71cdecd35
@ -3,7 +3,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Version>7.7.0.14</Version>
|
||||
<Version>7.7.1.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
26
Source/LibationWinForms/Form1.Designer.cs
generated
26
Source/LibationWinForms/Form1.Designer.cs
generated
@ -98,7 +98,7 @@
|
||||
// filterBtn
|
||||
//
|
||||
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.Name = "filterBtn";
|
||||
this.filterBtn.Size = new System.Drawing.Size(88, 27);
|
||||
@ -114,7 +114,7 @@
|
||||
this.filterSearchTb.Location = new System.Drawing.Point(196, 7);
|
||||
this.filterSearchTb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
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.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress);
|
||||
//
|
||||
@ -132,7 +132,7 @@
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
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.Text = "menuStrip1";
|
||||
//
|
||||
@ -396,7 +396,7 @@
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 618);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
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.Text = "statusStrip1";
|
||||
//
|
||||
@ -410,7 +410,7 @@
|
||||
// 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;
|
||||
//
|
||||
// backupsCountsLbl
|
||||
@ -452,8 +452,8 @@
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1231, 640);
|
||||
this.splitContainer1.SplitterDistance = 893;
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1463, 640);
|
||||
this.splitContainer1.SplitterDistance = 1061;
|
||||
this.splitContainer1.SplitterWidth = 8;
|
||||
this.splitContainer1.TabIndex = 7;
|
||||
//
|
||||
@ -470,7 +470,7 @@
|
||||
this.panel1.Location = new System.Drawing.Point(0, 24);
|
||||
this.panel1.Margin = new System.Windows.Forms.Padding(0);
|
||||
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;
|
||||
//
|
||||
// productsDisplay
|
||||
@ -482,16 +482,16 @@
|
||||
this.productsDisplay.Location = new System.Drawing.Point(15, 36);
|
||||
this.productsDisplay.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
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.LiberateClicked += new System.EventHandler<DataLayer.LibraryBook>(this.ProductsDisplay_LiberateClicked);
|
||||
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);
|
||||
//
|
||||
// toggleQueueHideBtn
|
||||
//
|
||||
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.Name = "toggleQueueHideBtn";
|
||||
this.toggleQueueHideBtn.Size = new System.Drawing.Size(33, 27);
|
||||
@ -507,14 +507,14 @@
|
||||
this.processBookQueue1.Location = new System.Drawing.Point(0, 0);
|
||||
this.processBookQueue1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
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;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
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.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
|
||||
@ -57,12 +57,48 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</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">
|
||||
<value>17, 17</value>
|
||||
</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">
|
||||
<value>132, 17</value>
|
||||
</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" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
@ -46,24 +46,31 @@ namespace LibationWinForms.ProcessQueue
|
||||
public ProcessQueueControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
Logger = LogMe.RegisterForm(this);
|
||||
|
||||
runningTimeLbl.Text = string.Empty;
|
||||
popoutBtn.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
popoutBtn.Name = "popoutBtn";
|
||||
popoutBtn.Text = "Pop Out";
|
||||
popoutBtn.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
popoutBtn.Alignment = ToolStripItemAlignment.Right;
|
||||
popoutBtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
|
||||
statusStrip1.Items.Add(popoutBtn);
|
||||
|
||||
Logger = LogMe.RegisterForm(this);
|
||||
|
||||
virtualFlowControl2.RequestData += VirtualFlowControl1_RequestData;
|
||||
virtualFlowControl2.ButtonClicked += VirtualFlowControl2_ButtonClicked;
|
||||
|
||||
Queue.QueuededCountChanged += Queue_QueuededCountChanged;
|
||||
Queue.CompletedCountChanged += Queue_CompletedCountChanged;
|
||||
|
||||
Load += ProcessQueueControl_Load;
|
||||
}
|
||||
|
||||
private void ProcessQueueControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (DesignMode) return;
|
||||
|
||||
runningTimeLbl.Text = string.Empty;
|
||||
QueuedCount = 0;
|
||||
ErrorCount = 0;
|
||||
CompletedCount = 0;
|
||||
|
||||
@ -114,9 +114,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
BookControls.Add(control);
|
||||
panel1.Controls.Add(control);
|
||||
|
||||
if (DesignMode)
|
||||
return;
|
||||
|
||||
for (int i = 1; i < NUM_ACTUAL_CONTROLS; i++)
|
||||
{
|
||||
control = InitControl(VirtualControlHeight * i);
|
||||
|
||||
@ -5,37 +5,12 @@ using LibationFileManager;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;using System.Drawing;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public interface IHierarchical<T> where T : class
|
||||
{
|
||||
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>
|
||||
public abstract class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable
|
||||
{
|
||||
protected abstract Book Book { get; }
|
||||
|
||||
@ -50,12 +25,7 @@ namespace LibationWinForms
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public new bool InvokeRequired => base.InvokeRequired;
|
||||
[Browsable(false)]
|
||||
public GridEntry Parent { get; set; }
|
||||
[Browsable(false)]
|
||||
public abstract DateTime DateAdded { get; }
|
||||
public abstract string ProductRating { get; protected set; }
|
||||
public abstract string PurchaseDate { get; protected set; }
|
||||
@ -116,9 +86,16 @@ namespace LibationWinForms
|
||||
|
||||
internal static class GridEntryExtensions
|
||||
{
|
||||
#nullable enable
|
||||
public static IEnumerable<SeriesEntry> Series(this IEnumerable<GridEntry> gridEntries)
|
||||
=> gridEntries.Where(i => i is SeriesEntry).Cast<SeriesEntry>();
|
||||
public static IEnumerable<LibraryBookEntry> LibraryBooks(this IEnumerable<GridEntry> gridEntries)
|
||||
=> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ using System.Linq;
|
||||
namespace LibationWinForms
|
||||
{
|
||||
/*
|
||||
* Allows filtering of the underlying SortableBindingList<GridEntry>
|
||||
* Allows filtering and sorting of the underlying BindingList<GridEntry>
|
||||
* by implementing IBindingListView and using SearchEngineCommands
|
||||
*
|
||||
* 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
|
||||
* 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>
|
||||
/// Items that were removed from the base list due to filtering
|
||||
/// </summary>
|
||||
private readonly List<GridEntry> FilterRemoved = new();
|
||||
private string FilterString;
|
||||
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
|
||||
public bool SupportsAdvancedSorting => false;
|
||||
@ -49,9 +64,6 @@ namespace LibationWinForms
|
||||
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)
|
||||
{
|
||||
if (filterString != FilterString)
|
||||
@ -88,7 +100,7 @@ namespace LibationWinForms
|
||||
|
||||
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);
|
||||
base.Remove(episode);
|
||||
@ -101,7 +113,7 @@ namespace LibationWinForms
|
||||
{
|
||||
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))
|
||||
{
|
||||
@ -120,23 +132,19 @@ namespace LibationWinForms
|
||||
|
||||
int visibleCount = Items.Count;
|
||||
|
||||
SuspendSorting = true;
|
||||
|
||||
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);
|
||||
base.InsertItem(visibleCount++, item);
|
||||
}
|
||||
}
|
||||
|
||||
SuspendSorting = false;
|
||||
|
||||
if (IsSortedCore)
|
||||
Sort();
|
||||
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.Direction = ListSortDirection.Descending;
|
||||
@ -148,5 +156,64 @@ namespace LibationWinForms
|
||||
FilterString = 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Source/LibationWinForms/grid/LiberateButtonStatus.cs
Normal file
28
Source/LibationWinForms/grid/LiberateButtonStatus.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using ApplicationServices;
|
||||
using DataLayer;
|
||||
using Dinah.Core.DataBinding;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.Drawing;
|
||||
using LibationFileManager;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
@ -30,7 +24,6 @@ namespace LibationWinForms
|
||||
public string LongDescription { get; private set; }
|
||||
#endregion
|
||||
|
||||
// alias
|
||||
protected override Book Book => LibraryBook.Book;
|
||||
#region Model properties exposed to the view
|
||||
|
||||
@ -69,9 +62,9 @@ namespace LibationWinForms
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public LibraryBookEntry(LibraryBook libraryBook) => setLibraryBook(libraryBook);
|
||||
|
||||
public SeriesEntry Parent { get; init; }
|
||||
public void UpdateLibraryBook(LibraryBook libraryBook)
|
||||
{
|
||||
if (AudibleProductId != libraryBook.Book.AudibleProductId)
|
||||
|
||||
@ -47,10 +47,8 @@
|
||||
this.tagAndDetailsGVColumn = new LibationWinForms.EditTagsDataGridViewImageButtonColumn();
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(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.syncBindingSource)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bindingSource)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// gridEntryDataGridView
|
||||
@ -216,11 +214,7 @@
|
||||
//
|
||||
// syncBindingSource
|
||||
//
|
||||
this.syncBindingSource.DataSource = this.bindingSource;
|
||||
//
|
||||
// bindingSource
|
||||
//
|
||||
this.bindingSource.DataSource = typeof(LibationWinForms.GridEntry);
|
||||
this.syncBindingSource.DataSource = typeof(LibationWinForms.GridEntry);
|
||||
//
|
||||
// ProductsGrid
|
||||
//
|
||||
@ -233,7 +227,6 @@
|
||||
this.Load += new System.EventHandler(this.ProductsGrid_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bindingSource)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@ -257,6 +250,5 @@
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn;
|
||||
private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn;
|
||||
private SyncBindingSource syncBindingSource;
|
||||
private System.Windows.Forms.BindingSource bindingSource;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ namespace LibationWinForms.grid
|
||||
public event LibraryBookEntryRectangleClickedEventHandler DescriptionClicked;
|
||||
public new event EventHandler<ScrollEventArgs> Scroll;
|
||||
|
||||
private FilterableSortableBindingList bindingList;
|
||||
private GridEntryBindingList bindingList;
|
||||
internal IEnumerable<LibraryBookEntry> GetVisible()
|
||||
=> bindingList
|
||||
.LibraryBooks();
|
||||
@ -89,20 +89,15 @@ namespace LibationWinForms.grid
|
||||
|
||||
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 s in series)
|
||||
foreach (var series in episodes.Select(lb => lb.Book.SeriesLink.First()).DistinctBy(s => s.Series))
|
||||
{
|
||||
var seriesEntry = new SeriesEntry();
|
||||
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);
|
||||
var seriesEntry = new SeriesEntry(series, episodes.Where(lb => lb.Book.SeriesLink.First().Series == series.Book.SeriesLink.First().Series));
|
||||
|
||||
geList.Add(seriesEntry);
|
||||
geList.AddRange(seriesEntry.Children);
|
||||
}
|
||||
|
||||
bindingList = new FilterableSortableBindingList(geList.OrderByDescending(e => e.DateAdded));
|
||||
bindingList = new GridEntryBindingList(geList.OrderByDescending(e => e.DateAdded));
|
||||
bindingList.CollapseAll();
|
||||
syncBindingSource.DataSource = bindingList;
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
@ -116,39 +111,36 @@ namespace LibationWinForms.grid
|
||||
//Add absent books to grid, or update current books
|
||||
|
||||
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.FirstOrDefault(i => i.AudibleProductId == libraryBook.Book.AudibleProductId);
|
||||
var existingItem = allItmes.FindBookByAsin(libraryBook.Book.AudibleProductId);
|
||||
|
||||
// add new to top
|
||||
if (existingItem is null)
|
||||
{
|
||||
var lb = new LibraryBookEntry(libraryBook);
|
||||
|
||||
if (libraryBook.Book.ContentType is ContentType.Episode)
|
||||
{
|
||||
LibraryBookEntry lbe;
|
||||
//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)
|
||||
{
|
||||
//Series doesn't exist yet, so create and add it
|
||||
var newSeries = new SeriesEntry { Children = new List<LibraryBookEntry> { lb } };
|
||||
newSeries.setSeriesBook(libraryBook.Book.SeriesLink.First());
|
||||
lb.Parent = newSeries;
|
||||
var newSeries = new SeriesEntry(libraryBook.Book.SeriesLink.First(), libraryBook);
|
||||
lbe = newSeries.Children[0];
|
||||
newSeries.Liberate.Expanded = true;
|
||||
bindingList.Insert(0, newSeries);
|
||||
series = newSeries;
|
||||
}
|
||||
else
|
||||
{
|
||||
lb.Parent = series;
|
||||
series.Children.Add(lb);
|
||||
lbe = new(libraryBook) { Parent = series };
|
||||
series.Children.Add(lbe);
|
||||
}
|
||||
//Add episode beneath the parent
|
||||
int seriesIndex = bindingList.IndexOf(series);
|
||||
bindingList.Insert(seriesIndex + 1, lb);
|
||||
bindingList.Insert(seriesIndex + 1, lbe);
|
||||
|
||||
if (series.Liberate.Expanded)
|
||||
bindingList.ExpandItem(series);
|
||||
@ -159,7 +151,7 @@ namespace LibationWinForms.grid
|
||||
}
|
||||
else
|
||||
//Add the new product
|
||||
bindingList.Insert(0, lb);
|
||||
bindingList.Insert(0, new LibraryBookEntry(libraryBook));
|
||||
}
|
||||
// update existing
|
||||
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.
|
||||
// note: actual deletion from db must still occur via the RemoveBook feature. deleting from audible will not trigger this
|
||||
var removedBooks =
|
||||
@ -176,26 +171,23 @@ namespace LibationWinForms.grid
|
||||
.LibraryBooks()
|
||||
.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))
|
||||
{
|
||||
var series = removed.Parent as SeriesEntry;
|
||||
series.Children.Remove(removed);
|
||||
series.NotifyPropertyChanged();
|
||||
removed.Parent.Children.Remove(removed);
|
||||
removed.Parent.NotifyPropertyChanged();
|
||||
}
|
||||
|
||||
//Remove series that have no children
|
||||
var removedSeries =
|
||||
bindingList
|
||||
.AllItems()
|
||||
.Series()
|
||||
.Where(i => i.Children.Count == 0);
|
||||
.EmptySeries();
|
||||
|
||||
foreach (var removed in removedBooks.Cast<GridEntry>().Concat(removedSeries))
|
||||
//no need to re-filter for removed books
|
||||
bindingList.Remove(removed);
|
||||
|
||||
Filter(existingFilter);
|
||||
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
}
|
||||
|
||||
|
||||
@ -6,9 +6,9 @@ using System.Linq;
|
||||
|
||||
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 string ProductRating
|
||||
{
|
||||
@ -55,7 +55,18 @@ namespace LibationWinForms
|
||||
|
||||
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;
|
||||
_memberValues = CreateMemberValueDictionary();
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user