mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-01-01 02:18:06 -05:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f880897542 | ||
|
|
b37472a954 | ||
|
|
68735a45dd | ||
|
|
e26deb9092 | ||
|
|
43d6ea82cd | ||
|
|
db1aa495ac | ||
|
|
ee62d9ae8d | ||
|
|
4001124cfa | ||
|
|
43a4d0d1d7 | ||
|
|
632b432b7c | ||
|
|
e778c7a59d | ||
|
|
d71cdecd35 | ||
|
|
4a82541ffd | ||
|
|
f29dff3386 | ||
|
|
718d21f6cb | ||
|
|
440550ded9 | ||
|
|
593fe57ea1 | ||
|
|
e8a320dac9 | ||
|
|
3cb43e5d3e | ||
|
|
f86bdba3c3 | ||
|
|
98c3940297 | ||
|
|
b9e789bbcf | ||
|
|
a108846731 | ||
|
|
0b4ce8d6e7 | ||
|
|
42df61b7dd | ||
|
|
6b46fa4cbc | ||
|
|
c0762eba18 | ||
|
|
036fb848e1 | ||
|
|
7198ae9025 | ||
|
|
d2822b06aa |
@@ -3,7 +3,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Version>7.6.2.1</Version>
|
||||
<Version>7.8.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -282,22 +282,20 @@ namespace AppScaffolding
|
||||
});
|
||||
}
|
||||
|
||||
public static (bool hasUpgrade, string zipUrl, string htmlUrl, string zipName) GetLatestRelease()
|
||||
public static UpgradeProperties GetLatestRelease()
|
||||
{
|
||||
(bool, string, string, string) isFalse = (false, null, null, null);
|
||||
|
||||
// timed out
|
||||
var latest = getLatestRelease(TimeSpan.FromSeconds(10));
|
||||
if (latest is null)
|
||||
return isFalse;
|
||||
return null;
|
||||
|
||||
var latestVersionString = latest.TagName.Trim('v');
|
||||
if (!Version.TryParse(latestVersionString, out var latestRelease))
|
||||
return isFalse;
|
||||
return null;
|
||||
|
||||
// we're up to date
|
||||
if (latestRelease <= BuildVersion)
|
||||
return isFalse;
|
||||
return null;
|
||||
|
||||
// we have an update
|
||||
var zip = latest.Assets.FirstOrDefault(a => a.BrowserDownloadUrl.EndsWith(".zip"));
|
||||
@@ -310,7 +308,7 @@ namespace AppScaffolding
|
||||
zipUrl
|
||||
});
|
||||
|
||||
return (true, zipUrl, latest.HtmlUrl, zip.Name);
|
||||
return new(zipUrl, latest.HtmlUrl, zip.Name, latestRelease);
|
||||
}
|
||||
private static Octokit.Release getLatestRelease(TimeSpan timeout)
|
||||
{
|
||||
|
||||
6
Source/AppScaffolding/UpgradeProperties.cs
Normal file
6
Source/AppScaffolding/UpgradeProperties.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace AppScaffolding
|
||||
{
|
||||
public record UpgradeProperties(string ZipUrl, string HtmlUrl, string ZipName, Version LatestRelease);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AudibleApi" Version="2.8.3.1" />
|
||||
<PackageReference Include="AudibleApi" Version="2.8.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="4.0.1.1" />
|
||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="4.1.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -29,7 +29,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<None Update="migrate.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace DataLayer
|
||||
public float StoryRating { get; private set; }
|
||||
|
||||
private Rating() { }
|
||||
internal Rating(float overallRating, float performanceRating, float storyRating)
|
||||
public Rating(float overallRating, float performanceRating, float storyRating)
|
||||
{
|
||||
OverallRating = overallRating;
|
||||
PerformanceRating = performanceRating;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"// this connection string is ONLY used for DataLayer's Migrations. this appsettings.json file is NOT used at all by application; it is overwritten": "",
|
||||
"LibationContext": "Data Source=LibationContext.db;Foreign Keys=False;"
|
||||
}
|
||||
}
|
||||
5
Source/DataLayer/migrate.json
Normal file
5
Source/DataLayer/migrate.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"LibationContext": "Data Source=LibationContext.db;Foreign Keys=False;"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Dinah.Core.Net.Http;
|
||||
|
||||
namespace FileLiberator
|
||||
{
|
||||
// currently only used to download the .zip flies for upgrade
|
||||
public class DownloadFile : Streamable
|
||||
{
|
||||
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
|
||||
{
|
||||
var client = new HttpClient();
|
||||
|
||||
var progress = new Progress<DownloadProgress>(OnStreamingProgressChanged);
|
||||
|
||||
OnStreamingBegin(proposedDownloadFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
var actualDownloadedFilePath = await client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, progress);
|
||||
OnFileCreated("Upgrade", actualDownloadedFilePath);
|
||||
return actualDownloadedFilePath;
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnStreamingCompleted(proposedDownloadFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ using FileLiberator;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
// streamlined, non-Forms copy of ProcessorAutomationController
|
||||
public abstract class ProcessableOptionsBase : OptionsBase
|
||||
{
|
||||
protected static TProcessable CreateProcessable<TProcessable>(EventHandler<LibraryBook> completedAction = null)
|
||||
|
||||
@@ -34,15 +34,15 @@ namespace LibationCli
|
||||
|
||||
private static void checkForUpdate()
|
||||
{
|
||||
var (hasUpgrade, zipUrl, htmlUrl, zipName) = LibationScaffolding.GetLatestRelease();
|
||||
if (!hasUpgrade)
|
||||
var upgradeProperties = LibationScaffolding.GetLatestRelease();
|
||||
if (upgradeProperties is null)
|
||||
return;
|
||||
|
||||
var origColor = Console.ForegroundColor;
|
||||
try
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"UPDATE AVAILABLE @ {zipUrl}");
|
||||
Console.WriteLine($"UPDATE AVAILABLE @ {upgradeProperties.ZipUrl}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -421,7 +421,7 @@ namespace LibationFileManager
|
||||
return libationFilesPathCache;
|
||||
|
||||
// FIRST: must write here before SettingsFilePath in next step reads cache
|
||||
libationFilesPathCache = getLiberationFilesSettingFromJson();
|
||||
libationFilesPathCache = getLibationFilesSettingFromJson();
|
||||
|
||||
// SECOND. before setting to json file with SetWithJsonPath, PersistentDictionary must exist
|
||||
persistentDictionary = new PersistentDictionary(SettingsFilePath);
|
||||
@@ -443,7 +443,7 @@ namespace LibationFileManager
|
||||
|
||||
private static string libationFilesPathCache;
|
||||
|
||||
private string getLiberationFilesSettingFromJson()
|
||||
private string getLibationFilesSettingFromJson()
|
||||
{
|
||||
string startingContents = null;
|
||||
try
|
||||
@@ -482,6 +482,14 @@ namespace LibationFileManager
|
||||
{
|
||||
libationFilesPathCache = null;
|
||||
|
||||
// ensure exists
|
||||
if (!File.Exists(APPSETTINGS_JSON))
|
||||
{
|
||||
// getter creates new file, loads PersistentDictionary
|
||||
var _ = LibationFiles;
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
|
||||
var startingContents = File.ReadAllText(APPSETTINGS_JSON);
|
||||
var jObj = JObject.Parse(startingContents);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Exceptions" Version="8.1.0" />
|
||||
<PackageReference Include="Serilog.Exceptions" Version="8.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
partial class DownloadForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.filenameLbl = new System.Windows.Forms.Label();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.progressLbl = new System.Windows.Forms.Label();
|
||||
this.lastUpdateLbl = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// filenameLbl
|
||||
//
|
||||
this.filenameLbl.AutoSize = true;
|
||||
this.filenameLbl.Location = new System.Drawing.Point(12, 9);
|
||||
this.filenameLbl.Name = "filenameLbl";
|
||||
this.filenameLbl.Size = new System.Drawing.Size(52, 13);
|
||||
this.filenameLbl.TabIndex = 0;
|
||||
this.filenameLbl.Text = "[filename]";
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBar1.Location = new System.Drawing.Point(15, 67);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(877, 23);
|
||||
this.progressBar1.TabIndex = 4;
|
||||
//
|
||||
// progressLbl
|
||||
//
|
||||
this.progressLbl.Location = new System.Drawing.Point(12, 36);
|
||||
this.progressLbl.Name = "progressLbl";
|
||||
this.progressLbl.Size = new System.Drawing.Size(173, 13);
|
||||
this.progressLbl.TabIndex = 5;
|
||||
this.progressLbl.Text = "[2,999,999,999] of [2,999,999,999]";
|
||||
this.progressLbl.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||
//
|
||||
// lastUpdateLbl
|
||||
//
|
||||
this.lastUpdateLbl.AutoSize = true;
|
||||
this.lastUpdateLbl.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lastUpdateLbl.ForeColor = System.Drawing.Color.DarkRed;
|
||||
this.lastUpdateLbl.Location = new System.Drawing.Point(361, 36);
|
||||
this.lastUpdateLbl.Name = "lastUpdateLbl";
|
||||
this.lastUpdateLbl.Size = new System.Drawing.Size(81, 13);
|
||||
this.lastUpdateLbl.TabIndex = 6;
|
||||
this.lastUpdateLbl.Text = "Last updated";
|
||||
this.lastUpdateLbl.Visible = false;
|
||||
//
|
||||
// DownloadForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(904, 102);
|
||||
this.Controls.Add(this.lastUpdateLbl);
|
||||
this.Controls.Add(this.progressLbl);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.Controls.Add(this.filenameLbl);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "DownloadForm";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Downloading";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.DownloadForm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.DownloadForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label filenameLbl;
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private System.Windows.Forms.Label progressLbl;
|
||||
private System.Windows.Forms.Label lastUpdateLbl;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Dinah.Core.Net.Http;
|
||||
using Dinah.Core.Threading;
|
||||
using FileLiberator;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
public partial class DownloadForm : Form
|
||||
{
|
||||
protected Streamable Streamable { get; private set; }
|
||||
protected LogMe LogMe { get; private set; }
|
||||
private SynchronizeInvoker Invoker { get; init; }
|
||||
|
||||
public DownloadForm()
|
||||
{
|
||||
//SynchronizationContext.Current will be null until the process contains a Form.
|
||||
//If this is the first form created, it will not exist until after execution
|
||||
//reaches inside the constructor (after base class has been initialized).
|
||||
Invoker = new SynchronizeInvoker();
|
||||
InitializeComponent();
|
||||
|
||||
this.SetLibationIcon();
|
||||
progressLbl.Text = "";
|
||||
filenameLbl.Text = "";
|
||||
}
|
||||
|
||||
public void RegisterFileLiberator(Streamable streamable, LogMe logMe = null)
|
||||
{
|
||||
if (streamable is null) return;
|
||||
streamable.StreamingBegin += Streamable_StreamingBegin;
|
||||
streamable.StreamingProgressChanged += Streamable_StreamingProgressChanged;
|
||||
streamable.StreamingCompleted += (_, _) => this.UIThreadAsync(Close);
|
||||
Streamable = streamable;
|
||||
LogMe = logMe;
|
||||
}
|
||||
|
||||
|
||||
#region Streamable event handler overrides
|
||||
public void Streamable_StreamingBegin(object sender, string beginString)
|
||||
{
|
||||
Invoker.UIThreadAsync(Show);
|
||||
filenameLbl.UIThreadAsync(() => filenameLbl.Text = beginString);
|
||||
}
|
||||
public void Streamable_StreamingProgressChanged(object sender, DownloadProgress downloadProgress)
|
||||
{
|
||||
// this won't happen with download file. it will happen with download string
|
||||
if (!downloadProgress.TotalBytesToReceive.HasValue || downloadProgress.TotalBytesToReceive.Value <= 0)
|
||||
return;
|
||||
|
||||
progressLbl.UIThreadAsync(() => progressLbl.Text = $"{downloadProgress.BytesReceived:#,##0} of {downloadProgress.TotalBytesToReceive.Value:#,##0}");
|
||||
|
||||
var d = double.Parse(downloadProgress.BytesReceived.ToString()) / double.Parse(downloadProgress.TotalBytesToReceive.Value.ToString()) * 100.0;
|
||||
var i = int.Parse(Math.Truncate(d).ToString());
|
||||
progressBar1.UIThreadAsync(() => progressBar1.Value = i);
|
||||
|
||||
lastDownloadProgress = DateTime.Now;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region timer
|
||||
private Timer timer { get; } = new Timer { Interval = 1000 };
|
||||
private void DownloadForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
timer.Start();
|
||||
}
|
||||
private DateTime lastDownloadProgress = DateTime.Now;
|
||||
private void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
// if no update in the last 30 seconds, display frozen label
|
||||
lastUpdateLbl.UIThreadAsync(() => lastUpdateLbl.Visible = lastDownloadProgress.AddSeconds(30) < DateTime.Now);
|
||||
if (lastUpdateLbl.Visible)
|
||||
{
|
||||
var diff = DateTime.Now - lastDownloadProgress;
|
||||
var min = (int)diff.TotalMinutes;
|
||||
var minText = min > 0 ? $"{min}min " : "";
|
||||
|
||||
lastUpdateLbl.UIThreadAsync(() => lastUpdateLbl.Text = $"Frozen? Last download activity: {minText}{diff.Seconds}sec ago");
|
||||
}
|
||||
}
|
||||
private void DownloadForm_FormClosing(object sender, FormClosingEventArgs e) => timer.Stop();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using FileLiberator;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
// decouple serilog and form. include convenience factory method
|
||||
public class LogMe
|
||||
{
|
||||
public event EventHandler<string> LogInfo;
|
||||
public event EventHandler<string> LogErrorString;
|
||||
public event EventHandler<(Exception, string)> LogError;
|
||||
|
||||
private LogMe()
|
||||
{
|
||||
LogInfo += (_, text) => Serilog.Log.Logger.Information($"Automated backup: {text}");
|
||||
LogErrorString += (_, text) => Serilog.Log.Logger.Error(text);
|
||||
LogError += (_, tuple) => Serilog.Log.Logger.Error(tuple.Item1, tuple.Item2 ?? "Automated backup: error");
|
||||
}
|
||||
|
||||
public static LogMe RegisterForm<T>(T form) where T : ILogForm
|
||||
{
|
||||
var logMe = new LogMe();
|
||||
|
||||
if (form is null)
|
||||
return logMe;
|
||||
|
||||
logMe.LogInfo += (_, text) => form?.WriteLine(text);
|
||||
|
||||
logMe.LogErrorString += (_, text) => form?.WriteLine(text);
|
||||
|
||||
logMe.LogError += (_, tuple) =>
|
||||
{
|
||||
form?.WriteLine(tuple.Item2 ?? "Automated backup: error");
|
||||
form?.WriteLine("ERROR: " + tuple.Item1.Message);
|
||||
};
|
||||
|
||||
return logMe;
|
||||
}
|
||||
|
||||
public void Info(string text) => LogInfo?.Invoke(this, text);
|
||||
public void Error(string text) => LogErrorString?.Invoke(this, text);
|
||||
public void Error(Exception ex, string text = null) => LogError?.Invoke(this, (ex, text));
|
||||
}
|
||||
|
||||
public static class ProcessorAutomationController
|
||||
{
|
||||
public static void DownloadFile(string url, string destination, bool showDownloadCompletedDialog = false)
|
||||
{
|
||||
Serilog.Log.Logger.Information($"Begin {nameof(DownloadFile)} for {url}");
|
||||
|
||||
void onDownloadFileStreamingCompleted(object sender, string savedFile)
|
||||
{
|
||||
Serilog.Log.Logger.Information($"Completed {nameof(DownloadFile)} for {url}. Saved to {savedFile}");
|
||||
|
||||
if (showDownloadCompletedDialog)
|
||||
MessageBox.Show($"File downloaded to:{Environment.NewLine}{Environment.NewLine}{savedFile}");
|
||||
}
|
||||
|
||||
var downloadFile = new DownloadFile();
|
||||
var downloadForm = new DownloadForm();
|
||||
downloadForm.RegisterFileLiberator(downloadFile);
|
||||
downloadFile.StreamingCompleted += onDownloadFileStreamingCompleted;
|
||||
|
||||
async void runDownload() => await downloadFile.PerformDownloadFileAsync(url, destination);
|
||||
new Task(runDownload).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace LibationWinForms.Dialogs
|
||||
this.authorsDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.miscDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.purchaseDateGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.gridEntryBindingSource = new LibationWinForms.SyncBindingSource(this.components);
|
||||
this.gridEntryBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components);
|
||||
this.btnRemoveBooks = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this._dataGridView)).BeginInit();
|
||||
@@ -176,7 +176,7 @@ namespace LibationWinForms.Dialogs
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.DataGridView _dataGridView;
|
||||
private LibationWinForms.SyncBindingSource gridEntryBindingSource;
|
||||
private LibationWinForms.GridView.SyncBindingSource gridEntryBindingSource;
|
||||
private System.Windows.Forms.Button btnRemoveBooks;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.DataGridViewCheckBoxColumn removeDataGridViewCheckBoxColumn;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
@@ -121,10 +120,8 @@ namespace LibationWinForms.Dialogs
|
||||
}
|
||||
}
|
||||
|
||||
internal class RemovableGridEntry : GridEntry
|
||||
internal class RemovableGridEntry : GridView.LibraryBookEntry
|
||||
{
|
||||
private static readonly IComparer BoolComparer = new ObjectComparer<bool>();
|
||||
|
||||
private bool _remove = false;
|
||||
public RemovableGridEntry(LibraryBook libraryBook) : base(libraryBook) { }
|
||||
|
||||
@@ -147,12 +144,5 @@ namespace LibationWinForms.Dialogs
|
||||
return Remove;
|
||||
return base.GetMemberValue(memberName);
|
||||
}
|
||||
|
||||
public override IComparer GetMemberComparer(Type memberType)
|
||||
{
|
||||
if (memberType == typeof(bool))
|
||||
return BoolComparer;
|
||||
return base.GetMemberComparer(memberType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
939
Source/LibationWinForms/Form1.Designer.cs
generated
939
Source/LibationWinForms/Form1.Designer.cs
generated
@@ -28,111 +28,100 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
this.gridPanel = new System.Windows.Forms.Panel();
|
||||
this.filterHelpBtn = new System.Windows.Forms.Button();
|
||||
this.filterBtn = new System.Windows.Forms.Button();
|
||||
this.filterSearchTb = new System.Windows.Forms.TextBox();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.autoScanLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.noAccountsYetAddAccountToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeLibraryBooksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeAllAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeSomeAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.liberateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.beginBookBackupsToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.beginPdfBackupsToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.convertAllM4bToMp3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.liberateVisible2ToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exportLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.quickFiltersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.firstFilterIsDefaultToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.editQuickFiltersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.scanningToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.visibleBooksToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.liberateVisibleToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.replaceTagsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.setDownloadedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.accountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.basicSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.visibleCountLbl = new LibationWinForms.FormattableToolStripStatusLabel();
|
||||
this.springLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.pdfsCountsLbl = new LibationWinForms.FormattableToolStripStatusLabel();
|
||||
this.addQuickFilterBtn = new System.Windows.Forms.Button();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.toggleQueueHideBtn = new System.Windows.Forms.Button();
|
||||
this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessQueueControl();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// gridPanel
|
||||
//
|
||||
this.gridPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
this.filterHelpBtn = new System.Windows.Forms.Button();
|
||||
this.filterBtn = new System.Windows.Forms.Button();
|
||||
this.filterSearchTb = new System.Windows.Forms.TextBox();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.autoScanLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.noAccountsYetAddAccountToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeLibraryBooksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeAllAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeSomeAccountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.liberateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.beginBookBackupsToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.beginPdfBackupsToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.convertAllM4bToMp3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.liberateVisible2ToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exportLibraryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.quickFiltersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.firstFilterIsDefaultToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.editQuickFiltersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.scanningToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.visibleBooksToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.liberateVisibleToolStripMenuItem = new LibationWinForms.FormattableToolStripMenuItem();
|
||||
this.replaceTagsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.setDownloadedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.accountsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.basicSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.visibleCountLbl = new LibationWinForms.FormattableToolStripStatusLabel();
|
||||
this.springLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.pdfsCountsLbl = new LibationWinForms.FormattableToolStripStatusLabel();
|
||||
this.addQuickFilterBtn = new System.Windows.Forms.Button();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.productsDisplay = new LibationWinForms.GridView.ProductsDisplay();
|
||||
this.toggleQueueHideBtn = new System.Windows.Forms.Button();
|
||||
this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessQueueControl();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// filterHelpBtn
|
||||
//
|
||||
this.filterHelpBtn.Location = new System.Drawing.Point(15, 3);
|
||||
this.filterHelpBtn.Margin = new System.Windows.Forms.Padding(15, 3, 4, 3);
|
||||
this.filterHelpBtn.Name = "filterHelpBtn";
|
||||
this.filterHelpBtn.Size = new System.Drawing.Size(26, 27);
|
||||
this.filterHelpBtn.TabIndex = 3;
|
||||
this.filterHelpBtn.Text = "?";
|
||||
this.filterHelpBtn.UseVisualStyleBackColor = true;
|
||||
this.filterHelpBtn.Click += new System.EventHandler(this.filterHelpBtn_Click);
|
||||
//
|
||||
// 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(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);
|
||||
this.filterBtn.TabIndex = 2;
|
||||
this.filterBtn.Text = "Filter";
|
||||
this.filterBtn.UseVisualStyleBackColor = true;
|
||||
this.filterBtn.Click += new System.EventHandler(this.filterBtn_Click);
|
||||
//
|
||||
// filterSearchTb
|
||||
//
|
||||
this.filterSearchTb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.gridPanel.Location = new System.Drawing.Point(15, 33);
|
||||
this.gridPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.gridPanel.Name = "gridPanel";
|
||||
this.gridPanel.Size = new System.Drawing.Size(864, 558);
|
||||
this.gridPanel.TabIndex = 5;
|
||||
//
|
||||
// filterHelpBtn
|
||||
//
|
||||
this.filterHelpBtn.Location = new System.Drawing.Point(15, 3);
|
||||
this.filterHelpBtn.Margin = new System.Windows.Forms.Padding(15, 3, 4, 3);
|
||||
this.filterHelpBtn.Name = "filterHelpBtn";
|
||||
this.filterHelpBtn.Size = new System.Drawing.Size(26, 27);
|
||||
this.filterHelpBtn.TabIndex = 3;
|
||||
this.filterHelpBtn.Text = "?";
|
||||
this.filterHelpBtn.UseVisualStyleBackColor = true;
|
||||
this.filterHelpBtn.Click += new System.EventHandler(this.filterHelpBtn_Click);
|
||||
//
|
||||
// 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.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.filterBtn.Name = "filterBtn";
|
||||
this.filterBtn.Size = new System.Drawing.Size(88, 27);
|
||||
this.filterBtn.TabIndex = 2;
|
||||
this.filterBtn.Text = "Filter";
|
||||
this.filterBtn.UseVisualStyleBackColor = true;
|
||||
this.filterBtn.Click += new System.EventHandler(this.filterBtn_Click);
|
||||
//
|
||||
// filterSearchTb
|
||||
//
|
||||
this.filterSearchTb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
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.TabIndex = 1;
|
||||
this.filterSearchTb.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress);
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
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(712, 23);
|
||||
this.filterSearchTb.TabIndex = 1;
|
||||
this.filterSearchTb.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filterSearchTb_KeyPress);
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.importToolStripMenuItem,
|
||||
this.liberateToolStripMenuItem,
|
||||
this.exportToolStripMenuItem,
|
||||
@@ -140,402 +129,415 @@
|
||||
this.scanningToolStripMenuItem,
|
||||
this.visibleBooksToolStripMenuItem,
|
||||
this.settingsToolStripMenuItem});
|
||||
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.TabIndex = 0;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// importToolStripMenuItem
|
||||
//
|
||||
this.importToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
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(1061, 24);
|
||||
this.menuStrip1.TabIndex = 0;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// importToolStripMenuItem
|
||||
//
|
||||
this.importToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.autoScanLibraryToolStripMenuItem,
|
||||
this.noAccountsYetAddAccountToolStripMenuItem,
|
||||
this.scanLibraryToolStripMenuItem,
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem,
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem,
|
||||
this.removeLibraryBooksToolStripMenuItem});
|
||||
this.importToolStripMenuItem.Name = "importToolStripMenuItem";
|
||||
this.importToolStripMenuItem.Size = new System.Drawing.Size(55, 20);
|
||||
this.importToolStripMenuItem.Text = "&Import";
|
||||
//
|
||||
// autoScanLibraryToolStripMenuItem
|
||||
//
|
||||
this.autoScanLibraryToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.autoScanLibraryToolStripMenuItem.Name = "autoScanLibraryToolStripMenuItem";
|
||||
this.autoScanLibraryToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.autoScanLibraryToolStripMenuItem.Text = "A&uto Scan Library";
|
||||
this.autoScanLibraryToolStripMenuItem.Click += new System.EventHandler(this.autoScanLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// noAccountsYetAddAccountToolStripMenuItem
|
||||
//
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Name = "noAccountsYetAddAccountToolStripMenuItem";
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Text = "No accounts yet. A&dd Account...";
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Click += new System.EventHandler(this.noAccountsYetAddAccountToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryToolStripMenuItem.Name = "scanLibraryToolStripMenuItem";
|
||||
this.scanLibraryToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryToolStripMenuItem.Text = "Scan &Library";
|
||||
this.scanLibraryToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryOfAllAccountsToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Name = "scanLibraryOfAllAccountsToolStripMenuItem";
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Text = "Scan Library of &All Accounts";
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryOfAllAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryOfSomeAccountsToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Name = "scanLibraryOfSomeAccountsToolStripMenuItem";
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Text = "Scan Library of &Some Accounts...";
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryOfSomeAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// removeLibraryBooksToolStripMenuItem
|
||||
//
|
||||
this.removeLibraryBooksToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.importToolStripMenuItem.Name = "importToolStripMenuItem";
|
||||
this.importToolStripMenuItem.Size = new System.Drawing.Size(55, 20);
|
||||
this.importToolStripMenuItem.Text = "&Import";
|
||||
//
|
||||
// autoScanLibraryToolStripMenuItem
|
||||
//
|
||||
this.autoScanLibraryToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.autoScanLibraryToolStripMenuItem.Name = "autoScanLibraryToolStripMenuItem";
|
||||
this.autoScanLibraryToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.autoScanLibraryToolStripMenuItem.Text = "A&uto Scan Library";
|
||||
this.autoScanLibraryToolStripMenuItem.Click += new System.EventHandler(this.autoScanLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// noAccountsYetAddAccountToolStripMenuItem
|
||||
//
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Name = "noAccountsYetAddAccountToolStripMenuItem";
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Text = "No accounts yet. A&dd Account...";
|
||||
this.noAccountsYetAddAccountToolStripMenuItem.Click += new System.EventHandler(this.noAccountsYetAddAccountToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryToolStripMenuItem.Name = "scanLibraryToolStripMenuItem";
|
||||
this.scanLibraryToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryToolStripMenuItem.Text = "Scan &Library";
|
||||
this.scanLibraryToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryOfAllAccountsToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Name = "scanLibraryOfAllAccountsToolStripMenuItem";
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Text = "Scan Library of &All Accounts";
|
||||
this.scanLibraryOfAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryOfAllAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// scanLibraryOfSomeAccountsToolStripMenuItem
|
||||
//
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Name = "scanLibraryOfSomeAccountsToolStripMenuItem";
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Text = "Scan Library of &Some Accounts...";
|
||||
this.scanLibraryOfSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.scanLibraryOfSomeAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// removeLibraryBooksToolStripMenuItem
|
||||
//
|
||||
this.removeLibraryBooksToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.removeAllAccountsToolStripMenuItem,
|
||||
this.removeSomeAccountsToolStripMenuItem});
|
||||
this.removeLibraryBooksToolStripMenuItem.Name = "removeLibraryBooksToolStripMenuItem";
|
||||
this.removeLibraryBooksToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.removeLibraryBooksToolStripMenuItem.Text = "Remove Library Books";
|
||||
this.removeLibraryBooksToolStripMenuItem.Click += new System.EventHandler(this.removeLibraryBooksToolStripMenuItem_Click);
|
||||
//
|
||||
// removeAllAccountsToolStripMenuItem
|
||||
//
|
||||
this.removeAllAccountsToolStripMenuItem.Name = "removeAllAccountsToolStripMenuItem";
|
||||
this.removeAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||
this.removeAllAccountsToolStripMenuItem.Text = "All Accounts";
|
||||
this.removeAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeAllAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// removeSomeAccountsToolStripMenuItem
|
||||
//
|
||||
this.removeSomeAccountsToolStripMenuItem.Name = "removeSomeAccountsToolStripMenuItem";
|
||||
this.removeSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||
this.removeSomeAccountsToolStripMenuItem.Text = "Some Accounts";
|
||||
this.removeSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeSomeAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// liberateToolStripMenuItem
|
||||
//
|
||||
this.liberateToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.removeLibraryBooksToolStripMenuItem.Name = "removeLibraryBooksToolStripMenuItem";
|
||||
this.removeLibraryBooksToolStripMenuItem.Size = new System.Drawing.Size(247, 22);
|
||||
this.removeLibraryBooksToolStripMenuItem.Text = "Remove Library Books";
|
||||
this.removeLibraryBooksToolStripMenuItem.Click += new System.EventHandler(this.removeLibraryBooksToolStripMenuItem_Click);
|
||||
//
|
||||
// removeAllAccountsToolStripMenuItem
|
||||
//
|
||||
this.removeAllAccountsToolStripMenuItem.Name = "removeAllAccountsToolStripMenuItem";
|
||||
this.removeAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||
this.removeAllAccountsToolStripMenuItem.Text = "All Accounts";
|
||||
this.removeAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeAllAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// removeSomeAccountsToolStripMenuItem
|
||||
//
|
||||
this.removeSomeAccountsToolStripMenuItem.Name = "removeSomeAccountsToolStripMenuItem";
|
||||
this.removeSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||
this.removeSomeAccountsToolStripMenuItem.Text = "Some Accounts";
|
||||
this.removeSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeSomeAccountsToolStripMenuItem_Click);
|
||||
//
|
||||
// liberateToolStripMenuItem
|
||||
//
|
||||
this.liberateToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.beginBookBackupsToolStripMenuItem,
|
||||
this.beginPdfBackupsToolStripMenuItem,
|
||||
this.convertAllM4bToMp3ToolStripMenuItem,
|
||||
this.liberateVisible2ToolStripMenuItem});
|
||||
this.liberateToolStripMenuItem.Name = "liberateToolStripMenuItem";
|
||||
this.liberateToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
|
||||
this.liberateToolStripMenuItem.Text = "&Liberate";
|
||||
//
|
||||
// beginBookBackupsToolStripMenuItem
|
||||
//
|
||||
this.beginBookBackupsToolStripMenuItem.FormatText = "Begin &Book and PDF Backups: {0}";
|
||||
this.beginBookBackupsToolStripMenuItem.Name = "beginBookBackupsToolStripMenuItem";
|
||||
this.beginBookBackupsToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.beginBookBackupsToolStripMenuItem.Text = "Begin &Book and PDF Backups: {0}";
|
||||
this.beginBookBackupsToolStripMenuItem.Click += new System.EventHandler(this.beginBookBackupsToolStripMenuItem_Click);
|
||||
//
|
||||
// beginPdfBackupsToolStripMenuItem
|
||||
//
|
||||
this.beginPdfBackupsToolStripMenuItem.FormatText = "Begin &PDF Only Backups: {0}";
|
||||
this.beginPdfBackupsToolStripMenuItem.Name = "beginPdfBackupsToolStripMenuItem";
|
||||
this.beginPdfBackupsToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.beginPdfBackupsToolStripMenuItem.Text = "Begin &PDF Only Backups: {0}";
|
||||
this.beginPdfBackupsToolStripMenuItem.Click += new System.EventHandler(this.beginPdfBackupsToolStripMenuItem_Click);
|
||||
//
|
||||
// convertAllM4bToMp3ToolStripMenuItem
|
||||
//
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Name = "convertAllM4bToMp3ToolStripMenuItem";
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Text = "Convert all &M4b to Mp3 [Long-running]...";
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Click += new System.EventHandler(this.convertAllM4bToMp3ToolStripMenuItem_Click);
|
||||
//
|
||||
// liberateVisible2ToolStripMenuItem
|
||||
//
|
||||
this.liberateVisible2ToolStripMenuItem.FormatText = "Liberate &Visible Books: {0}";
|
||||
this.liberateVisible2ToolStripMenuItem.Name = "liberateVisible2ToolStripMenuItem";
|
||||
this.liberateVisible2ToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.liberateVisible2ToolStripMenuItem.Text = "Liberate &Visible Books: {0}";
|
||||
this.liberateVisible2ToolStripMenuItem.Click += new System.EventHandler(this.liberateVisible);
|
||||
//
|
||||
// exportToolStripMenuItem
|
||||
//
|
||||
this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.liberateToolStripMenuItem.Name = "liberateToolStripMenuItem";
|
||||
this.liberateToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
|
||||
this.liberateToolStripMenuItem.Text = "&Liberate";
|
||||
//
|
||||
// beginBookBackupsToolStripMenuItem
|
||||
//
|
||||
this.beginBookBackupsToolStripMenuItem.FormatText = "Begin &Book and PDF Backups: {0}";
|
||||
this.beginBookBackupsToolStripMenuItem.Name = "beginBookBackupsToolStripMenuItem";
|
||||
this.beginBookBackupsToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.beginBookBackupsToolStripMenuItem.Text = "Begin &Book and PDF Backups: {0}";
|
||||
this.beginBookBackupsToolStripMenuItem.Click += new System.EventHandler(this.beginBookBackupsToolStripMenuItem_Click);
|
||||
//
|
||||
// beginPdfBackupsToolStripMenuItem
|
||||
//
|
||||
this.beginPdfBackupsToolStripMenuItem.FormatText = "Begin &PDF Only Backups: {0}";
|
||||
this.beginPdfBackupsToolStripMenuItem.Name = "beginPdfBackupsToolStripMenuItem";
|
||||
this.beginPdfBackupsToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.beginPdfBackupsToolStripMenuItem.Text = "Begin &PDF Only Backups: {0}";
|
||||
this.beginPdfBackupsToolStripMenuItem.Click += new System.EventHandler(this.beginPdfBackupsToolStripMenuItem_Click);
|
||||
//
|
||||
// convertAllM4bToMp3ToolStripMenuItem
|
||||
//
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Name = "convertAllM4bToMp3ToolStripMenuItem";
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Text = "Convert all &M4b to Mp3 [Long-running]...";
|
||||
this.convertAllM4bToMp3ToolStripMenuItem.Click += new System.EventHandler(this.convertAllM4bToMp3ToolStripMenuItem_Click);
|
||||
//
|
||||
// liberateVisible2ToolStripMenuItem
|
||||
//
|
||||
this.liberateVisible2ToolStripMenuItem.FormatText = "Liberate &Visible Books: {0}";
|
||||
this.liberateVisible2ToolStripMenuItem.Name = "liberateVisible2ToolStripMenuItem";
|
||||
this.liberateVisible2ToolStripMenuItem.Size = new System.Drawing.Size(293, 22);
|
||||
this.liberateVisible2ToolStripMenuItem.Text = "Liberate &Visible Books: {0}";
|
||||
this.liberateVisible2ToolStripMenuItem.Click += new System.EventHandler(this.liberateVisible);
|
||||
//
|
||||
// exportToolStripMenuItem
|
||||
//
|
||||
this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.exportLibraryToolStripMenuItem});
|
||||
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
|
||||
this.exportToolStripMenuItem.Size = new System.Drawing.Size(53, 20);
|
||||
this.exportToolStripMenuItem.Text = "E&xport";
|
||||
//
|
||||
// exportLibraryToolStripMenuItem
|
||||
//
|
||||
this.exportLibraryToolStripMenuItem.Name = "exportLibraryToolStripMenuItem";
|
||||
this.exportLibraryToolStripMenuItem.Size = new System.Drawing.Size(156, 22);
|
||||
this.exportLibraryToolStripMenuItem.Text = "E&xport Library...";
|
||||
this.exportLibraryToolStripMenuItem.Click += new System.EventHandler(this.exportLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// quickFiltersToolStripMenuItem
|
||||
//
|
||||
this.quickFiltersToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
|
||||
this.exportToolStripMenuItem.Size = new System.Drawing.Size(53, 20);
|
||||
this.exportToolStripMenuItem.Text = "E&xport";
|
||||
//
|
||||
// exportLibraryToolStripMenuItem
|
||||
//
|
||||
this.exportLibraryToolStripMenuItem.Name = "exportLibraryToolStripMenuItem";
|
||||
this.exportLibraryToolStripMenuItem.Size = new System.Drawing.Size(156, 22);
|
||||
this.exportLibraryToolStripMenuItem.Text = "E&xport Library...";
|
||||
this.exportLibraryToolStripMenuItem.Click += new System.EventHandler(this.exportLibraryToolStripMenuItem_Click);
|
||||
//
|
||||
// quickFiltersToolStripMenuItem
|
||||
//
|
||||
this.quickFiltersToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.firstFilterIsDefaultToolStripMenuItem,
|
||||
this.editQuickFiltersToolStripMenuItem,
|
||||
this.toolStripSeparator1});
|
||||
this.quickFiltersToolStripMenuItem.Name = "quickFiltersToolStripMenuItem";
|
||||
this.quickFiltersToolStripMenuItem.Size = new System.Drawing.Size(84, 20);
|
||||
this.quickFiltersToolStripMenuItem.Text = "Quick &Filters";
|
||||
//
|
||||
// firstFilterIsDefaultToolStripMenuItem
|
||||
//
|
||||
this.firstFilterIsDefaultToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Name = "firstFilterIsDefaultToolStripMenuItem";
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Text = "Start Libation with 1st filter &Default";
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Click += new System.EventHandler(this.firstFilterIsDefaultToolStripMenuItem_Click);
|
||||
//
|
||||
// editQuickFiltersToolStripMenuItem
|
||||
//
|
||||
this.editQuickFiltersToolStripMenuItem.Name = "editQuickFiltersToolStripMenuItem";
|
||||
this.editQuickFiltersToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
|
||||
this.editQuickFiltersToolStripMenuItem.Text = "&Edit quick filters...";
|
||||
this.editQuickFiltersToolStripMenuItem.Click += new System.EventHandler(this.editQuickFiltersToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(253, 6);
|
||||
//
|
||||
// scanningToolStripMenuItem
|
||||
//
|
||||
this.scanningToolStripMenuItem.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
this.scanningToolStripMenuItem.Enabled = false;
|
||||
this.scanningToolStripMenuItem.Image = global::LibationWinForms.Properties.Resources.import_16x16;
|
||||
this.scanningToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.scanningToolStripMenuItem.Name = "scanningToolStripMenuItem";
|
||||
this.scanningToolStripMenuItem.Size = new System.Drawing.Size(93, 20);
|
||||
this.scanningToolStripMenuItem.Text = "Scanning...";
|
||||
this.scanningToolStripMenuItem.Visible = false;
|
||||
//
|
||||
// visibleBooksToolStripMenuItem
|
||||
//
|
||||
this.visibleBooksToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.quickFiltersToolStripMenuItem.Name = "quickFiltersToolStripMenuItem";
|
||||
this.quickFiltersToolStripMenuItem.Size = new System.Drawing.Size(84, 20);
|
||||
this.quickFiltersToolStripMenuItem.Text = "Quick &Filters";
|
||||
//
|
||||
// firstFilterIsDefaultToolStripMenuItem
|
||||
//
|
||||
this.firstFilterIsDefaultToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Name = "firstFilterIsDefaultToolStripMenuItem";
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Text = "Start Libation with 1st filter &Default";
|
||||
this.firstFilterIsDefaultToolStripMenuItem.Click += new System.EventHandler(this.firstFilterIsDefaultToolStripMenuItem_Click);
|
||||
//
|
||||
// editQuickFiltersToolStripMenuItem
|
||||
//
|
||||
this.editQuickFiltersToolStripMenuItem.Name = "editQuickFiltersToolStripMenuItem";
|
||||
this.editQuickFiltersToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
|
||||
this.editQuickFiltersToolStripMenuItem.Text = "&Edit quick filters...";
|
||||
this.editQuickFiltersToolStripMenuItem.Click += new System.EventHandler(this.editQuickFiltersToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(253, 6);
|
||||
//
|
||||
// scanningToolStripMenuItem
|
||||
//
|
||||
this.scanningToolStripMenuItem.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
this.scanningToolStripMenuItem.Enabled = false;
|
||||
this.scanningToolStripMenuItem.Image = global::LibationWinForms.Properties.Resources.import_16x16;
|
||||
this.scanningToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.scanningToolStripMenuItem.Name = "scanningToolStripMenuItem";
|
||||
this.scanningToolStripMenuItem.Size = new System.Drawing.Size(93, 20);
|
||||
this.scanningToolStripMenuItem.Text = "Scanning...";
|
||||
this.scanningToolStripMenuItem.Visible = false;
|
||||
//
|
||||
// visibleBooksToolStripMenuItem
|
||||
//
|
||||
this.visibleBooksToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.liberateVisibleToolStripMenuItem,
|
||||
this.replaceTagsToolStripMenuItem,
|
||||
this.setDownloadedToolStripMenuItem,
|
||||
this.removeToolStripMenuItem});
|
||||
this.visibleBooksToolStripMenuItem.FormatText = "&Visible Books: {0}";
|
||||
this.visibleBooksToolStripMenuItem.Name = "visibleBooksToolStripMenuItem";
|
||||
this.visibleBooksToolStripMenuItem.Size = new System.Drawing.Size(108, 20);
|
||||
this.visibleBooksToolStripMenuItem.Text = "&Visible Books: {0}";
|
||||
//
|
||||
// liberateVisibleToolStripMenuItem
|
||||
//
|
||||
this.liberateVisibleToolStripMenuItem.FormatText = "&Liberate: {0}";
|
||||
this.liberateVisibleToolStripMenuItem.Name = "liberateVisibleToolStripMenuItem";
|
||||
this.liberateVisibleToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.liberateVisibleToolStripMenuItem.Text = "&Liberate: {0}";
|
||||
this.liberateVisibleToolStripMenuItem.Click += new System.EventHandler(this.liberateVisible);
|
||||
//
|
||||
// replaceTagsToolStripMenuItem
|
||||
//
|
||||
this.replaceTagsToolStripMenuItem.Name = "replaceTagsToolStripMenuItem";
|
||||
this.replaceTagsToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.replaceTagsToolStripMenuItem.Text = "Replace &Tags...";
|
||||
this.replaceTagsToolStripMenuItem.Click += new System.EventHandler(this.replaceTagsToolStripMenuItem_Click);
|
||||
//
|
||||
// setDownloadedToolStripMenuItem
|
||||
//
|
||||
this.setDownloadedToolStripMenuItem.Name = "setDownloadedToolStripMenuItem";
|
||||
this.setDownloadedToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.setDownloadedToolStripMenuItem.Text = "Set \'&Downloaded\' status...";
|
||||
this.setDownloadedToolStripMenuItem.Click += new System.EventHandler(this.setDownloadedToolStripMenuItem_Click);
|
||||
//
|
||||
// removeToolStripMenuItem
|
||||
//
|
||||
this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
|
||||
this.removeToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.removeToolStripMenuItem.Text = "&Remove from library...";
|
||||
this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
|
||||
//
|
||||
// settingsToolStripMenuItem
|
||||
//
|
||||
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.visibleBooksToolStripMenuItem.FormatText = "&Visible Books: {0}";
|
||||
this.visibleBooksToolStripMenuItem.Name = "visibleBooksToolStripMenuItem";
|
||||
this.visibleBooksToolStripMenuItem.Size = new System.Drawing.Size(108, 20);
|
||||
this.visibleBooksToolStripMenuItem.Text = "&Visible Books: {0}";
|
||||
//
|
||||
// liberateVisibleToolStripMenuItem
|
||||
//
|
||||
this.liberateVisibleToolStripMenuItem.FormatText = "&Liberate: {0}";
|
||||
this.liberateVisibleToolStripMenuItem.Name = "liberateVisibleToolStripMenuItem";
|
||||
this.liberateVisibleToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.liberateVisibleToolStripMenuItem.Text = "&Liberate: {0}";
|
||||
this.liberateVisibleToolStripMenuItem.Click += new System.EventHandler(this.liberateVisible);
|
||||
//
|
||||
// replaceTagsToolStripMenuItem
|
||||
//
|
||||
this.replaceTagsToolStripMenuItem.Name = "replaceTagsToolStripMenuItem";
|
||||
this.replaceTagsToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.replaceTagsToolStripMenuItem.Text = "Replace &Tags...";
|
||||
this.replaceTagsToolStripMenuItem.Click += new System.EventHandler(this.replaceTagsToolStripMenuItem_Click);
|
||||
//
|
||||
// setDownloadedToolStripMenuItem
|
||||
//
|
||||
this.setDownloadedToolStripMenuItem.Name = "setDownloadedToolStripMenuItem";
|
||||
this.setDownloadedToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.setDownloadedToolStripMenuItem.Text = "Set \'&Downloaded\' status...";
|
||||
this.setDownloadedToolStripMenuItem.Click += new System.EventHandler(this.setDownloadedToolStripMenuItem_Click);
|
||||
//
|
||||
// removeToolStripMenuItem
|
||||
//
|
||||
this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
|
||||
this.removeToolStripMenuItem.Size = new System.Drawing.Size(209, 22);
|
||||
this.removeToolStripMenuItem.Text = "&Remove from library...";
|
||||
this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
|
||||
//
|
||||
// settingsToolStripMenuItem
|
||||
//
|
||||
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.accountsToolStripMenuItem,
|
||||
this.basicSettingsToolStripMenuItem,
|
||||
this.toolStripSeparator2,
|
||||
this.aboutToolStripMenuItem});
|
||||
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
|
||||
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
|
||||
this.settingsToolStripMenuItem.Text = "&Settings";
|
||||
//
|
||||
// accountsToolStripMenuItem
|
||||
//
|
||||
this.accountsToolStripMenuItem.Name = "accountsToolStripMenuItem";
|
||||
this.accountsToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.accountsToolStripMenuItem.Text = "&Accounts...";
|
||||
this.accountsToolStripMenuItem.Click += new System.EventHandler(this.accountsToolStripMenuItem_Click);
|
||||
//
|
||||
// basicSettingsToolStripMenuItem
|
||||
//
|
||||
this.basicSettingsToolStripMenuItem.Name = "basicSettingsToolStripMenuItem";
|
||||
this.basicSettingsToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.basicSettingsToolStripMenuItem.Text = "&Settings...";
|
||||
this.basicSettingsToolStripMenuItem.Click += new System.EventHandler(this.basicSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(130, 6);
|
||||
//
|
||||
// aboutToolStripMenuItem
|
||||
//
|
||||
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
|
||||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.aboutToolStripMenuItem.Text = "A&bout...";
|
||||
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
|
||||
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
|
||||
this.settingsToolStripMenuItem.Text = "&Settings";
|
||||
//
|
||||
// accountsToolStripMenuItem
|
||||
//
|
||||
this.accountsToolStripMenuItem.Name = "accountsToolStripMenuItem";
|
||||
this.accountsToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.accountsToolStripMenuItem.Text = "&Accounts...";
|
||||
this.accountsToolStripMenuItem.Click += new System.EventHandler(this.accountsToolStripMenuItem_Click);
|
||||
//
|
||||
// basicSettingsToolStripMenuItem
|
||||
//
|
||||
this.basicSettingsToolStripMenuItem.Name = "basicSettingsToolStripMenuItem";
|
||||
this.basicSettingsToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.basicSettingsToolStripMenuItem.Text = "&Settings...";
|
||||
this.basicSettingsToolStripMenuItem.Click += new System.EventHandler(this.basicSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(130, 6);
|
||||
//
|
||||
// aboutToolStripMenuItem
|
||||
//
|
||||
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
|
||||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(133, 22);
|
||||
this.aboutToolStripMenuItem.Text = "A&bout...";
|
||||
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.visibleCountLbl,
|
||||
this.springLbl,
|
||||
this.backupsCountsLbl,
|
||||
this.pdfsCountsLbl});
|
||||
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.TabIndex = 6;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// visibleCountLbl
|
||||
//
|
||||
this.visibleCountLbl.FormatText = "Visible: {0}";
|
||||
this.visibleCountLbl.Name = "visibleCountLbl";
|
||||
this.visibleCountLbl.Size = new System.Drawing.Size(61, 17);
|
||||
this.visibleCountLbl.Text = "Visible: {0}";
|
||||
//
|
||||
// springLbl
|
||||
//
|
||||
this.springLbl.Name = "springLbl";
|
||||
this.springLbl.Size = new System.Drawing.Size(379, 17);
|
||||
this.springLbl.Spring = true;
|
||||
//
|
||||
// backupsCountsLbl
|
||||
//
|
||||
this.backupsCountsLbl.Name = "backupsCountsLbl";
|
||||
this.backupsCountsLbl.Size = new System.Drawing.Size(218, 17);
|
||||
this.backupsCountsLbl.Text = "[Calculating backed up book quantities]";
|
||||
//
|
||||
// pdfsCountsLbl
|
||||
//
|
||||
this.pdfsCountsLbl.FormatText = "| PDFs: NOT d/l\'ed: {0} Downloaded: {1}";
|
||||
this.pdfsCountsLbl.Name = "pdfsCountsLbl";
|
||||
this.pdfsCountsLbl.Size = new System.Drawing.Size(218, 17);
|
||||
this.pdfsCountsLbl.Text = "| PDFs: NOT d/l\'ed: {0} Downloaded: {1}";
|
||||
//
|
||||
// addQuickFilterBtn
|
||||
//
|
||||
this.addQuickFilterBtn.Location = new System.Drawing.Point(50, 3);
|
||||
this.addQuickFilterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.addQuickFilterBtn.Name = "addQuickFilterBtn";
|
||||
this.addQuickFilterBtn.Size = new System.Drawing.Size(137, 27);
|
||||
this.addQuickFilterBtn.TabIndex = 4;
|
||||
this.addQuickFilterBtn.Text = "Add To Quick Filters";
|
||||
this.addQuickFilterBtn.UseVisualStyleBackColor = true;
|
||||
this.addQuickFilterBtn.Click += new System.EventHandler(this.addQuickFilterBtn_Click);
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.panel1);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.menuStrip1);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.statusStrip1);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1231, 640);
|
||||
this.splitContainer1.SplitterDistance = 893;
|
||||
this.splitContainer1.SplitterWidth = 8;
|
||||
this.splitContainer1.TabIndex = 7;
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.panel1.Controls.Add(this.toggleQueueHideBtn);
|
||||
this.panel1.Controls.Add(this.gridPanel);
|
||||
this.panel1.Controls.Add(this.addQuickFilterBtn);
|
||||
this.panel1.Controls.Add(this.filterHelpBtn);
|
||||
this.panel1.Controls.Add(this.filterSearchTb);
|
||||
this.panel1.Controls.Add(this.filterBtn);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
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.TabIndex = 7;
|
||||
//
|
||||
// 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.Margin = new System.Windows.Forms.Padding(4, 3, 15, 3);
|
||||
this.toggleQueueHideBtn.Name = "toggleQueueHideBtn";
|
||||
this.toggleQueueHideBtn.Size = new System.Drawing.Size(33, 27);
|
||||
this.toggleQueueHideBtn.TabIndex = 8;
|
||||
this.toggleQueueHideBtn.Text = "❱❱❱";
|
||||
this.toggleQueueHideBtn.UseVisualStyleBackColor = true;
|
||||
this.toggleQueueHideBtn.Click += new System.EventHandler(this.ToggleQueueHideBtn_Click);
|
||||
//
|
||||
// processBookQueue1
|
||||
//
|
||||
this.processBookQueue1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.processBookQueue1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
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.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.Controls.Add(this.splitContainer1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "Form1";
|
||||
this.Text = "Libation: Liberate your Library";
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.PerformLayout();
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
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(1061, 22);
|
||||
this.statusStrip1.TabIndex = 6;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// visibleCountLbl
|
||||
//
|
||||
this.visibleCountLbl.FormatText = "Visible: {0}";
|
||||
this.visibleCountLbl.Name = "visibleCountLbl";
|
||||
this.visibleCountLbl.Size = new System.Drawing.Size(61, 17);
|
||||
this.visibleCountLbl.Text = "Visible: {0}";
|
||||
//
|
||||
// springLbl
|
||||
//
|
||||
this.springLbl.Name = "springLbl";
|
||||
this.springLbl.Size = new System.Drawing.Size(547, 17);
|
||||
this.springLbl.Spring = true;
|
||||
//
|
||||
// backupsCountsLbl
|
||||
//
|
||||
this.backupsCountsLbl.Name = "backupsCountsLbl";
|
||||
this.backupsCountsLbl.Size = new System.Drawing.Size(218, 17);
|
||||
this.backupsCountsLbl.Text = "[Calculating backed up book quantities]";
|
||||
//
|
||||
// pdfsCountsLbl
|
||||
//
|
||||
this.pdfsCountsLbl.FormatText = "| PDFs: NOT d/l\'ed: {0} Downloaded: {1}";
|
||||
this.pdfsCountsLbl.Name = "pdfsCountsLbl";
|
||||
this.pdfsCountsLbl.Size = new System.Drawing.Size(218, 17);
|
||||
this.pdfsCountsLbl.Text = "| PDFs: NOT d/l\'ed: {0} Downloaded: {1}";
|
||||
//
|
||||
// addQuickFilterBtn
|
||||
//
|
||||
this.addQuickFilterBtn.Location = new System.Drawing.Point(50, 3);
|
||||
this.addQuickFilterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.addQuickFilterBtn.Name = "addQuickFilterBtn";
|
||||
this.addQuickFilterBtn.Size = new System.Drawing.Size(137, 27);
|
||||
this.addQuickFilterBtn.TabIndex = 4;
|
||||
this.addQuickFilterBtn.Text = "Add To Quick Filters";
|
||||
this.addQuickFilterBtn.UseVisualStyleBackColor = true;
|
||||
this.addQuickFilterBtn.Click += new System.EventHandler(this.addQuickFilterBtn_Click);
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.panel1);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.menuStrip1);
|
||||
this.splitContainer1.Panel1.Controls.Add(this.statusStrip1);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1463, 640);
|
||||
this.splitContainer1.SplitterDistance = 1061;
|
||||
this.splitContainer1.SplitterWidth = 8;
|
||||
this.splitContainer1.TabIndex = 7;
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.panel1.Controls.Add(this.productsDisplay);
|
||||
this.panel1.Controls.Add(this.toggleQueueHideBtn);
|
||||
this.panel1.Controls.Add(this.addQuickFilterBtn);
|
||||
this.panel1.Controls.Add(this.filterHelpBtn);
|
||||
this.panel1.Controls.Add(this.filterSearchTb);
|
||||
this.panel1.Controls.Add(this.filterBtn);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
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(1061, 594);
|
||||
this.panel1.TabIndex = 7;
|
||||
//
|
||||
// productsDisplay
|
||||
//
|
||||
this.productsDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.productsDisplay.AutoScroll = true;
|
||||
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(1031, 555);
|
||||
this.productsDisplay.TabIndex = 9;
|
||||
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(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);
|
||||
this.toggleQueueHideBtn.TabIndex = 8;
|
||||
this.toggleQueueHideBtn.Text = "❱❱❱";
|
||||
this.toggleQueueHideBtn.UseVisualStyleBackColor = true;
|
||||
this.toggleQueueHideBtn.Click += new System.EventHandler(this.ToggleQueueHideBtn_Click);
|
||||
//
|
||||
// processBookQueue1
|
||||
//
|
||||
this.processBookQueue1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.processBookQueue1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
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(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(1463, 640);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "Form1";
|
||||
this.Text = "Libation: Liberate your Library";
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel1.PerformLayout();
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Panel gridPanel;
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem importToolStripMenuItem;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
@@ -581,5 +583,6 @@
|
||||
private LibationWinForms.ProcessQueue.ProcessQueueControl processBookQueue1;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Button toggleQueueHideBtn;
|
||||
private LibationWinForms.GridView.ProductsDisplay productsDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace LibationWinForms
|
||||
|
||||
try
|
||||
{
|
||||
productsGrid.Filter(filterString);
|
||||
productsDisplay.Filter(filterString);
|
||||
lastGoodFilter = filterString;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace LibationWinForms
|
||||
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
|
||||
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));
|
||||
PictureStorage.SetDefaultImage(PictureSize._500x500, Properties.Resources.default_cover_500x500.ToBytes(format));
|
||||
PictureStorage.SetDefaultImage(PictureSize.Native, Properties.Resources.default_cover_500x500.ToBytes(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,27 +14,15 @@ namespace LibationWinForms
|
||||
int WidthChange = 0;
|
||||
private void Configure_ProcessQueue()
|
||||
{
|
||||
productsGrid.LiberateClicked += ProductsGrid_LiberateClicked;
|
||||
processBookQueue1.popoutBtn.Click += ProcessBookQueue1_PopOut;
|
||||
var coppalseState = Configuration.Instance.GetNonString<bool>(nameof(splitContainer1.Panel2Collapsed));
|
||||
WidthChange = splitContainer1.Panel2.Width + splitContainer1.SplitterWidth;
|
||||
SetQueueCollapseState(coppalseState);
|
||||
}
|
||||
|
||||
private void ProductsGrid_LiberateClicked(object sender, LibraryBook e)
|
||||
private void ProductsDisplay_LiberateClicked(object sender, LibraryBook e)
|
||||
{
|
||||
if (e.Book.Audio_Exists())
|
||||
{
|
||||
// liberated: open explorer to file
|
||||
var filePath = AudibleFileStorage.Audio.GetPath(e.Book.AudibleProductId);
|
||||
if (!Go.To.File(filePath))
|
||||
{
|
||||
var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
|
||||
MessageBox.Show($"File not found" + suffix);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (e.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated)
|
||||
if (e.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated)
|
||||
{
|
||||
SetQueueCollapseState(false);
|
||||
processBookQueue1.AddDownloadDecrypt(e);
|
||||
@@ -44,7 +32,16 @@ namespace LibationWinForms
|
||||
SetQueueCollapseState(false);
|
||||
processBookQueue1.AddDownloadPdf(e);
|
||||
}
|
||||
|
||||
else if (e.Book.Audio_Exists())
|
||||
{
|
||||
// liberated: open explorer to file
|
||||
var filePath = AudibleFileStorage.Audio.GetPath(e.Book.AudibleProductId);
|
||||
if (!Go.To.File(filePath))
|
||||
{
|
||||
var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
|
||||
MessageBox.Show($"File not found" + suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetQueueCollapseState(bool collapsed)
|
||||
|
||||
@@ -14,12 +14,6 @@ namespace LibationWinForms
|
||||
Load += updateFiltersMenu;
|
||||
QuickFilters.UseDefaultChanged += updateFirstFilterIsDefaultToolStripMenuItem;
|
||||
QuickFilters.Updated += updateFiltersMenu;
|
||||
|
||||
productsGrid.InitialLoaded += (_, __) =>
|
||||
{
|
||||
if (QuickFilters.UseDefault)
|
||||
performFilter(QuickFilters.Filters.FirstOrDefault());
|
||||
};
|
||||
}
|
||||
|
||||
private object quickFilterTag { get; } = new();
|
||||
@@ -56,5 +50,11 @@ namespace LibationWinForms
|
||||
private void addQuickFilterBtn_Click(object sender, EventArgs e) => QuickFilters.Add(this.filterSearchTb.Text);
|
||||
|
||||
private void editQuickFiltersToolStripMenuItem_Click(object sender, EventArgs e) => new EditQuickFilters().ShowDialog();
|
||||
|
||||
private void productsDisplay_InitialLoaded(object sender, EventArgs e)
|
||||
{
|
||||
if (QuickFilters.UseDefault)
|
||||
performFilter(QuickFilters.Filters.FirstOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,28 +17,16 @@ namespace LibationWinForms
|
||||
liberateVisibleToolStripMenuItem.Format(0);
|
||||
liberateVisible2ToolStripMenuItem.Format(0);
|
||||
|
||||
// bottom-left visible count
|
||||
productsGrid.VisibleCountChanged += (_, qty) => visibleCountLbl.Format(qty);
|
||||
|
||||
// top menu strip
|
||||
visibleBooksToolStripMenuItem.Format(0);
|
||||
productsGrid.VisibleCountChanged += (_, qty) => {
|
||||
visibleBooksToolStripMenuItem.Format(qty);
|
||||
visibleBooksToolStripMenuItem.Enabled = qty > 0;
|
||||
|
||||
var notLiberatedCount = productsGrid.GetVisible().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated);
|
||||
};
|
||||
|
||||
productsGrid.VisibleCountChanged += setLiberatedVisibleMenuItemAsync;
|
||||
LibraryCommands.BookUserDefinedItemCommitted += setLiberatedVisibleMenuItemAsync;
|
||||
}
|
||||
private async void setLiberatedVisibleMenuItemAsync(object _, int __)
|
||||
=> await Task.Run(setLiberatedVisibleMenuItem);
|
||||
private async void setLiberatedVisibleMenuItemAsync(object _, EventArgs __)
|
||||
=> await Task.Run(setLiberatedVisibleMenuItem);
|
||||
void setLiberatedVisibleMenuItem()
|
||||
{
|
||||
var notLiberated = productsGrid.GetVisible().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated);
|
||||
var notLiberated = productsDisplay.GetVisible().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated);
|
||||
this.UIThreadSync(() =>
|
||||
{
|
||||
if (notLiberated > 0)
|
||||
@@ -63,7 +51,7 @@ namespace LibationWinForms
|
||||
private async void liberateVisible(object sender, EventArgs e)
|
||||
{
|
||||
SetQueueCollapseState(false);
|
||||
await Task.Run(() => processBookQueue1.AddDownloadDecrypt(productsGrid.GetVisible()));
|
||||
await Task.Run(() => processBookQueue1.AddDownloadDecrypt(productsDisplay.GetVisible()));
|
||||
}
|
||||
|
||||
private void replaceTagsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
@@ -73,7 +61,7 @@ namespace LibationWinForms
|
||||
if (result != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var visibleLibraryBooks = productsGrid.GetVisible();
|
||||
var visibleLibraryBooks = productsDisplay.GetVisible();
|
||||
|
||||
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
|
||||
visibleLibraryBooks,
|
||||
@@ -95,7 +83,7 @@ namespace LibationWinForms
|
||||
if (result != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var visibleLibraryBooks = productsGrid.GetVisible();
|
||||
var visibleLibraryBooks = productsDisplay.GetVisible();
|
||||
|
||||
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
|
||||
visibleLibraryBooks,
|
||||
@@ -112,7 +100,7 @@ namespace LibationWinForms
|
||||
|
||||
private async void removeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var visibleLibraryBooks = productsGrid.GetVisible();
|
||||
var visibleLibraryBooks = productsDisplay.GetVisible();
|
||||
|
||||
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
|
||||
visibleLibraryBooks,
|
||||
@@ -125,5 +113,20 @@ namespace LibationWinForms
|
||||
var visibleIds = visibleLibraryBooks.Select(lb => lb.Book.AudibleProductId).ToList();
|
||||
await LibraryCommands.RemoveBooksAsync(visibleIds);
|
||||
}
|
||||
|
||||
private async void productsDisplay_VisibleCountChanged(object sender, int qty)
|
||||
{
|
||||
// bottom-left visible count
|
||||
visibleCountLbl.Format(qty);
|
||||
|
||||
// top menu strip
|
||||
visibleBooksToolStripMenuItem.Format(qty);
|
||||
visibleBooksToolStripMenuItem.Enabled = qty > 0;
|
||||
|
||||
//Not used for anything?
|
||||
var notLiberatedCount = productsDisplay.GetVisible().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated);
|
||||
|
||||
await Task.Run(setLiberatedVisibleMenuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,24 +12,10 @@ namespace LibationWinForms
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
private ProductsGrid productsGrid { get; }
|
||||
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (this.DesignMode)
|
||||
return;
|
||||
|
||||
{
|
||||
// I'd actually like these lines to be handled in the designer, but I'm currently getting this error when I try:
|
||||
// Failed to create component 'ProductsGrid'. The error message follows:
|
||||
// 'Microsoft.DotNet.DesignTools.Client.DesignToolsServerException: Object reference not set to an instance of an object.
|
||||
// Since the designer's choking on it, I'm keeping it below the DesignMode check to be safe
|
||||
productsGrid = new ProductsGrid { Dock = DockStyle.Fill };
|
||||
gridPanel.Controls.Add(productsGrid);
|
||||
}
|
||||
|
||||
// Pre-requisite:
|
||||
// Before calling anything else, including subscribing to events, ensure database exists. If we wait and let it happen lazily, race conditions and errors are likely during new installs
|
||||
using var _ = DbContexts.GetContext();
|
||||
@@ -67,8 +53,8 @@ namespace LibationWinForms
|
||||
|
||||
// Configure_Grid(); // since it's just this, can keep here. If it needs more, then give grid it's own 'partial class Form1'
|
||||
{
|
||||
this.Load += (_, __) => productsGrid.Display();
|
||||
LibraryCommands.LibrarySizeChanged += (_, __) => this.UIThreadAsync(() => productsGrid.Display());
|
||||
this.Load += (_, __) => productsDisplay.Display();
|
||||
LibraryCommands.LibrarySizeChanged += (_, __) => this.UIThreadAsync(() => productsDisplay.Display());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public abstract class AsyncNotifyPropertyChanged : SynchronizeInvoker, INotifyPropertyChanged
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class DataGridViewImageButtonCell : DataGridViewButtonCell
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
partial class DescriptionDisplay
|
||||
{
|
||||
@@ -1,17 +1,15 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public partial class DescriptionDisplay : Form
|
||||
{
|
||||
private int borderThickness = 5;
|
||||
|
||||
public int BorderThickness
|
||||
public int BorderThickness
|
||||
{
|
||||
get => borderThickness;
|
||||
set
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Drawing;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class EditTagsDataGridViewImageButtonColumn : DataGridViewButtonColumn
|
||||
{
|
||||
@@ -18,6 +19,12 @@ namespace LibationWinForms
|
||||
|
||||
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
|
||||
{
|
||||
if (rowIndex >= 0 && DataGridView.GetBoundItem<GridEntry>(rowIndex) is SeriesEntry)
|
||||
{
|
||||
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);
|
||||
return;
|
||||
}
|
||||
|
||||
var tagsString = (string)value;
|
||||
|
||||
var foreColor = tagsString?.Contains("hidden") == true ? HiddenForeColor : DataGridView.DefaultCellStyle.ForeColor;
|
||||
113
Source/LibationWinForms/GridView/GridEntry.cs
Normal file
113
Source/LibationWinForms/GridView/GridEntry.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using DataLayer;
|
||||
using Dinah.Core.DataBinding;
|
||||
using Dinah.Core.Drawing;
|
||||
using LibationFileManager;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public abstract class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable
|
||||
{
|
||||
protected abstract Book Book { get; }
|
||||
|
||||
private Image _cover;
|
||||
#region Model properties exposed to the view
|
||||
public Image Cover
|
||||
{
|
||||
get => _cover;
|
||||
protected set
|
||||
{
|
||||
_cover = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
public new bool InvokeRequired => base.InvokeRequired;
|
||||
public abstract DateTime DateAdded { get; }
|
||||
public abstract float SeriesIndex { get; }
|
||||
public abstract string ProductRating { get; protected set; }
|
||||
public abstract string PurchaseDate { get; protected set; }
|
||||
public abstract string MyRating { get; protected set; }
|
||||
public abstract string Series { get; protected set; }
|
||||
public abstract string Title { get; protected set; }
|
||||
public abstract string Length { get; protected set; }
|
||||
public abstract string Authors { get; protected set; }
|
||||
public abstract string Narrators { get; protected set; }
|
||||
public abstract string Category { get; protected set; }
|
||||
public abstract string Misc { get; protected set; }
|
||||
public abstract string Description { get; protected set; }
|
||||
public abstract string DisplayTags { get; }
|
||||
public abstract LiberateButtonStatus Liberate { get; }
|
||||
#endregion
|
||||
|
||||
#region Sorting
|
||||
|
||||
public GridEntry() => _memberValues = CreateMemberValueDictionary();
|
||||
private Dictionary<string, Func<object>> _memberValues { get; set; }
|
||||
protected abstract Dictionary<string, Func<object>> CreateMemberValueDictionary();
|
||||
|
||||
// These methods are implementation of Dinah.Core.DataBinding.IMemberComparable
|
||||
// Used by GridEntryBindingList for all sorting
|
||||
public virtual object GetMemberValue(string memberName) => _memberValues[memberName]();
|
||||
public IComparer GetMemberComparer(Type memberType) => _memberTypeComparers[memberType];
|
||||
|
||||
#endregion
|
||||
|
||||
protected void LoadCover()
|
||||
{
|
||||
// Get cover art. If it's default, subscribe to PictureCached
|
||||
{
|
||||
(bool isDefault, byte[] picture) = PictureStorage.GetPicture(new PictureDefinition(Book.PictureId, PictureSize._80x80));
|
||||
|
||||
if (isDefault)
|
||||
PictureStorage.PictureCached += PictureStorage_PictureCached;
|
||||
|
||||
// Mutable property. Set the field so PropertyChanged isn't fired.
|
||||
_cover = ImageReader.ToImage(picture);
|
||||
}
|
||||
}
|
||||
|
||||
private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e)
|
||||
{
|
||||
if (e.Definition.PictureId == Book.PictureId)
|
||||
{
|
||||
Cover = ImageReader.ToImage(e.Picture);
|
||||
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate comparers for every exposed member object type.
|
||||
private static readonly Dictionary<Type, IComparer> _memberTypeComparers = new()
|
||||
{
|
||||
{ typeof(string), new ObjectComparer<string>() },
|
||||
{ typeof(int), new ObjectComparer<int>() },
|
||||
{ typeof(float), new ObjectComparer<float>() },
|
||||
{ typeof(bool), new ObjectComparer<bool>() },
|
||||
{ typeof(DateTime), new ObjectComparer<DateTime>() },
|
||||
{ typeof(LiberateButtonStatus), new ObjectComparer<LiberateButtonStatus>() },
|
||||
};
|
||||
|
||||
~GridEntry()
|
||||
{
|
||||
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
231
Source/LibationWinForms/GridView/GridEntryBindingList.cs
Normal file
231
Source/LibationWinForms/GridView/GridEntryBindingList.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using ApplicationServices;
|
||||
using Dinah.Core.DataBinding;
|
||||
using LibationSearchEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* from the base list and added to the private FilterRemoved list.
|
||||
* When filtering is removed, items in the FilterRemoved list are
|
||||
* added back to the base list.
|
||||
*
|
||||
* Remove is overridden to ensure that removed items are removed from
|
||||
* the base list (visible items) as well as the FilterRemoved list.
|
||||
*/
|
||||
internal class GridEntryBindingList : BindingList<GridEntry>, IBindingListView
|
||||
{
|
||||
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();
|
||||
public bool SupportsFiltering => true;
|
||||
public string Filter { get => FilterString; set => ApplyFilter(value); }
|
||||
|
||||
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;
|
||||
|
||||
/// <summary> Items that were removed from the base list due to filtering </summary>
|
||||
private readonly List<GridEntry> FilterRemoved = new();
|
||||
private string FilterString;
|
||||
private SearchResultSet SearchResults;
|
||||
private bool isSorted;
|
||||
private ListSortDirection listSortDirection;
|
||||
private PropertyDescriptor propertyDescriptor;
|
||||
|
||||
|
||||
#region Unused - Advanced Filtering
|
||||
public bool SupportsAdvancedSorting => false;
|
||||
|
||||
//This ApplySort overload is only called if SupportsAdvancedSorting is true.
|
||||
//Otherwise BindingList.ApplySort() is used
|
||||
public void ApplySort(ListSortDescriptionCollection sorts) => throw new NotImplementedException();
|
||||
|
||||
public ListSortDescriptionCollection SortDescriptions => throw new NotImplementedException();
|
||||
#endregion
|
||||
|
||||
public new void Remove(GridEntry entry)
|
||||
{
|
||||
FilterRemoved.Remove(entry);
|
||||
base.Remove(entry);
|
||||
}
|
||||
|
||||
private void ApplyFilter(string filterString)
|
||||
{
|
||||
if (filterString != FilterString)
|
||||
RemoveFilter();
|
||||
|
||||
FilterString = filterString;
|
||||
SearchResults = SearchEngineCommands.Search(filterString);
|
||||
|
||||
var booksFilteredIn = Items.LibraryBooks().Join(SearchResults.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => (GridEntry)lbe);
|
||||
|
||||
//Find all series containing children that match the search criteria
|
||||
var seriesFilteredIn = Items.Series().Where(s => s.Children.Join(SearchResults.Docs, lbe => lbe.AudibleProductId, d => d.ProductId, (lbe, d) => lbe).Any());
|
||||
|
||||
var filteredOut = Items.Except(booksFilteredIn.Concat(seriesFilteredIn)).ToList();
|
||||
|
||||
foreach (var item in filteredOut)
|
||||
{
|
||||
FilterRemoved.Add(item);
|
||||
base.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void CollapseAll()
|
||||
{
|
||||
foreach (var series in Items.Series().ToList())
|
||||
CollapseItem(series);
|
||||
}
|
||||
|
||||
public void ExpandAll()
|
||||
{
|
||||
foreach (var series in Items.Series().ToList())
|
||||
ExpandItem(series);
|
||||
}
|
||||
|
||||
public void CollapseItem(SeriesEntry sEntry)
|
||||
{
|
||||
foreach (var episode in Items.LibraryBooks().Where(b => b.Parent == sEntry).ToList())
|
||||
{
|
||||
FilterRemoved.Add(episode);
|
||||
base.Remove(episode);
|
||||
}
|
||||
|
||||
sEntry.Liberate.Expanded = false;
|
||||
}
|
||||
|
||||
public void ExpandItem(SeriesEntry sEntry)
|
||||
{
|
||||
var sindex = Items.IndexOf(sEntry);
|
||||
|
||||
foreach (var episode in FilterRemoved.LibraryBooks().Where(b => b.Parent == sEntry).ToList())
|
||||
{
|
||||
if (SearchResults is null || SearchResults.Docs.Any(d => d.ProductId == episode.AudibleProductId))
|
||||
{
|
||||
FilterRemoved.Remove(episode);
|
||||
InsertItem(++sindex, episode);
|
||||
}
|
||||
}
|
||||
sEntry.Liberate.Expanded = true;
|
||||
}
|
||||
|
||||
public void RemoveFilter()
|
||||
{
|
||||
if (FilterString is null) return;
|
||||
|
||||
int visibleCount = Items.Count;
|
||||
|
||||
foreach (var item in FilterRemoved.ToList())
|
||||
{
|
||||
if (item is SeriesEntry || (item is LibraryBookEntry lbe && (lbe.Parent is null || lbe.Parent.Liberate.Expanded)))
|
||||
{
|
||||
FilterRemoved.Remove(item);
|
||||
InsertItem(visibleCount++, item);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSortedCore)
|
||||
Sort();
|
||||
else
|
||||
//No user sort is applied, so do default sorting by DateAdded, descending
|
||||
{
|
||||
Comparer.PropertyName = nameof(GridEntry.DateAdded);
|
||||
Comparer.Direction = ListSortDirection.Descending;
|
||||
Sort();
|
||||
}
|
||||
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||
|
||||
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 children = itemsList.LibraryBooks().Where(i => i.Parent is not null).ToList();
|
||||
|
||||
var sortedItems = itemsList.Except(children).OrderBy(ge => ge, Comparer).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);
|
||||
|
||||
foreach (var parent in children.Select(c => c.Parent).Distinct())
|
||||
{
|
||||
var pIndex = itemsList.IndexOf(parent);
|
||||
|
||||
//children should always be sorted by series index.
|
||||
foreach (var c in children.Where(c => c.Parent == parent).OrderBy(c => c.SeriesIndex))
|
||||
itemsList.Insert(++pIndex, c);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnListChanged(ListChangedEventArgs e)
|
||||
{
|
||||
if (e.ListChangedType == ListChangedType.ItemChanged)
|
||||
{
|
||||
if (Items[e.NewIndex] is LibraryBookEntry lbItem)
|
||||
{
|
||||
SearchResults = SearchEngineCommands.Search(FilterString);
|
||||
if (!SearchResults.Docs.Any(d => d.ProductId == lbItem.AudibleProductId))
|
||||
{
|
||||
FilterRemoved.Add(lbItem);
|
||||
base.Remove(lbItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSorted && e.PropertyDescriptor == SortPropertyCore)
|
||||
{
|
||||
var item = Items[e.NewIndex];
|
||||
Sort();
|
||||
var newIndex = Items.IndexOf(item);
|
||||
|
||||
base.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemMoved, newIndex, e.NewIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
base.OnListChanged(e);
|
||||
}
|
||||
|
||||
protected override void RemoveSortCore()
|
||||
{
|
||||
isSorted = false;
|
||||
propertyDescriptor = base.SortPropertyCore;
|
||||
listSortDirection = base.SortDirectionCore;
|
||||
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
partial class ImageDisplay
|
||||
{
|
||||
@@ -1,11 +1,9 @@
|
||||
using FileLiberator;
|
||||
using LibationFileManager;
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public partial class ImageDisplay : Form
|
||||
{
|
||||
28
Source/LibationWinForms/GridView/LiberateButtonStatus.cs
Normal file
28
Source/LibationWinForms/GridView/LiberateButtonStatus.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class LiberateButtonStatus : IComparable
|
||||
{
|
||||
public LiberatedStatus BookStatus { get; set; }
|
||||
public LiberatedStatus? PdfStatus { get; set; }
|
||||
public bool Expanded { get; set; }
|
||||
public bool IsSeries { get; init; }
|
||||
|
||||
/// <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,10 +1,10 @@
|
||||
using System;
|
||||
using DataLayer;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
using DataLayer;
|
||||
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class LiberateDataGridViewImageButtonColumn : DataGridViewButtonColumn
|
||||
{
|
||||
@@ -16,19 +16,35 @@ namespace LibationWinForms
|
||||
|
||||
internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell
|
||||
{
|
||||
private static readonly Color SERIES_BG_COLOR = Color.FromArgb(230, 255, 230);
|
||||
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
|
||||
{
|
||||
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, null, null, null, cellStyle, advancedBorderStyle, paintParts);
|
||||
|
||||
if (value is (LiberatedStatus, LiberatedStatus) or (LiberatedStatus, null))
|
||||
if (value is LiberateButtonStatus status)
|
||||
{
|
||||
var (bookState, pdfState) = ((LiberatedStatus bookState, LiberatedStatus? pdfState))value;
|
||||
if (rowIndex >= 0 && DataGridView.GetBoundItem<GridEntry>(rowIndex) is LibraryBookEntry lbEntry && lbEntry.Parent is not null)
|
||||
{
|
||||
DataGridView.Rows[rowIndex].DefaultCellStyle.BackColor = SERIES_BG_COLOR;
|
||||
}
|
||||
|
||||
(string mouseoverText, Bitmap buttonImage) = GetLiberateDisplay(bookState, pdfState);
|
||||
if (status.IsSeries)
|
||||
{
|
||||
var imageName = status.Expanded ? "minus" : "plus";
|
||||
|
||||
DrawButtonImage(graphics, buttonImage, cellBounds);
|
||||
var bmp = (Bitmap)Properties.Resources.ResourceManager.GetObject(imageName);
|
||||
DrawButtonImage(graphics, bmp, cellBounds);
|
||||
|
||||
ToolTipText = mouseoverText;
|
||||
ToolTipText = status.Expanded ? "Click to Collpase" : "Click to Expand";
|
||||
}
|
||||
else
|
||||
{
|
||||
(string mouseoverText, Bitmap buttonImage) = GetLiberateDisplay(status.BookStatus, status.PdfStatus);
|
||||
|
||||
DrawButtonImage(graphics, buttonImage, cellBounds);
|
||||
|
||||
ToolTipText = mouseoverText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using ApplicationServices;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using System;
|
||||
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
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
/// <summary>
|
||||
/// The View Model for a LibraryBook
|
||||
/// </summary>
|
||||
internal class GridEntry : AsyncNotifyPropertyChanged, IMemberComparable
|
||||
public class LibraryBookEntry : GridEntry
|
||||
{
|
||||
#region implementation properties NOT exposed to the view
|
||||
// hide from public fields from Data Source GUI with [Browsable(false)]
|
||||
@@ -30,37 +24,30 @@ namespace LibationWinForms
|
||||
public string LongDescription { get; private set; }
|
||||
#endregion
|
||||
|
||||
protected override Book Book => LibraryBook.Book;
|
||||
#region Model properties exposed to the view
|
||||
private Image _cover;
|
||||
|
||||
private DateTime lastStatusUpdate = default;
|
||||
private LiberatedStatus _bookStatus;
|
||||
private LiberatedStatus? _pdfStatus;
|
||||
public Image Cover
|
||||
{
|
||||
get => _cover;
|
||||
private set
|
||||
{
|
||||
_cover = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string ProductRating { get; private set; }
|
||||
public string PurchaseDate { get; private set; }
|
||||
public string MyRating { get; private set; }
|
||||
public string Series { get; private set; }
|
||||
public string Title { get; private set; }
|
||||
public string Length { get; private set; }
|
||||
public string Authors { get; private set; }
|
||||
public string Narrators { get; private set; }
|
||||
public string Category { get; private set; }
|
||||
public string Misc { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
public string DisplayTags => string.Join("\r\n", Book.UserDefinedItem.TagsEnumerated);
|
||||
public override DateTime DateAdded => LibraryBook.DateAdded;
|
||||
public override float SeriesIndex => Book.SeriesLink.FirstOrDefault()?.Index ?? 0;
|
||||
public override string ProductRating { get; protected set; }
|
||||
public override string PurchaseDate { get; protected set; }
|
||||
public override string MyRating { get; protected set; }
|
||||
public override string Series { get; protected set; }
|
||||
public override string Title { get; protected set; }
|
||||
public override string Length { get; protected set; }
|
||||
public override string Authors { get; protected set; }
|
||||
public override string Narrators { get; protected set; }
|
||||
public override string Category { get; protected set; }
|
||||
public override string Misc { get; protected set; }
|
||||
public override string Description { get; protected set; }
|
||||
public override string DisplayTags => string.Join("\r\n", Book.UserDefinedItem.TagsEnumerated);
|
||||
|
||||
// these 2 values being in 1 field is the trick behind getting the liberated+pdf 'stoplight' icon to draw. See: LiberateDataGridViewImageButtonCell.Paint
|
||||
public (LiberatedStatus BookStatus, LiberatedStatus? PdfStatus) Liberate
|
||||
public override LiberateButtonStatus Liberate
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -71,16 +58,14 @@ namespace LibationWinForms
|
||||
_pdfStatus = LibraryCommands.Pdf_Status(LibraryBook.Book);
|
||||
lastStatusUpdate = DateTime.Now;
|
||||
}
|
||||
return (_bookStatus, _pdfStatus);
|
||||
return new LiberateButtonStatus { BookStatus = _bookStatus, PdfStatus = _pdfStatus, IsSeries = false };
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// alias
|
||||
private Book Book => LibraryBook.Book;
|
||||
|
||||
public GridEntry(LibraryBook libraryBook) => setLibraryBook(libraryBook);
|
||||
public LibraryBookEntry(LibraryBook libraryBook) => setLibraryBook(libraryBook);
|
||||
|
||||
public SeriesEntry Parent { get; init; }
|
||||
public void UpdateLibraryBook(LibraryBook libraryBook)
|
||||
{
|
||||
if (AudibleProductId != libraryBook.Book.AudibleProductId)
|
||||
@@ -93,19 +78,9 @@ namespace LibationWinForms
|
||||
|
||||
private void setLibraryBook(LibraryBook libraryBook)
|
||||
{
|
||||
LibraryBook = libraryBook;
|
||||
_memberValues = CreateMemberValueDictionary();
|
||||
LibraryBook = libraryBook;
|
||||
|
||||
// Get cover art. If it's default, subscribe to PictureCached
|
||||
{
|
||||
(bool isDefault, byte[] picture) = PictureStorage.GetPicture(new PictureDefinition(Book.PictureId, PictureSize._80x80));
|
||||
|
||||
if (isDefault)
|
||||
PictureStorage.PictureCached += PictureStorage_PictureCached;
|
||||
|
||||
// Mutable property. Set the field so PropertyChanged isn't fired.
|
||||
_cover = ImageReader.ToImage(picture);
|
||||
}
|
||||
LoadCover();
|
||||
|
||||
// Immutable properties
|
||||
{
|
||||
@@ -126,14 +101,6 @@ namespace LibationWinForms
|
||||
UserDefinedItem.ItemChanged += UserDefinedItem_ItemChanged;
|
||||
}
|
||||
|
||||
private void PictureStorage_PictureCached(object sender, PictureCachedEventArgs e)
|
||||
{
|
||||
if (e.Definition.PictureId == Book.PictureId)
|
||||
{
|
||||
Cover = ImageReader.ToImage(e.Picture);
|
||||
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
||||
}
|
||||
}
|
||||
|
||||
#region detect changes to the model, update the view, and save to database.
|
||||
|
||||
@@ -152,16 +119,19 @@ namespace LibationWinForms
|
||||
{
|
||||
case nameof(udi.Tags):
|
||||
Book.UserDefinedItem.Tags = udi.Tags;
|
||||
SearchEngineCommands.UpdateBookTags(Book);
|
||||
NotifyPropertyChanged(nameof(DisplayTags));
|
||||
break;
|
||||
case nameof(udi.BookStatus):
|
||||
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
||||
_bookStatus = udi.BookStatus;
|
||||
SearchEngineCommands.UpdateLiberatedStatus(Book);
|
||||
NotifyPropertyChanged(nameof(Liberate));
|
||||
break;
|
||||
case nameof(udi.PdfStatus):
|
||||
Book.UserDefinedItem.PdfStatus = udi.PdfStatus;
|
||||
_pdfStatus = udi.PdfStatus;
|
||||
SearchEngineCommands.UpdateLiberatedStatus(Book);
|
||||
NotifyPropertyChanged(nameof(Liberate));
|
||||
break;
|
||||
}
|
||||
@@ -190,17 +160,9 @@ namespace LibationWinForms
|
||||
#endregion
|
||||
|
||||
#region Data Sorting
|
||||
// These methods are implementation of Dinah.Core.DataBinding.IMemberComparable
|
||||
// Used by Dinah.Core.DataBinding.SortableBindingList<T> for all sorting
|
||||
public virtual object GetMemberValue(string memberName) => _memberValues[memberName]();
|
||||
public virtual IComparer GetMemberComparer(Type memberType) => _memberTypeComparers[memberType];
|
||||
|
||||
private Dictionary<string, Func<object>> _memberValues { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create getters for all member object values by name
|
||||
/// </summary>
|
||||
private Dictionary<string, Func<object>> CreateMemberValueDictionary() => new()
|
||||
/// <summary>Create getters for all member object values by name </summary>
|
||||
protected override Dictionary<string, Func<object>> CreateMemberValueDictionary() => new()
|
||||
{
|
||||
{ nameof(Title), () => Book.TitleSortable() },
|
||||
{ nameof(Series), () => Book.SeriesSortable() },
|
||||
@@ -214,25 +176,17 @@ namespace LibationWinForms
|
||||
{ nameof(Category), () => Category },
|
||||
{ nameof(Misc), () => Misc },
|
||||
{ nameof(DisplayTags), () => DisplayTags },
|
||||
{ nameof(Liberate), () => Liberate.BookStatus }
|
||||
{ nameof(Liberate), () => Liberate },
|
||||
{ nameof(DateAdded), () => DateAdded },
|
||||
};
|
||||
|
||||
// Instantiate comparers for every exposed member object type.
|
||||
private static readonly Dictionary<Type, IComparer> _memberTypeComparers = new()
|
||||
{
|
||||
{ typeof(string), new ObjectComparer<string>() },
|
||||
{ typeof(int), new ObjectComparer<int>() },
|
||||
{ typeof(float), new ObjectComparer<float>() },
|
||||
{ typeof(DateTime), new ObjectComparer<DateTime>() },
|
||||
{ typeof(LiberatedStatus), new ObjectComparer<LiberatedStatus>() },
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static library display functions
|
||||
|
||||
/// <summary>
|
||||
/// This information should not change during <see cref="GridEntry"/> lifetime, so call only once.
|
||||
/// This information should not change during <see cref="LibraryBookEntry"/> lifetime, so call only once.
|
||||
/// </summary>
|
||||
private static string GetDescriptionDisplay(Book book)
|
||||
{
|
||||
@@ -250,7 +204,7 @@ namespace LibationWinForms
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This information should not change during <see cref="GridEntry"/> lifetime, so call only once.
|
||||
/// This information should not change during <see cref="LibraryBookEntry"/> lifetime, so call only once.
|
||||
/// Maximum of 5 text rows will fit in 80-pixel row height.
|
||||
/// </summary>
|
||||
private static string GetMiscDisplay(LibraryBook libraryBook)
|
||||
@@ -280,10 +234,9 @@ namespace LibationWinForms
|
||||
|
||||
#endregion
|
||||
|
||||
~GridEntry()
|
||||
~LibraryBookEntry()
|
||||
{
|
||||
UserDefinedItem.ItemChanged -= UserDefinedItem_ItemChanged;
|
||||
PictureStorage.PictureCached -= PictureStorage_PictureCached;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Source/LibationWinForms/GridView/ProductsDisplay.Designer.cs
generated
Normal file
64
Source/LibationWinForms/GridView/ProductsDisplay.Designer.cs
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
partial class ProductsDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.productsGrid = new LibationWinForms.GridView.ProductsGrid();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// productsGrid
|
||||
//
|
||||
this.productsGrid.AutoScroll = true;
|
||||
this.productsGrid.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.productsGrid.Location = new System.Drawing.Point(0, 0);
|
||||
this.productsGrid.Name = "productsGrid";
|
||||
this.productsGrid.Size = new System.Drawing.Size(1510, 380);
|
||||
this.productsGrid.TabIndex = 0;
|
||||
this.productsGrid.LiberateClicked += new LibationWinForms.GridView.ProductsGrid.LibraryBookEntryClickedEventHandler(this.productsGrid_LiberateClicked);
|
||||
this.productsGrid.CoverClicked += new LibationWinForms.GridView.ProductsGrid.LibraryBookEntryClickedEventHandler(this.productsGrid_CoverClicked);
|
||||
this.productsGrid.DetailsClicked += new LibationWinForms.GridView.ProductsGrid.LibraryBookEntryClickedEventHandler(this.productsGrid_DetailsClicked);
|
||||
this.productsGrid.DescriptionClicked += new LibationWinForms.GridView.ProductsGrid.LibraryBookEntryRectangleClickedEventHandler(this.productsGrid_DescriptionClicked);
|
||||
this.productsGrid.VisibleCountChanged += new System.EventHandler<int>(this.productsGrid_VisibleCountChanged);
|
||||
//
|
||||
// ProductsDisplay
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.productsGrid);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "ProductsDisplay";
|
||||
this.Size = new System.Drawing.Size(1510, 380);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private GridView.ProductsGrid productsGrid;
|
||||
}
|
||||
}
|
||||
123
Source/LibationWinForms/GridView/ProductsDisplay.cs
Normal file
123
Source/LibationWinForms/GridView/ProductsDisplay.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using ApplicationServices;
|
||||
using DataLayer;
|
||||
using FileLiberator;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public partial class ProductsDisplay : UserControl
|
||||
{
|
||||
/// <summary>Number of visible rows has changed</summary>
|
||||
public event EventHandler<int> VisibleCountChanged;
|
||||
public event EventHandler<LibraryBook> LiberateClicked;
|
||||
public event EventHandler InitialLoaded;
|
||||
|
||||
private bool hasBeenDisplayed;
|
||||
|
||||
public ProductsDisplay()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#region Button controls
|
||||
|
||||
private ImageDisplay imageDisplay;
|
||||
private async void productsGrid_CoverClicked(LibraryBookEntry liveGridEntry)
|
||||
{
|
||||
var picDefinition = new PictureDefinition(liveGridEntry.LibraryBook.Book.PictureLarge ?? liveGridEntry.LibraryBook.Book.PictureId, PictureSize.Native);
|
||||
var picDlTask = Task.Run(() => PictureStorage.GetPictureSynchronously(picDefinition));
|
||||
|
||||
(_, byte[] initialImageBts) = PictureStorage.GetPicture(new PictureDefinition(liveGridEntry.LibraryBook.Book.PictureId, PictureSize._80x80));
|
||||
var windowTitle = $"{liveGridEntry.Title} - Cover";
|
||||
|
||||
if (imageDisplay is null || imageDisplay.IsDisposed || !imageDisplay.Visible)
|
||||
{
|
||||
imageDisplay = new ImageDisplay();
|
||||
imageDisplay.RestoreSizeAndLocation(Configuration.Instance);
|
||||
imageDisplay.FormClosed += (_, _) => imageDisplay.SaveSizeAndLocation(Configuration.Instance);
|
||||
imageDisplay.Show(this);
|
||||
}
|
||||
|
||||
imageDisplay.BookSaveDirectory = AudibleFileStorage.Audio.GetDestinationDirectory(liveGridEntry.LibraryBook);
|
||||
imageDisplay.PictureFileName = System.IO.Path.GetFileName(AudibleFileStorage.Audio.GetBooksDirectoryFilename(liveGridEntry.LibraryBook, ".jpg"));
|
||||
imageDisplay.Text = windowTitle;
|
||||
imageDisplay.CoverPicture = initialImageBts;
|
||||
imageDisplay.CoverPicture = await picDlTask;
|
||||
}
|
||||
|
||||
private void productsGrid_DescriptionClicked(LibraryBookEntry liveGridEntry, Rectangle cellRectangle)
|
||||
{
|
||||
var displayWindow = new DescriptionDisplay
|
||||
{
|
||||
SpawnLocation = PointToScreen(cellRectangle.Location + new Size(cellRectangle.Width, 0)),
|
||||
DescriptionText = liveGridEntry.LongDescription,
|
||||
BorderThickness = 2,
|
||||
};
|
||||
|
||||
void CloseWindow(object o, EventArgs e)
|
||||
{
|
||||
displayWindow.Close();
|
||||
}
|
||||
|
||||
productsGrid.Scroll += CloseWindow;
|
||||
displayWindow.FormClosed += (_, _) => productsGrid.Scroll -= CloseWindow;
|
||||
displayWindow.Show(this);
|
||||
}
|
||||
|
||||
private void productsGrid_DetailsClicked(LibraryBookEntry liveGridEntry)
|
||||
{
|
||||
var bookDetailsForm = new BookDetailsDialog(liveGridEntry.LibraryBook);
|
||||
if (bookDetailsForm.ShowDialog() == DialogResult.OK)
|
||||
liveGridEntry.Commit(bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI display functions
|
||||
|
||||
public void Display()
|
||||
{
|
||||
// don't return early if lib size == 0. this will not update correctly if all books are removed
|
||||
var lib = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (!hasBeenDisplayed)
|
||||
{
|
||||
// bind
|
||||
productsGrid.BindToGrid(lib);
|
||||
hasBeenDisplayed = true;
|
||||
InitialLoaded?.Invoke(this, new());
|
||||
}
|
||||
else
|
||||
productsGrid.UpdateGrid(lib);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filter
|
||||
|
||||
public void Filter(string searchString)
|
||||
=> productsGrid.Filter(searchString);
|
||||
|
||||
#endregion
|
||||
|
||||
internal List<LibraryBook> GetVisible() => productsGrid.GetVisible().Select(v => v.LibraryBook).ToList();
|
||||
|
||||
private void productsGrid_VisibleCountChanged(object sender, int count)
|
||||
{
|
||||
VisibleCountChanged?.Invoke(this, count);
|
||||
}
|
||||
|
||||
private void productsGrid_LiberateClicked(LibraryBookEntry liveGridEntry)
|
||||
{
|
||||
LiberateClicked?.Invoke(this, liveGridEntry.LibraryBook);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -58,4 +57,7 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>81</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace LibationWinForms
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
partial class ProductsGrid
|
||||
{
|
||||
@@ -29,10 +29,9 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.gridEntryBindingSource = new LibationWinForms.SyncBindingSource(this.components);
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.gridEntryDataGridView = new System.Windows.Forms.DataGridView();
|
||||
this.liberateGVColumn = new LibationWinForms.LiberateDataGridViewImageButtonColumn();
|
||||
this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn();
|
||||
this.coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn();
|
||||
this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
@@ -45,16 +44,13 @@
|
||||
this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.myRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.tagAndDetailsGVColumn = new LibationWinForms.EditTagsDataGridViewImageButtonColumn();
|
||||
this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn();
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryBindingSource)).BeginInit();
|
||||
this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// gridEntryBindingSource
|
||||
//
|
||||
this.gridEntryBindingSource.DataSource = typeof(LibationWinForms.GridEntry);
|
||||
//
|
||||
// gridEntryDataGridView
|
||||
//
|
||||
this.gridEntryDataGridView.AllowUserToAddRows = false;
|
||||
@@ -64,42 +60,40 @@
|
||||
this.gridEntryDataGridView.AutoGenerateColumns = false;
|
||||
this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.liberateGVColumn,
|
||||
this.coverGVColumn,
|
||||
this.titleGVColumn,
|
||||
this.authorsGVColumn,
|
||||
this.narratorsGVColumn,
|
||||
this.lengthGVColumn,
|
||||
this.seriesGVColumn,
|
||||
this.descriptionGVColumn,
|
||||
this.categoryGVColumn,
|
||||
this.productRatingGVColumn,
|
||||
this.purchaseDateGVColumn,
|
||||
this.myRatingGVColumn,
|
||||
this.miscGVColumn,
|
||||
this.tagAndDetailsGVColumn});
|
||||
this.liberateGVColumn,
|
||||
this.coverGVColumn,
|
||||
this.titleGVColumn,
|
||||
this.authorsGVColumn,
|
||||
this.narratorsGVColumn,
|
||||
this.lengthGVColumn,
|
||||
this.seriesGVColumn,
|
||||
this.descriptionGVColumn,
|
||||
this.categoryGVColumn,
|
||||
this.productRatingGVColumn,
|
||||
this.purchaseDateGVColumn,
|
||||
this.myRatingGVColumn,
|
||||
this.miscGVColumn,
|
||||
this.tagAndDetailsGVColumn});
|
||||
this.gridEntryDataGridView.ContextMenuStrip = this.contextMenuStrip1;
|
||||
this.gridEntryDataGridView.DataSource = this.gridEntryBindingSource;
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1;
|
||||
this.gridEntryDataGridView.DataSource = this.syncBindingSource;
|
||||
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle2.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle2;
|
||||
this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0);
|
||||
this.gridEntryDataGridView.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.gridEntryDataGridView.Name = "gridEntryDataGridView";
|
||||
this.gridEntryDataGridView.ReadOnly = true;
|
||||
this.gridEntryDataGridView.RowHeadersVisible = false;
|
||||
this.gridEntryDataGridView.RowTemplate.Height = 82;
|
||||
this.gridEntryDataGridView.Size = new System.Drawing.Size(1510, 380);
|
||||
this.gridEntryDataGridView.TabIndex = 0;
|
||||
this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick);
|
||||
this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded);
|
||||
this.gridEntryDataGridView.ColumnDisplayIndexChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridEntryDataGridView_ColumnDisplayIndexChanged);
|
||||
this.gridEntryDataGridView.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridEntryDataGridView_ColumnWidthChanged);
|
||||
//
|
||||
// liberateGVColumn
|
||||
//
|
||||
@@ -218,23 +212,27 @@
|
||||
this.contextMenuStrip1.Name = "contextMenuStrip1";
|
||||
this.contextMenuStrip1.Size = new System.Drawing.Size(61, 4);
|
||||
//
|
||||
// syncBindingSource
|
||||
//
|
||||
this.syncBindingSource.DataSource = typeof(LibationWinForms.GridView.GridEntry);
|
||||
//
|
||||
// ProductsGrid
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScroll = true;
|
||||
this.Controls.Add(this.gridEntryDataGridView);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "ProductsGrid";
|
||||
this.Size = new System.Drawing.Size(1510, 380);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryBindingSource)).EndInit();
|
||||
this.Load += new System.EventHandler(this.ProductsGrid_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private LibationWinForms.SyncBindingSource gridEntryBindingSource;
|
||||
#endregion
|
||||
private System.Windows.Forms.DataGridView gridEntryDataGridView;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||
private LiberateDataGridViewImageButtonColumn liberateGVColumn;
|
||||
@@ -251,5 +249,6 @@
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn myRatingGVColumn;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn;
|
||||
private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn;
|
||||
private SyncBindingSource syncBindingSource;
|
||||
}
|
||||
}
|
||||
319
Source/LibationWinForms/GridView/ProductsGrid.cs
Normal file
319
Source/LibationWinForms/GridView/ProductsGrid.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
using DataLayer;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using LibationFileManager;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public partial class ProductsGrid : UserControl
|
||||
{
|
||||
public delegate void LibraryBookEntryClickedEventHandler(LibraryBookEntry liveGridEntry);
|
||||
public delegate void LibraryBookEntryRectangleClickedEventHandler(LibraryBookEntry liveGridEntry, Rectangle cellRectangle);
|
||||
|
||||
/// <summary>Number of visible rows has changed</summary>
|
||||
public event EventHandler<int> VisibleCountChanged;
|
||||
public event LibraryBookEntryClickedEventHandler LiberateClicked;
|
||||
public event LibraryBookEntryClickedEventHandler CoverClicked;
|
||||
public event LibraryBookEntryClickedEventHandler DetailsClicked;
|
||||
public event LibraryBookEntryRectangleClickedEventHandler DescriptionClicked;
|
||||
public new event EventHandler<ScrollEventArgs> Scroll;
|
||||
|
||||
private GridEntryBindingList bindingList;
|
||||
internal IEnumerable<LibraryBookEntry> GetVisible()
|
||||
=> bindingList
|
||||
.LibraryBooks();
|
||||
|
||||
public ProductsGrid()
|
||||
{
|
||||
InitializeComponent();
|
||||
EnableDoubleBuffering();
|
||||
gridEntryDataGridView.Scroll += (_, s) => Scroll?.Invoke(this, s);
|
||||
}
|
||||
|
||||
private void EnableDoubleBuffering()
|
||||
{
|
||||
var propertyInfo = gridEntryDataGridView.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
|
||||
propertyInfo.SetValue(gridEntryDataGridView, true, null);
|
||||
}
|
||||
|
||||
#region Button controls
|
||||
private void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
// handle grid button click: https://stackoverflow.com/a/13687844
|
||||
if (e.RowIndex < 0)
|
||||
return;
|
||||
|
||||
var entry = getGridEntry(e.RowIndex);
|
||||
if (entry is LibraryBookEntry lbEntry)
|
||||
{
|
||||
if (e.ColumnIndex == liberateGVColumn.Index)
|
||||
LiberateClicked?.Invoke(lbEntry);
|
||||
else if (e.ColumnIndex == tagAndDetailsGVColumn.Index)
|
||||
DetailsClicked?.Invoke(lbEntry);
|
||||
else if (e.ColumnIndex == descriptionGVColumn.Index)
|
||||
DescriptionClicked?.Invoke(lbEntry, gridEntryDataGridView.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false));
|
||||
else if (e.ColumnIndex == coverGVColumn.Index)
|
||||
CoverClicked?.Invoke(lbEntry);
|
||||
}
|
||||
else if (entry is SeriesEntry sEntry && e.ColumnIndex == liberateGVColumn.Index)
|
||||
{
|
||||
if (sEntry.Liberate.Expanded)
|
||||
bindingList.CollapseItem(sEntry);
|
||||
else
|
||||
bindingList.ExpandItem(sEntry);
|
||||
|
||||
sEntry.NotifyPropertyChanged(nameof(sEntry.Liberate));
|
||||
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
}
|
||||
}
|
||||
|
||||
private GridEntry getGridEntry(int rowIndex) => gridEntryDataGridView.GetBoundItem<GridEntry>(rowIndex);
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI display functions
|
||||
|
||||
internal void BindToGrid(List<LibraryBook> dbBooks)
|
||||
{
|
||||
var geList = dbBooks.Where(b => b.Book.ContentType is not ContentType.Episode).Select(b => new LibraryBookEntry(b)).Cast<GridEntry>().ToList();
|
||||
|
||||
var episodes = dbBooks.Where(b => b.Book.ContentType is ContentType.Episode).ToList();
|
||||
|
||||
foreach (var series in episodes.Select(lb => lb.Book.SeriesLink.First()).DistinctBy(s => s.Series))
|
||||
{
|
||||
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 GridEntryBindingList(geList.OrderByDescending(e => e.DateAdded));
|
||||
bindingList.CollapseAll();
|
||||
syncBindingSource.DataSource = bindingList;
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
}
|
||||
|
||||
internal void UpdateGrid(List<LibraryBook> dbBooks)
|
||||
{
|
||||
string existingFilter = syncBindingSource.Filter;
|
||||
Filter(null);
|
||||
|
||||
//Add absent books to grid, or update current books
|
||||
|
||||
var allItmes = bindingList.AllItems().LibraryBooks();
|
||||
foreach (var libraryBook in dbBooks)
|
||||
{
|
||||
var existingItem = allItmes.FindBookByAsin(libraryBook.Book.AudibleProductId);
|
||||
|
||||
// add new to top
|
||||
if (existingItem is null)
|
||||
{
|
||||
if (libraryBook.Book.ContentType is ContentType.Episode)
|
||||
{
|
||||
LibraryBookEntry lbe;
|
||||
//Find the series that libraryBook belongs to, if it exists
|
||||
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(libraryBook.Book.SeriesLink.First(), libraryBook);
|
||||
lbe = newSeries.Children[0];
|
||||
newSeries.Liberate.Expanded = true;
|
||||
bindingList.Insert(0, newSeries);
|
||||
series = newSeries;
|
||||
}
|
||||
else
|
||||
{
|
||||
lbe = new(libraryBook) { Parent = series };
|
||||
series.Children.Add(lbe);
|
||||
}
|
||||
//Add episode beneath the parent
|
||||
int seriesIndex = bindingList.IndexOf(series);
|
||||
bindingList.Insert(seriesIndex + 1, lbe);
|
||||
|
||||
if (series.Liberate.Expanded)
|
||||
bindingList.ExpandItem(series);
|
||||
else
|
||||
bindingList.CollapseItem(series);
|
||||
|
||||
series.NotifyPropertyChanged();
|
||||
}
|
||||
else
|
||||
//Add the new product
|
||||
bindingList.Insert(0, new LibraryBookEntry(libraryBook));
|
||||
}
|
||||
// update existing
|
||||
else
|
||||
{
|
||||
existingItem.UpdateLibraryBook(libraryBook);
|
||||
}
|
||||
}
|
||||
|
||||
//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 =
|
||||
bindingList
|
||||
.AllItems()
|
||||
.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))
|
||||
{
|
||||
removed.Parent.Children.Remove(removed);
|
||||
removed.Parent.NotifyPropertyChanged();
|
||||
}
|
||||
|
||||
//Remove series that have no children
|
||||
var removedSeries =
|
||||
bindingList
|
||||
.AllItems()
|
||||
.EmptySeries();
|
||||
|
||||
foreach (var removed in removedBooks.Cast<GridEntry>().Concat(removedSeries))
|
||||
//no need to re-filter for removed books
|
||||
bindingList.Remove(removed);
|
||||
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filter
|
||||
|
||||
public void Filter(string searchString)
|
||||
{
|
||||
int visibleCount = bindingList.Count;
|
||||
|
||||
if (string.IsNullOrEmpty(searchString))
|
||||
syncBindingSource.RemoveFilter();
|
||||
else
|
||||
syncBindingSource.Filter = searchString;
|
||||
|
||||
if (visibleCount != bindingList.Count)
|
||||
VisibleCountChanged?.Invoke(this, bindingList.LibraryBooks().Count());
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Column Customizations
|
||||
|
||||
private void ProductsGrid_Load(object sender, EventArgs e)
|
||||
{
|
||||
//https://stackoverflow.com/a/4498512/3335599
|
||||
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime) return;
|
||||
|
||||
gridEntryDataGridView.ColumnWidthChanged += gridEntryDataGridView_ColumnWidthChanged;
|
||||
gridEntryDataGridView.ColumnDisplayIndexChanged += gridEntryDataGridView_ColumnDisplayIndexChanged;
|
||||
|
||||
contextMenuStrip1.Items.Add(new ToolStripLabel("Show / Hide Columns"));
|
||||
contextMenuStrip1.Items.Add(new ToolStripSeparator());
|
||||
|
||||
//Restore Grid Display Settings
|
||||
var config = Configuration.Instance;
|
||||
var gridColumnsVisibilities = config.GridColumnsVisibilities;
|
||||
var gridColumnsWidths = config.GridColumnsWidths;
|
||||
var displayIndices = config.GridColumnsDisplayIndices;
|
||||
|
||||
var cmsKiller = new ContextMenuStrip();
|
||||
|
||||
foreach (DataGridViewColumn column in gridEntryDataGridView.Columns)
|
||||
{
|
||||
var itemName = column.DataPropertyName;
|
||||
var visible = gridColumnsVisibilities.GetValueOrDefault(itemName, true);
|
||||
|
||||
var menuItem = new ToolStripMenuItem()
|
||||
{
|
||||
Text = column.HeaderText,
|
||||
Checked = visible,
|
||||
Tag = itemName
|
||||
};
|
||||
menuItem.Click += HideMenuItem_Click;
|
||||
contextMenuStrip1.Items.Add(menuItem);
|
||||
|
||||
column.Width = gridColumnsWidths.GetValueOrDefault(itemName, column.Width);
|
||||
column.MinimumWidth = 10;
|
||||
column.HeaderCell.ContextMenuStrip = contextMenuStrip1;
|
||||
column.Visible = visible;
|
||||
|
||||
//Setting a default ContextMenuStrip will allow the columns to handle the
|
||||
//Show() event so it is not passed up to the _dataGridView.ContextMenuStrip.
|
||||
//This allows the ContextMenuStrip to be shown if right-clicking in the gray
|
||||
//background of _dataGridView but not shown if right-clicking inside cells.
|
||||
column.ContextMenuStrip = cmsKiller;
|
||||
}
|
||||
|
||||
//We must set DisplayIndex properties in ascending order
|
||||
foreach (var itemName in displayIndices.OrderBy(i => i.Value).Select(i => i.Key))
|
||||
{
|
||||
var column = gridEntryDataGridView.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.Single(c => c.DataPropertyName == itemName);
|
||||
|
||||
column.DisplayIndex = displayIndices.GetValueOrDefault(itemName, column.Index);
|
||||
}
|
||||
}
|
||||
|
||||
private void HideMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var menuItem = sender as ToolStripMenuItem;
|
||||
var propertyName = menuItem.Tag as string;
|
||||
|
||||
var column = gridEntryDataGridView.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.FirstOrDefault(c => c.DataPropertyName == propertyName);
|
||||
|
||||
if (column != null)
|
||||
{
|
||||
var visible = menuItem.Checked;
|
||||
menuItem.Checked = !visible;
|
||||
column.Visible = !visible;
|
||||
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsVisibilities;
|
||||
dictionary[propertyName] = column.Visible;
|
||||
config.GridColumnsVisibilities = dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
|
||||
{
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsDisplayIndices;
|
||||
dictionary[e.Column.DataPropertyName] = e.Column.DisplayIndex;
|
||||
config.GridColumnsDisplayIndices = dictionary;
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
|
||||
{
|
||||
if (e.ColumnIndex == descriptionGVColumn.Index)
|
||||
e.ToolTipText = "Click to see full description";
|
||||
else if (e.ColumnIndex == coverGVColumn.Index)
|
||||
e.ToolTipText = "Click to see full size";
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
|
||||
{
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsWidths;
|
||||
dictionary[e.Column.DataPropertyName] = e.Column.Width;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -57,13 +57,16 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="gridEntryBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>171, 17</value>
|
||||
</metadata>
|
||||
<metadata name="syncBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>197, 17</value>
|
||||
<metadata name="bindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>326, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>81</value>
|
||||
<metadata name="bindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>326, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
109
Source/LibationWinForms/GridView/SeriesEntry.cs
Normal file
109
Source/LibationWinForms/GridView/SeriesEntry.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class SeriesEntry : GridEntry
|
||||
{
|
||||
public List<LibraryBookEntry> Children { get; init; }
|
||||
public override DateTime DateAdded => Children.Max(c => c.DateAdded);
|
||||
public override float SeriesIndex { get; }
|
||||
public override string ProductRating
|
||||
{
|
||||
get
|
||||
{
|
||||
var productAverageRating = new Rating(Children.Average(c => c.LibraryBook.Book.Rating.OverallRating), Children.Average(c => c.LibraryBook.Book.Rating.PerformanceRating), Children.Average(c => c.LibraryBook.Book.Rating.StoryRating));
|
||||
return productAverageRating.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||
}
|
||||
protected set => throw new NotImplementedException();
|
||||
}
|
||||
public override string PurchaseDate { get; protected set; }
|
||||
public override string MyRating
|
||||
{
|
||||
get
|
||||
{
|
||||
var myAverageRating = new Rating(Children.Average(c => c.LibraryBook.Book.UserDefinedItem.Rating.OverallRating), Children.Average(c => c.LibraryBook.Book.UserDefinedItem.Rating.PerformanceRating), Children.Average(c => c.LibraryBook.Book.UserDefinedItem.Rating.StoryRating));
|
||||
return myAverageRating.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||
}
|
||||
protected set => throw new NotImplementedException();
|
||||
}
|
||||
public override string Series { get; protected set; }
|
||||
public override string Title { get; protected set; }
|
||||
public override string Length
|
||||
{
|
||||
get
|
||||
{
|
||||
int bookLenMins = Children.Sum(c => c.LibraryBook.Book.LengthInMinutes);
|
||||
return bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min";
|
||||
}
|
||||
protected set => throw new NotImplementedException();
|
||||
}
|
||||
public override string Authors { get; protected set; }
|
||||
public override string Narrators { get; protected set; }
|
||||
public override string Category { get; protected set; }
|
||||
public override string Misc { get; protected set; } = string.Empty;
|
||||
public override string Description { get; protected set; } = string.Empty;
|
||||
public override string DisplayTags { get; } = string.Empty;
|
||||
|
||||
public override LiberateButtonStatus Liberate { get; }
|
||||
|
||||
protected override Book Book => SeriesBook.Book;
|
||||
|
||||
private SeriesBook SeriesBook { get; set; }
|
||||
|
||||
private SeriesEntry(SeriesBook seriesBook)
|
||||
{
|
||||
Liberate = new LiberateButtonStatus { IsSeries = true };
|
||||
SeriesIndex = seriesBook.Index;
|
||||
}
|
||||
public SeriesEntry(SeriesBook seriesBook, IEnumerable<LibraryBook> children) : this(seriesBook)
|
||||
{
|
||||
Children = children.Select(c => new LibraryBookEntry(c) { Parent = this }).OrderBy(c => c.SeriesIndex).ToList();
|
||||
SetSeriesBook(seriesBook);
|
||||
}
|
||||
public SeriesEntry(SeriesBook seriesBook, LibraryBook child) : this(seriesBook)
|
||||
{
|
||||
Children = new() { new LibraryBookEntry(child) { Parent = this } };
|
||||
SetSeriesBook(seriesBook);
|
||||
}
|
||||
|
||||
private void SetSeriesBook(SeriesBook seriesBook)
|
||||
{
|
||||
SeriesBook = seriesBook;
|
||||
LoadCover();
|
||||
|
||||
// Immutable properties
|
||||
{
|
||||
Title = SeriesBook.Series.Name;
|
||||
Series = SeriesBook.Series.Name;
|
||||
PurchaseDate = Children.Min(c => c.LibraryBook.DateAdded).ToString("d");
|
||||
Authors = Book.AuthorNames();
|
||||
Narrators = Book.NarratorNames();
|
||||
Category = string.Join(" > ", Book.CategoriesNames());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Create getters for all member object values by name</summary>
|
||||
protected override Dictionary<string, Func<object>> CreateMemberValueDictionary() => new()
|
||||
{
|
||||
{ nameof(Title), () => Book.SeriesSortable() },
|
||||
{ nameof(Series), () => Book.SeriesSortable() },
|
||||
{ nameof(Length), () => Children.Sum(c => c.LibraryBook.Book.LengthInMinutes) },
|
||||
{ nameof(MyRating), () => Children.Average(c => c.LibraryBook.Book.UserDefinedItem.Rating.FirstScore()) },
|
||||
{ nameof(PurchaseDate), () => Children.Min(c => c.LibraryBook.DateAdded) },
|
||||
{ nameof(ProductRating), () => Children.Average(c => c.LibraryBook.Book.Rating.FirstScore()) },
|
||||
{ nameof(Authors), () => string.Empty },
|
||||
{ nameof(Narrators), () => string.Empty },
|
||||
{ nameof(Description), () => string.Empty },
|
||||
{ nameof(Category), () => string.Empty },
|
||||
{ nameof(Misc), () => string.Empty },
|
||||
{ nameof(DisplayTags), () => string.Empty },
|
||||
{ nameof(Liberate), () => Liberate },
|
||||
{ nameof(DateAdded), () => DateAdded },
|
||||
};
|
||||
}
|
||||
}
|
||||
29
Source/LibationWinForms/GridView/SyncBindingSource.cs
Normal file
29
Source/LibationWinForms/GridView/SyncBindingSource.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
// https://stackoverflow.com/a/32886415
|
||||
namespace LibationWinForms.GridView
|
||||
{
|
||||
public class SyncBindingSource : BindingSource
|
||||
{
|
||||
private SynchronizationContext syncContext { get; }
|
||||
|
||||
public SyncBindingSource() : base()
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
public SyncBindingSource(IContainer container) : base(container)
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
public SyncBindingSource(object dataSource, string dataMember) : base(dataSource, dataMember)
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
|
||||
public override bool SupportsFiltering => true;
|
||||
|
||||
protected override void OnListChanged(ListChangedEventArgs e)
|
||||
{
|
||||
if (syncContext is not null)
|
||||
syncContext.Send(_ => base.OnListChanged(e), null);
|
||||
else
|
||||
base.OnListChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.0" />
|
||||
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="4.2.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
namespace LibationWinForms.ProcessQueue
|
||||
{
|
||||
public interface ILogForm
|
||||
{
|
||||
59
Source/LibationWinForms/ProcessQueue/LogMe.cs
Normal file
59
Source/LibationWinForms/ProcessQueue/LogMe.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationWinForms.ProcessQueue
|
||||
{
|
||||
// decouple serilog and form. include convenience factory method
|
||||
public class LogMe
|
||||
{
|
||||
public event EventHandler<string> LogInfo;
|
||||
public event EventHandler<string> LogErrorString;
|
||||
public event EventHandler<(Exception, string)> LogError;
|
||||
|
||||
private LogMe()
|
||||
{
|
||||
LogInfo += (_, text) => Serilog.Log.Logger.Information($"Automated backup: {text}");
|
||||
LogErrorString += (_, text) => Serilog.Log.Logger.Error(text);
|
||||
LogError += (_, tuple) => Serilog.Log.Logger.Error(tuple.Item1, tuple.Item2 ?? "Automated backup: error");
|
||||
}
|
||||
private static ILogForm LogForm;
|
||||
public static LogMe RegisterForm<T>(T form) where T : ILogForm
|
||||
{
|
||||
var logMe = new LogMe();
|
||||
|
||||
if (form is null)
|
||||
return logMe;
|
||||
|
||||
LogForm = form;
|
||||
|
||||
logMe.LogInfo += LogMe_LogInfo;
|
||||
logMe.LogErrorString += LogMe_LogErrorString;
|
||||
logMe.LogError += LogMe_LogError;
|
||||
|
||||
return logMe;
|
||||
}
|
||||
|
||||
private static async void LogMe_LogError(object sender, (Exception, string) tuple)
|
||||
{
|
||||
await Task.Run(() => LogForm?.WriteLine(tuple.Item2 ?? "Automated backup: error"));
|
||||
await Task.Run(() => LogForm?.WriteLine("ERROR: " + tuple.Item1.Message));
|
||||
}
|
||||
|
||||
private static async void LogMe_LogErrorString(object sender, string text)
|
||||
{
|
||||
await Task.Run(() => LogForm?.WriteLine(text));
|
||||
}
|
||||
|
||||
private static async void LogMe_LogInfo(object sender, string text)
|
||||
{
|
||||
await Task.Run(() => LogForm?.WriteLine(text));
|
||||
}
|
||||
|
||||
public void Info(string text) => LogInfo?.Invoke(this, text);
|
||||
public void Error(string text) => LogErrorString?.Invoke(this, text);
|
||||
public void Error(Exception ex, string text = null) => LogError?.Invoke(this, (ex, text));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using Dinah.Core;
|
||||
using FileLiberator;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.BookLiberation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -132,7 +131,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
{
|
||||
ProcessBookResult.Success => ProcessBookStatus.Completed,
|
||||
ProcessBookResult.Cancelled => ProcessBookStatus.Cancelled,
|
||||
ProcessBookResult.FailedRetry => ProcessBookStatus.Queued,
|
||||
_ => ProcessBookStatus.Failed,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ namespace LibationWinForms.ProcessQueue
|
||||
Status = ProcessBookStatus.Cancelled;
|
||||
break;
|
||||
case ProcessBookResult.FailedRetry:
|
||||
statusText = "Queued";
|
||||
Status = ProcessBookStatus.Queued;
|
||||
statusText = "Error, will retry later";
|
||||
Status = ProcessBookStatus.Failed;
|
||||
break;
|
||||
case ProcessBookResult.FailedSkip:
|
||||
statusText = "Error, Skippping";
|
||||
|
||||
@@ -51,9 +51,9 @@
|
||||
this.logEntryColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.panel4 = new System.Windows.Forms.Panel();
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.logCopyBtn = new System.Windows.Forms.Button();
|
||||
this.clearLogBtn = new System.Windows.Forms.Button();
|
||||
this.counterTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.logCopyBtn = new System.Windows.Forms.Button();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
@@ -264,10 +264,21 @@
|
||||
this.panel2.Size = new System.Drawing.Size(390, 25);
|
||||
this.panel2.TabIndex = 1;
|
||||
//
|
||||
// logCopyBtn
|
||||
//
|
||||
this.logCopyBtn.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
this.logCopyBtn.Location = new System.Drawing.Point(0, 0);
|
||||
this.logCopyBtn.Name = "logCopyBtn";
|
||||
this.logCopyBtn.Size = new System.Drawing.Size(57, 23);
|
||||
this.logCopyBtn.TabIndex = 1;
|
||||
this.logCopyBtn.Text = "Copy";
|
||||
this.logCopyBtn.UseVisualStyleBackColor = true;
|
||||
this.logCopyBtn.Click += new System.EventHandler(this.LogCopyBtn_Click);
|
||||
//
|
||||
// clearLogBtn
|
||||
//
|
||||
this.clearLogBtn.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
this.clearLogBtn.Location = new System.Drawing.Point(0, 0);
|
||||
this.clearLogBtn.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.clearLogBtn.Location = new System.Drawing.Point(328, 0);
|
||||
this.clearLogBtn.Name = "clearLogBtn";
|
||||
this.clearLogBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.clearLogBtn.TabIndex = 0;
|
||||
@@ -280,17 +291,6 @@
|
||||
this.counterTimer.Interval = 950;
|
||||
this.counterTimer.Tick += new System.EventHandler(this.CounterTimer_Tick);
|
||||
//
|
||||
// logCopyBtn
|
||||
//
|
||||
this.logCopyBtn.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.logCopyBtn.Location = new System.Drawing.Point(331, 0);
|
||||
this.logCopyBtn.Name = "logCopyBtn";
|
||||
this.logCopyBtn.Size = new System.Drawing.Size(57, 23);
|
||||
this.logCopyBtn.TabIndex = 1;
|
||||
this.logCopyBtn.Text = "Copy";
|
||||
this.logCopyBtn.UseVisualStyleBackColor = true;
|
||||
this.logCopyBtn.Click += new System.EventHandler(this.LogCopyBtn_Click);
|
||||
//
|
||||
// ProcessQueueControl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using LibationWinForms.BookLiberation;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
@@ -47,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;
|
||||
@@ -145,12 +151,15 @@ namespace LibationWinForms.ProcessQueue
|
||||
|
||||
var result = await nextBook.ProcessOneAsync();
|
||||
|
||||
if (result == ProcessBookResult.FailedRetry)
|
||||
Queue.Enqueue(nextBook);
|
||||
else if (result == ProcessBookResult.ValidationFail)
|
||||
if (result == ProcessBookResult.ValidationFail)
|
||||
Queue.ClearCurrent();
|
||||
else if (result == ProcessBookResult.FailedAbort)
|
||||
return;
|
||||
Queue.ClearQueue();
|
||||
else if (result == ProcessBookResult.FailedSkip)
|
||||
{
|
||||
nextBook.LibraryBook.Book.UserDefinedItem.BookStatus = DataLayer.LiberatedStatus.Error;
|
||||
ApplicationServices.LibraryCommands.UpdateUserDefinedItem(nextBook.LibraryBook.Book);
|
||||
}
|
||||
}
|
||||
Queue_CompletedCountChanged(this, 0);
|
||||
counterTimer.Stop();
|
||||
@@ -163,14 +172,14 @@ namespace LibationWinForms.ProcessQueue
|
||||
if (IsDisposed) return;
|
||||
|
||||
var timeStamp = DateTime.Now;
|
||||
logDGV.Rows.Add(timeStamp, text.Trim());
|
||||
Invoke(() => logDGV.Rows.Add(timeStamp, text.Trim()));
|
||||
}
|
||||
|
||||
#region Control event handlers
|
||||
|
||||
private void Queue_CompletedCountChanged(object sender, int e)
|
||||
{
|
||||
int errCount = Queue.Completed.Count(p => p.Result is ProcessBookResult.FailedAbort or ProcessBookResult.FailedSkip or ProcessBookResult.ValidationFail);
|
||||
int errCount = Queue.Completed.Count(p => p.Result is ProcessBookResult.FailedAbort or ProcessBookResult.FailedSkip or ProcessBookResult.FailedRetry or ProcessBookResult.ValidationFail);
|
||||
int completeCount = Queue.Completed.Count(p => p.Result is ProcessBookResult.Success);
|
||||
|
||||
ErrorCount = errCount;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
@@ -39,12 +40,21 @@
|
||||
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(377, 505);
|
||||
this.panel1.Size = new System.Drawing.Size(357, 505);
|
||||
this.panel1.TabIndex = 0;
|
||||
//
|
||||
// vScrollBar1
|
||||
//
|
||||
this.vScrollBar1.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.vScrollBar1.Location = new System.Drawing.Point(360, 0);
|
||||
this.vScrollBar1.Name = "vScrollBar1";
|
||||
this.vScrollBar1.Size = new System.Drawing.Size(17, 505);
|
||||
this.vScrollBar1.TabIndex = 0;
|
||||
//
|
||||
// VirtualFlowControl
|
||||
//
|
||||
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.Controls.Add(this.vScrollBar1);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.Name = "VirtualFlowControl";
|
||||
this.Size = new System.Drawing.Size(377, 505);
|
||||
@@ -55,5 +65,6 @@
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.VScrollBar vScrollBar1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
/// </summary>
|
||||
private readonly int TopMargin;
|
||||
|
||||
private readonly VScrollBar vScrollBar1;
|
||||
private readonly List<ProcessBookControl> BookControls = new();
|
||||
|
||||
#endregion
|
||||
@@ -101,16 +100,6 @@ namespace LibationWinForms.ProcessQueue
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
vScrollBar1 = new VScrollBar
|
||||
{
|
||||
Minimum = 0,
|
||||
Value = 0,
|
||||
Dock = DockStyle.Right
|
||||
};
|
||||
Controls.Add(vScrollBar1);
|
||||
|
||||
vScrollBar1.Scroll += (_, s) => SetScrollPosition(s.NewValue);
|
||||
panel1.Width -= vScrollBar1.Width + panel1.Margin.Right;
|
||||
panel1.Resize += (_, _) =>
|
||||
{
|
||||
AdjustScrollBar();
|
||||
@@ -125,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);
|
||||
@@ -135,6 +121,7 @@ namespace LibationWinForms.ProcessQueue
|
||||
panel1.Controls.Add(control);
|
||||
}
|
||||
|
||||
vScrollBar1.Scroll += (_, s) => SetScrollPosition(s.NewValue);
|
||||
vScrollBar1.SmallChange = SmallScrollChange;
|
||||
panel1.Height += NUM_BLANK_SPACES_AT_BOTTOM * VirtualControlHeight;
|
||||
}
|
||||
@@ -227,6 +214,8 @@ namespace LibationWinForms.ProcessQueue
|
||||
/// </summary>
|
||||
private void SetScrollPosition(int value)
|
||||
{
|
||||
if (!vScrollBar1.Enabled) return;
|
||||
|
||||
int newPos = (int)Math.Round((double)value / SmallScrollChange) * SmallScrollChange;
|
||||
if (vScrollBar1.Value != newPos)
|
||||
{
|
||||
|
||||
@@ -3,14 +3,9 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using AudibleApi.Authorization;
|
||||
using AudibleUtilities;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.Dialogs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
|
||||
namespace LibationWinForms
|
||||
@@ -165,15 +160,12 @@ namespace LibationWinForms
|
||||
|
||||
private static void checkForUpdate()
|
||||
{
|
||||
string zipUrl;
|
||||
string htmlUrl;
|
||||
string zipName;
|
||||
AppScaffolding.UpgradeProperties upgradeProperties;
|
||||
|
||||
try
|
||||
{
|
||||
bool hasUpgrade;
|
||||
(hasUpgrade, zipUrl, htmlUrl, zipName) = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
||||
|
||||
if (!hasUpgrade)
|
||||
upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
||||
if (upgradeProperties is null)
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -182,29 +174,13 @@ namespace LibationWinForms
|
||||
return;
|
||||
}
|
||||
|
||||
if (zipUrl is null)
|
||||
if (upgradeProperties.ZipUrl is null)
|
||||
{
|
||||
MessageBox.Show(htmlUrl, "New version available");
|
||||
MessageBox.Show(upgradeProperties.HtmlUrl, "New version available");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageBox.Show($"New version available @ {htmlUrl}\r\nDownload the zip file?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (result != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
using var fileSelector = new SaveFileDialog { FileName = zipName, Filter = "Zip Files (*.zip)|*.zip|All files (*.*)|*.*" };
|
||||
if (fileSelector.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
var selectedPath = fileSelector.FileName;
|
||||
|
||||
BookLiberation.ProcessorAutomationController.DownloadFile(zipUrl, selectedPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
|
||||
}
|
||||
Updater.Run(upgradeProperties.LatestRelease, upgradeProperties.ZipUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
cause the file to be unrecognizable by the program.
|
||||
-->
|
||||
<GenericObjectDataSource DisplayName="GridEntry" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
|
||||
<TypeInfo>LibationWinForms.GridEntry, LibationWinForms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
<TypeInfo>LibationWinForms.GridView.GridEntry, LibationWinForms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
|
||||
</GenericObjectDataSource>
|
||||
@@ -229,5 +229,25 @@ namespace LibationWinForms.Properties {
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap minus {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("minus", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap plus {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("plus", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,4 +169,10 @@
|
||||
<data name="liberate_yellow_pdf_yes" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\liberate_yellow_pdf_yes.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="minus" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\minus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="plus" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\plus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
Source/LibationWinForms/Resources/minus.png
Normal file
BIN
Source/LibationWinForms/Resources/minus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 425 B |
BIN
Source/LibationWinForms/Resources/plus.png
Normal file
BIN
Source/LibationWinForms/Resources/plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 689 B |
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
// https://stackoverflow.com/a/32886415
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public class SyncBindingSource : BindingSource
|
||||
{
|
||||
private SynchronizationContext syncContext { get; }
|
||||
|
||||
public SyncBindingSource() : base()
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
public SyncBindingSource(IContainer container) : base(container)
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
public SyncBindingSource(object dataSource, string dataMember) : base(dataSource, dataMember)
|
||||
=> syncContext = SynchronizationContext.Current;
|
||||
|
||||
public override bool SupportsFiltering => true;
|
||||
|
||||
protected override void OnListChanged(ListChangedEventArgs e)
|
||||
{
|
||||
if (syncContext is not null)
|
||||
syncContext.Send(_ => base.OnListChanged(e), null);
|
||||
else
|
||||
base.OnListChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Source/LibationWinForms/Updater.cs
Normal file
50
Source/LibationWinForms/Updater.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using AutoUpdaterDotNET;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public static class Updater
|
||||
{
|
||||
private const string REPO_URL = "https://github.com/rmcrackan/Libation/releases/latest";
|
||||
|
||||
public static void Run(Version latestVersionOnServer, string downloadZipUrl)
|
||||
=> Run(latestVersionOnServer.ToString(), downloadZipUrl);
|
||||
public static void Run(string latestVersionOnServer, string downloadZipUrl)
|
||||
{
|
||||
AutoUpdater.ParseUpdateInfoEvent +=
|
||||
args => args.UpdateInfo = new()
|
||||
{
|
||||
CurrentVersion = latestVersionOnServer,
|
||||
DownloadURL = downloadZipUrl,
|
||||
ChangelogURL = REPO_URL
|
||||
};
|
||||
AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent;
|
||||
AutoUpdater.Start(REPO_URL);
|
||||
}
|
||||
|
||||
private static void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args)
|
||||
{
|
||||
if (args is null || !args.IsUpdateAvailable)
|
||||
return;
|
||||
|
||||
var dialogResult = MessageBox.Show(string.Format(
|
||||
$"There is a new version avilable. Would you like to update?\r\n\r\nAfter you close Libation, the upgrade will start automatically."),
|
||||
"Update Available",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Information);
|
||||
if (dialogResult != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Serilog.Log.Logger.Information("Start upgrade. {@DebugInfo}", new { CurrentlyInstalled = args.InstalledVersion, TargetVersion = args.CurrentVersion });
|
||||
AutoUpdater.DownloadUpdate(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using ApplicationServices;
|
||||
using Dinah.Core.DataBinding;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
/*
|
||||
* Allows filtering of the underlying SortableBindingList<GridEntry>
|
||||
* by implementing IBindingListView and using SearchEngineCommands
|
||||
*
|
||||
* When filtering is applied, the filtered-out items are removed
|
||||
* from the base list and added to the private FilterRemoved list.
|
||||
* When filtering is removed, items in the FilterRemoved list are
|
||||
* added back to the base list.
|
||||
*
|
||||
* 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 : SortableBindingList<GridEntry>, IBindingListView
|
||||
{
|
||||
/// <summary>
|
||||
/// Items that were removed from the base list due to filtering
|
||||
/// </summary>
|
||||
private readonly List<GridEntry> FilterRemoved = new();
|
||||
private string FilterString;
|
||||
public FilterableSortableBindingList(IEnumerable<GridEntry> enumeration) : base(enumeration) { }
|
||||
|
||||
public bool SupportsFiltering => true;
|
||||
public string Filter { get => FilterString; set => ApplyFilter(value); }
|
||||
|
||||
#region Unused - Advanced Filtering
|
||||
public bool SupportsAdvancedSorting => false;
|
||||
|
||||
//This ApplySort overload is only called if SupportsAdvancedSorting is true.
|
||||
//Otherwise BindingList.ApplySort() is used
|
||||
public void ApplySort(ListSortDescriptionCollection sorts) => throw new NotImplementedException();
|
||||
|
||||
public ListSortDescriptionCollection SortDescriptions => throw new NotImplementedException();
|
||||
#endregion
|
||||
|
||||
public new void Remove(GridEntry entry)
|
||||
{
|
||||
FilterRemoved.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)
|
||||
{
|
||||
if (filterString != FilterString)
|
||||
RemoveFilter();
|
||||
|
||||
FilterString = filterString;
|
||||
|
||||
var searchResults = SearchEngineCommands.Search(filterString);
|
||||
var filteredOut = Items.ExceptBy(searchResults.Docs.Select(d => d.ProductId), ge => ge.AudibleProductId);
|
||||
|
||||
for (int i = Items.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (filteredOut.Contains(Items[i]))
|
||||
{
|
||||
FilterRemoved.Add(Items[i]);
|
||||
Items.RemoveAt(i);
|
||||
base.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveFilter()
|
||||
{
|
||||
if (FilterString is null) return;
|
||||
|
||||
int visibleCount = Items.Count;
|
||||
for (int i = 0; i < FilterRemoved.Count; i++)
|
||||
base.InsertItem(i + visibleCount, FilterRemoved[i]);
|
||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||
|
||||
FilterRemoved.Clear();
|
||||
|
||||
if (IsSortedCore)
|
||||
Sort();
|
||||
else
|
||||
//No user-defined sort is applied, so do default sorting by date added, descending
|
||||
((List<GridEntry>)Items).Sort((i1, i2) => i2.LibraryBook.DateAdded.CompareTo(i1.LibraryBook.DateAdded));
|
||||
|
||||
FilterString = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ApplicationServices;
|
||||
using DataLayer;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using FileLiberator;
|
||||
using LibationFileManager;
|
||||
using LibationWinForms.Dialogs;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
|
||||
#region // legacy instructions to update data_grid_view
|
||||
// INSTRUCTIONS TO UPDATE DATA_GRID_VIEW
|
||||
// - delete current DataGridView
|
||||
// - view > other windows > data sources
|
||||
// - refresh
|
||||
// OR
|
||||
// - Add New Data Source
|
||||
// Object. Next
|
||||
// LibationWinForms
|
||||
// AudibleDTO
|
||||
// GridEntry
|
||||
// - go to Design view
|
||||
// - click on Data Sources > ProductItem. dropdown: DataGridView
|
||||
// - drag/drop ProductItem on design surface
|
||||
//
|
||||
// as of august 2021 this does not work in vs2019 with .net5 projects
|
||||
// VS has improved since then with .net6+ but I haven't checked again
|
||||
#endregion
|
||||
|
||||
|
||||
public partial class ProductsGrid : UserControl
|
||||
{
|
||||
public event EventHandler<LibraryBook> LiberateClicked;
|
||||
/// <summary>Number of visible rows has changed</summary>
|
||||
public event EventHandler<int> VisibleCountChanged;
|
||||
|
||||
// alias
|
||||
private DataGridView _dataGridView => gridEntryDataGridView;
|
||||
|
||||
public ProductsGrid()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (this.DesignMode)
|
||||
return;
|
||||
|
||||
EnableDoubleBuffering();
|
||||
|
||||
_dataGridView.CellContentClick += DataGridView_CellContentClick;
|
||||
|
||||
this.Load += ProductsGrid_Load;
|
||||
}
|
||||
|
||||
private void EnableDoubleBuffering()
|
||||
{
|
||||
var propertyInfo = _dataGridView.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
|
||||
propertyInfo.SetValue(_dataGridView, true, null);
|
||||
}
|
||||
|
||||
#region Button controls
|
||||
|
||||
private async void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
// handle grid button click: https://stackoverflow.com/a/13687844
|
||||
if (e.RowIndex < 0)
|
||||
return;
|
||||
|
||||
if (e.ColumnIndex == liberateGVColumn.Index)
|
||||
Liberate_Click(getGridEntry(e.RowIndex));
|
||||
else if (e.ColumnIndex == tagAndDetailsGVColumn.Index)
|
||||
Details_Click(getGridEntry(e.RowIndex));
|
||||
else if (e.ColumnIndex == descriptionGVColumn.Index)
|
||||
Description_Click(getGridEntry(e.RowIndex), _dataGridView.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false));
|
||||
else if (e.ColumnIndex == coverGVColumn.Index)
|
||||
await Cover_Click(getGridEntry(e.RowIndex));
|
||||
}
|
||||
|
||||
private ImageDisplay imageDisplay;
|
||||
private async Task Cover_Click(GridEntry liveGridEntry)
|
||||
{
|
||||
var picDefinition = new PictureDefinition(liveGridEntry.LibraryBook.Book.PictureLarge ?? liveGridEntry.LibraryBook.Book.PictureId, PictureSize.Native);
|
||||
var picDlTask = Task.Run(() => PictureStorage.GetPictureSynchronously(picDefinition));
|
||||
|
||||
(_, byte[] initialImageBts) = PictureStorage.GetPicture(new PictureDefinition(liveGridEntry.LibraryBook.Book.PictureId, PictureSize._80x80));
|
||||
var windowTitle = $"{liveGridEntry.Title} - Cover";
|
||||
|
||||
if (imageDisplay is null || imageDisplay.IsDisposed || !imageDisplay.Visible)
|
||||
{
|
||||
imageDisplay = new ImageDisplay();
|
||||
imageDisplay.RestoreSizeAndLocation(Configuration.Instance);
|
||||
imageDisplay.FormClosed += (_, _) => imageDisplay.SaveSizeAndLocation(Configuration.Instance);
|
||||
imageDisplay.Show(this);
|
||||
}
|
||||
|
||||
imageDisplay.BookSaveDirectory = AudibleFileStorage.Audio.GetDestinationDirectory(liveGridEntry.LibraryBook);
|
||||
imageDisplay.PictureFileName = System.IO.Path.GetFileName(AudibleFileStorage.Audio.GetBooksDirectoryFilename(liveGridEntry.LibraryBook, ".jpg"));
|
||||
imageDisplay.Text = windowTitle;
|
||||
imageDisplay.CoverPicture = initialImageBts;
|
||||
imageDisplay.CoverPicture = await picDlTask;
|
||||
}
|
||||
|
||||
private void Description_Click(GridEntry liveGridEntry, Rectangle cellDisplay)
|
||||
{
|
||||
var displayWindow = new DescriptionDisplay
|
||||
{
|
||||
SpawnLocation = PointToScreen(cellDisplay.Location + new Size(cellDisplay.Width, 0)),
|
||||
DescriptionText = liveGridEntry.LongDescription,
|
||||
BorderThickness = 2,
|
||||
};
|
||||
|
||||
void CloseWindow(object o, EventArgs e)
|
||||
{
|
||||
displayWindow.Close();
|
||||
}
|
||||
|
||||
_dataGridView.Scroll += CloseWindow;
|
||||
displayWindow.FormClosed += (_, _) => _dataGridView.Scroll -= CloseWindow;
|
||||
displayWindow.Show(this);
|
||||
}
|
||||
|
||||
private void Liberate_Click(GridEntry liveGridEntry)
|
||||
{
|
||||
LiberateClicked?.Invoke(this, liveGridEntry.LibraryBook);
|
||||
}
|
||||
|
||||
private static void Details_Click(GridEntry liveGridEntry)
|
||||
{
|
||||
var bookDetailsForm = new BookDetailsDialog(liveGridEntry.LibraryBook);
|
||||
if (bookDetailsForm.ShowDialog() == DialogResult.OK)
|
||||
liveGridEntry.Commit(bookDetailsForm.NewTags, bookDetailsForm.BookLiberatedStatus, bookDetailsForm.PdfLiberatedStatus);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI display functions
|
||||
|
||||
private FilterableSortableBindingList bindingList;
|
||||
|
||||
private bool hasBeenDisplayed;
|
||||
public event EventHandler InitialLoaded;
|
||||
public void Display()
|
||||
{
|
||||
// don't return early if lib size == 0. this will not update correctly if all books are removed
|
||||
var lib = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (!hasBeenDisplayed)
|
||||
{
|
||||
// bind
|
||||
bindToGrid(lib);
|
||||
hasBeenDisplayed = true;
|
||||
InitialLoaded?.Invoke(this, new());
|
||||
VisibleCountChanged?.Invoke(this, bindingList.Count);
|
||||
}
|
||||
else
|
||||
updateGrid(lib);
|
||||
|
||||
}
|
||||
|
||||
private void bindToGrid(List<LibraryBook> dbBooks)
|
||||
{
|
||||
bindingList = new FilterableSortableBindingList(dbBooks.OrderByDescending(lb => lb.DateAdded).Select(lb => new GridEntry(lb)));
|
||||
gridEntryBindingSource.DataSource = bindingList;
|
||||
}
|
||||
|
||||
private void updateGrid(List<LibraryBook> dbBooks)
|
||||
{
|
||||
int visibleCount = bindingList.Count;
|
||||
string existingFilter = gridEntryBindingSource.Filter;
|
||||
|
||||
//Add absent books to grid, or update current books
|
||||
|
||||
var allItmes = bindingList.AllItems();
|
||||
for (var i = dbBooks.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var libraryBook = dbBooks[i];
|
||||
var existingItem = allItmes.FirstOrDefault(i => i.AudibleProductId == libraryBook.Book.AudibleProductId);
|
||||
|
||||
// add new to top
|
||||
if (existingItem is null)
|
||||
bindingList.Insert(0, new GridEntry(libraryBook));
|
||||
// update existing
|
||||
else
|
||||
existingItem.UpdateLibraryBook(libraryBook);
|
||||
}
|
||||
|
||||
if (bindingList.Count != visibleCount)
|
||||
{
|
||||
//re-filter for newly added items
|
||||
Filter(null);
|
||||
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 =
|
||||
bindingList
|
||||
.AllItems()
|
||||
.ExceptBy(dbBooks.Select(lb => lb.Book.AudibleProductId), ge => ge.AudibleProductId)
|
||||
.ToList();
|
||||
|
||||
foreach (var removed in removedBooks)
|
||||
//no need to re-filter for removed books
|
||||
bindingList.Remove(removed);
|
||||
|
||||
if (bindingList.Count != visibleCount)
|
||||
VisibleCountChanged?.Invoke(this, bindingList.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Filter
|
||||
|
||||
public void Filter(string searchString)
|
||||
{
|
||||
int visibleCount = bindingList.Count;
|
||||
|
||||
if (string.IsNullOrEmpty(searchString))
|
||||
gridEntryBindingSource.RemoveFilter();
|
||||
else
|
||||
gridEntryBindingSource.Filter = searchString;
|
||||
|
||||
if (visibleCount != bindingList.Count)
|
||||
VisibleCountChanged?.Invoke(this, bindingList.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal List<LibraryBook> GetVisible()
|
||||
=> bindingList
|
||||
.Select(row => row.LibraryBook)
|
||||
.ToList();
|
||||
|
||||
private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem<GridEntry>(rowIndex);
|
||||
|
||||
#region Column Customizations
|
||||
|
||||
// to ensure this is only ever called once: Load instead of 'override OnVisibleChanged'
|
||||
private void ProductsGrid_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (this.DesignMode)
|
||||
return;
|
||||
|
||||
contextMenuStrip1.Items.Add(new ToolStripLabel("Show / Hide Columns"));
|
||||
contextMenuStrip1.Items.Add(new ToolStripSeparator());
|
||||
|
||||
//Restore Grid Display Settings
|
||||
var config = Configuration.Instance;
|
||||
var gridColumnsVisibilities = config.GridColumnsVisibilities;
|
||||
var gridColumnsWidths = config.GridColumnsWidths;
|
||||
var displayIndices = config.GridColumnsDisplayIndices;
|
||||
|
||||
var cmsKiller = new ContextMenuStrip();
|
||||
|
||||
foreach (DataGridViewColumn column in _dataGridView.Columns)
|
||||
{
|
||||
var itemName = column.DataPropertyName;
|
||||
var visible = gridColumnsVisibilities.GetValueOrDefault(itemName, true);
|
||||
|
||||
var menuItem = new ToolStripMenuItem()
|
||||
{
|
||||
Text = column.HeaderText,
|
||||
Checked = visible,
|
||||
Tag = itemName
|
||||
};
|
||||
menuItem.Click += HideMenuItem_Click;
|
||||
contextMenuStrip1.Items.Add(menuItem);
|
||||
|
||||
column.Width = gridColumnsWidths.GetValueOrDefault(itemName, column.Width);
|
||||
column.MinimumWidth = 10;
|
||||
column.HeaderCell.ContextMenuStrip = contextMenuStrip1;
|
||||
column.Visible = visible;
|
||||
|
||||
//Setting a default ContextMenuStrip will allow the columns to handle the
|
||||
//Show() event so it is not passed up to the _dataGridView.ContextMenuStrip.
|
||||
//This allows the ContextMenuStrip to be shown if right-clicking in the gray
|
||||
//background of _dataGridView but not shown if right-clicking inside cells.
|
||||
column.ContextMenuStrip = cmsKiller;
|
||||
}
|
||||
|
||||
//We must set DisplayIndex properties in ascending order
|
||||
foreach (var itemName in displayIndices.OrderBy(i => i.Value).Select(i => i.Key))
|
||||
{
|
||||
var column = _dataGridView.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.Single(c => c.DataPropertyName == itemName);
|
||||
|
||||
column.DisplayIndex = displayIndices.GetValueOrDefault(itemName, column.Index);
|
||||
}
|
||||
|
||||
base.OnVisibleChanged(e);
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
|
||||
{
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsDisplayIndices;
|
||||
dictionary[e.Column.DataPropertyName] = e.Column.DisplayIndex;
|
||||
config.GridColumnsDisplayIndices = dictionary;
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
|
||||
{
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsWidths;
|
||||
dictionary[e.Column.DataPropertyName] = e.Column.Width;
|
||||
config.GridColumnsWidths = dictionary;
|
||||
}
|
||||
|
||||
private void HideMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var menuItem = sender as ToolStripMenuItem;
|
||||
var propertyName = menuItem.Tag as string;
|
||||
|
||||
var column = _dataGridView.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.FirstOrDefault(c => c.DataPropertyName == propertyName);
|
||||
|
||||
if (column != null)
|
||||
{
|
||||
var visible = menuItem.Checked;
|
||||
menuItem.Checked = !visible;
|
||||
column.Visible = !visible;
|
||||
|
||||
var config = Configuration.Instance;
|
||||
|
||||
var dictionary = config.GridColumnsVisibilities;
|
||||
dictionary[propertyName] = column.Visible;
|
||||
config.GridColumnsVisibilities = dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
private void gridEntryDataGridView_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
|
||||
{
|
||||
if (e.ColumnIndex == descriptionGVColumn.Index)
|
||||
e.ToolTipText = "Click to see full description";
|
||||
else if (e.ColumnIndex == coverGVColumn.Index)
|
||||
e.ToolTipText = "Click to see full size";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
|
||||
Reference in New Issue
Block a user