diff --git a/Source/AaxDecrypter/AudiobookDownloadBase.cs b/Source/AaxDecrypter/AudiobookDownloadBase.cs index 04e901ed..21cb77d1 100644 --- a/Source/AaxDecrypter/AudiobookDownloadBase.cs +++ b/Source/AaxDecrypter/AudiobookDownloadBase.cs @@ -20,7 +20,7 @@ namespace AaxDecrypter public event EventHandler DecryptTimeRemaining; public event EventHandler FileCreated; - protected bool IsCanceled { get; set; } + public bool IsCanceled { get; set; } protected string OutputFileName { get; private set; } protected DownloadOptions DownloadOptions { get; } diff --git a/Source/FileLiberator/ConvertToMp3.cs b/Source/FileLiberator/ConvertToMp3.cs index 12d758c1..35f3411e 100644 --- a/Source/FileLiberator/ConvertToMp3.cs +++ b/Source/FileLiberator/ConvertToMp3.cs @@ -14,6 +14,7 @@ namespace FileLiberator { public class ConvertToMp3 : AudioDecodable { + public override string Name => "Convert to Mp3"; private Mp4File m4bBook; private long fileSize; diff --git a/Source/FileLiberator/DownloadDecryptBook.cs b/Source/FileLiberator/DownloadDecryptBook.cs index 3cfc687f..ef54d81d 100644 --- a/Source/FileLiberator/DownloadDecryptBook.cs +++ b/Source/FileLiberator/DownloadDecryptBook.cs @@ -15,6 +15,7 @@ namespace FileLiberator { public class DownloadDecryptBook : AudioDecodable { + public override string Name => "Download & Decrypt"; private AudiobookDownloadBase abDownloader; public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists(); @@ -65,7 +66,9 @@ namespace FileLiberator foreach (var tmpFile in entries.Where(f => f.FileType != FileType.AAXC)) FileUtility.SaferDelete(tmpFile.Path); - return new StatusHandler { "Decrypt failed" }; + return abDownloader?.IsCanceled == true ? + new StatusHandler { "Cancelled" } : + new StatusHandler { "Decrypt failed" }; } // moves new files from temp dir to final dest diff --git a/Source/FileLiberator/DownloadPdf.cs b/Source/FileLiberator/DownloadPdf.cs index a9e047a7..5bc61f7c 100644 --- a/Source/FileLiberator/DownloadPdf.cs +++ b/Source/FileLiberator/DownloadPdf.cs @@ -14,6 +14,7 @@ namespace FileLiberator { public class DownloadPdf : Processable { + public override string Name => "Download Pdf"; public override bool Validate(LibraryBook libraryBook) => !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook)) && !libraryBook.Book.PDF_Exists(); diff --git a/Source/FileLiberator/Processable.cs b/Source/FileLiberator/Processable.cs index da66f0f6..b8b984ff 100644 --- a/Source/FileLiberator/Processable.cs +++ b/Source/FileLiberator/Processable.cs @@ -11,6 +11,7 @@ namespace FileLiberator { public abstract class Processable : Streamable { + public abstract string Name { get; } public event EventHandler Begin; /// General string message to display. DON'T rely on this for success, failure, or control logic diff --git a/Source/LibationWinForms/BookLiberation/AutomatedBackupsForm.cs b/Source/LibationWinForms/BookLiberation/AutomatedBackupsForm.cs index 2a800e3d..a020ecb0 100644 --- a/Source/LibationWinForms/BookLiberation/AutomatedBackupsForm.cs +++ b/Source/LibationWinForms/BookLiberation/AutomatedBackupsForm.cs @@ -4,7 +4,11 @@ using Dinah.Core.Threading; namespace LibationWinForms.BookLiberation { - public partial class AutomatedBackupsForm : Form + public interface ILogForm + { + void WriteLine(string text); + } + public partial class AutomatedBackupsForm : Form, ILogForm { public bool KeepGoingChecked => keepGoingCb.Checked; diff --git a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs index 299f5aec..38a185c3 100644 --- a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs +++ b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs @@ -25,7 +25,8 @@ namespace LibationWinForms.BookLiberation LogError += (_, tuple) => Serilog.Log.Logger.Error(tuple.Item1, tuple.Item2 ?? "Automated backup: error"); } - public static LogMe RegisterForm(AutomatedBackupsForm form = null) + public static LogMe RegisterForm() => RegisterForm(null); + public static LogMe RegisterForm(T form) where T : ILogForm { var logMe = new LogMe(); diff --git a/Source/LibationWinForms/Dialogs/AccountsDialog.cs b/Source/LibationWinForms/Dialogs/AccountsDialog.cs index b31009b3..7670c0dd 100644 --- a/Source/LibationWinForms/Dialogs/AccountsDialog.cs +++ b/Source/LibationWinForms/Dialogs/AccountsDialog.cs @@ -15,9 +15,9 @@ namespace LibationWinForms.Dialogs private const string COL_AccountName = nameof(AccountName); private const string COL_Locale = nameof(Locale); - private Form1 _parent { get; } + private Form _parent { get; } - public AccountsDialog(Form1 parent) + public AccountsDialog(Form parent) { _parent = parent; diff --git a/Source/LibationWinForms/Dialogs/EditQuickFilters.cs b/Source/LibationWinForms/Dialogs/EditQuickFilters.cs index 3d6eab63..3e53d77a 100644 --- a/Source/LibationWinForms/Dialogs/EditQuickFilters.cs +++ b/Source/LibationWinForms/Dialogs/EditQuickFilters.cs @@ -15,9 +15,9 @@ namespace LibationWinForms.Dialogs private const string COL_MoveUp = nameof(MoveUp); private const string COL_MoveDown = nameof(MoveDown); - private Form1 _parent { get; } + private Form _parent { get; } - public EditQuickFilters(Form1 parent) + public EditQuickFilters(Form parent) { _parent = parent; diff --git a/Source/LibationWinForms/Dialogs/ScanAccountsDialog.cs b/Source/LibationWinForms/Dialogs/ScanAccountsDialog.cs index 0ebd283d..09a62f23 100644 --- a/Source/LibationWinForms/Dialogs/ScanAccountsDialog.cs +++ b/Source/LibationWinForms/Dialogs/ScanAccountsDialog.cs @@ -10,9 +10,9 @@ namespace LibationWinForms.Dialogs { public List CheckedAccounts { get; } = new List(); - private Form1 _parent { get; } + private Form _parent { get; } - public ScanAccountsDialog(Form1 parent) + public ScanAccountsDialog(Form parent) { _parent = parent; diff --git a/Source/LibationWinForms/Form1.Designer.cs b/Source/LibationWinForms/Form1.Designer.cs index fb916fe2..162599e7 100644 --- a/Source/LibationWinForms/Form1.Designer.cs +++ b/Source/LibationWinForms/Form1.Designer.cs @@ -28,102 +28,108 @@ /// 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 System.Windows.Forms.ToolStripMenuItem(); - this.beginPdfBackupsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.convertAllM4bToMp3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.liberateVisible2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - 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 System.Windows.Forms.ToolStripMenuItem(); - this.liberateVisibleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - 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 System.Windows.Forms.ToolStripStatusLabel(); - this.springLbl = new System.Windows.Forms.ToolStripStatusLabel(); - this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel(); - this.pdfsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel(); - this.addFilterBtn = new System.Windows.Forms.Button(); - this.menuStrip1.SuspendLayout(); - this.statusStrip1.SuspendLayout(); - this.SuspendLayout(); - // - // gridPanel - // - this.gridPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + 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 System.Windows.Forms.ToolStripMenuItem(); + this.beginPdfBackupsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.convertAllM4bToMp3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.liberateVisible2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + 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 System.Windows.Forms.ToolStripMenuItem(); + this.liberateVisibleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + 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 System.Windows.Forms.ToolStripStatusLabel(); + this.springLbl = new System.Windows.Forms.ToolStripStatusLabel(); + this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel(); + this.pdfsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel(); + this.addFilterBtn = new System.Windows.Forms.Button(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessBookQueue(); + this.menuStrip1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.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.Windows.Forms.AnchorStyles.Right))); - this.gridPanel.Location = new System.Drawing.Point(34, 178); - this.gridPanel.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - this.gridPanel.Name = "gridPanel"; - this.gridPanel.Size = new System.Drawing.Size(2378, 1216); - this.gridPanel.TabIndex = 5; - // - // filterHelpBtn - // - this.filterHelpBtn.Location = new System.Drawing.Point(34, 85); - this.filterHelpBtn.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - this.filterHelpBtn.Name = "filterHelpBtn"; - this.filterHelpBtn.Size = new System.Drawing.Size(63, 74); - 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(2198, 85); - this.filterBtn.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - this.filterBtn.Name = "filterBtn"; - this.filterBtn.Size = new System.Drawing.Size(214, 74); - 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) + this.gridPanel.Location = new System.Drawing.Point(15, 60); + this.gridPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.gridPanel.Name = "gridPanel"; + this.gridPanel.Size = new System.Drawing.Size(865, 556); + this.gridPanel.TabIndex = 5; + // + // filterHelpBtn + // + this.filterHelpBtn.Location = new System.Drawing.Point(15, 27); + 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(792, 27); + this.filterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 15, 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(527, 90); - this.filterSearchTb.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - this.filterSearchTb.Name = "filterSearchTb"; - this.filterSearchTb.Size = new System.Drawing.Size(1648, 47); - 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(220, 30); + this.filterSearchTb.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.filterSearchTb.Name = "filterSearchTb"; + this.filterSearchTb.Size = new System.Drawing.Size(564, 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, @@ -131,328 +137,359 @@ 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(17, 5, 0, 5); - this.menuStrip1.Size = new System.Drawing.Size(2446, 58); - 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(895, 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(132, 48); - this.importToolStripMenuItem.Text = "&Import"; - // - // autoScanLibraryToolStripMenuItem - // - this.autoScanLibraryToolStripMenuItem.Name = "autoScanLibraryToolStripMenuItem"; - this.autoScanLibraryToolStripMenuItem.Size = new System.Drawing.Size(613, 54); - 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(613, 54); - 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(613, 54); - 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(613, 54); - 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(613, 54); - 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.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(613, 54); - 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(390, 54); - 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(390, 54); - 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(148, 48); - this.liberateToolStripMenuItem.Text = "&Liberate"; - // - // beginBookBackupsToolStripMenuItem - // - this.beginBookBackupsToolStripMenuItem.Name = "beginBookBackupsToolStripMenuItem"; - this.beginBookBackupsToolStripMenuItem.Size = new System.Drawing.Size(728, 54); - this.beginBookBackupsToolStripMenuItem.Text = "Begin &Book and PDF Backups: {0}"; - this.beginBookBackupsToolStripMenuItem.Click += new System.EventHandler(this.beginBookBackupsToolStripMenuItem_Click); - // - // beginPdfBackupsToolStripMenuItem - // - this.beginPdfBackupsToolStripMenuItem.Name = "beginPdfBackupsToolStripMenuItem"; - this.beginPdfBackupsToolStripMenuItem.Size = new System.Drawing.Size(728, 54); - 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(728, 54); - this.convertAllM4bToMp3ToolStripMenuItem.Text = "Convert all &M4b to Mp3 [Long-running]..."; - this.convertAllM4bToMp3ToolStripMenuItem.Click += new System.EventHandler(this.convertAllM4bToMp3ToolStripMenuItem_Click); - // - // liberateVisible2ToolStripMenuItem - // - this.liberateVisible2ToolStripMenuItem.Name = "liberateVisible2ToolStripMenuItem"; - this.liberateVisible2ToolStripMenuItem.Size = new System.Drawing.Size(728, 54); - 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.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.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.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(127, 48); - this.exportToolStripMenuItem.Text = "E&xport"; - // - // exportLibraryToolStripMenuItem - // - this.exportLibraryToolStripMenuItem.Name = "exportLibraryToolStripMenuItem"; - this.exportLibraryToolStripMenuItem.Size = new System.Drawing.Size(387, 54); - 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(204, 48); - this.quickFiltersToolStripMenuItem.Text = "Quick &Filters"; - // - // firstFilterIsDefaultToolStripMenuItem - // - this.firstFilterIsDefaultToolStripMenuItem.Name = "firstFilterIsDefaultToolStripMenuItem"; - this.firstFilterIsDefaultToolStripMenuItem.Size = new System.Drawing.Size(639, 54); - 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(639, 54); - 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(636, 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.Name = "scanningToolStripMenuItem"; - this.scanningToolStripMenuItem.Size = new System.Drawing.Size(224, 48); - 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.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.Name = "scanningToolStripMenuItem"; + this.scanningToolStripMenuItem.Size = new System.Drawing.Size(117, 44); + 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.Name = "visibleBooksToolStripMenuItem"; - this.visibleBooksToolStripMenuItem.Size = new System.Drawing.Size(267, 48); - this.visibleBooksToolStripMenuItem.Text = "&Visible Books: {0}"; - // - // liberateVisibleToolStripMenuItem - // - this.liberateVisibleToolStripMenuItem.Name = "liberateVisibleToolStripMenuItem"; - this.liberateVisibleToolStripMenuItem.Size = new System.Drawing.Size(525, 54); - 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(525, 54); - 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(525, 54); - 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(525, 54); - 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.Name = "visibleBooksToolStripMenuItem"; + this.visibleBooksToolStripMenuItem.Size = new System.Drawing.Size(108, 20); + this.visibleBooksToolStripMenuItem.Text = "&Visible Books: {0}"; + // + // liberateVisibleToolStripMenuItem + // + 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(149, 48); - this.settingsToolStripMenuItem.Text = "&Settings"; - // - // accountsToolStripMenuItem - // - this.accountsToolStripMenuItem.Name = "accountsToolStripMenuItem"; - this.accountsToolStripMenuItem.Size = new System.Drawing.Size(327, 54); - 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(327, 54); - 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(324, 6); - // - // aboutToolStripMenuItem - // - this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; - this.aboutToolStripMenuItem.Size = new System.Drawing.Size(327, 54); - 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, 1419); - this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Padding = new System.Windows.Forms.Padding(2, 0, 39, 0); - this.statusStrip1.Size = new System.Drawing.Size(2446, 54); - this.statusStrip1.TabIndex = 6; - this.statusStrip1.Text = "statusStrip1"; - // - // visibleCountLbl - // - this.visibleCountLbl.Name = "visibleCountLbl"; - this.visibleCountLbl.Size = new System.Drawing.Size(136, 41); - this.visibleCountLbl.Text = "Visible: 0"; - // - // springLbl - // - this.springLbl.Name = "springLbl"; - this.springLbl.Size = new System.Drawing.Size(1299, 41); - this.springLbl.Spring = true; - // - // backupsCountsLbl - // - this.backupsCountsLbl.Name = "backupsCountsLbl"; - this.backupsCountsLbl.Size = new System.Drawing.Size(544, 41); - this.backupsCountsLbl.Text = "[Calculating backed up book quantities]"; - // - // pdfsCountsLbl - // - this.pdfsCountsLbl.Name = "pdfsCountsLbl"; - this.pdfsCountsLbl.Size = new System.Drawing.Size(426, 41); - this.pdfsCountsLbl.Text = "| [Calculating backed up PDFs]"; - // - // addFilterBtn - // - this.addFilterBtn.Location = new System.Drawing.Point(114, 85); - this.addFilterBtn.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - this.addFilterBtn.Name = "addFilterBtn"; - this.addFilterBtn.Size = new System.Drawing.Size(396, 74); - this.addFilterBtn.TabIndex = 4; - this.addFilterBtn.Text = "Add To Quick Filters"; - this.addFilterBtn.UseVisualStyleBackColor = true; - this.addFilterBtn.Click += new System.EventHandler(this.AddFilterBtn_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(17F, 41F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(2446, 1473); - this.Controls.Add(this.filterBtn); - this.Controls.Add(this.addFilterBtn); - this.Controls.Add(this.filterSearchTb); - this.Controls.Add(this.filterHelpBtn); - this.Controls.Add(this.statusStrip1); - this.Controls.Add(this.gridPanel); - this.Controls.Add(this.menuStrip1); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MainMenuStrip = this.menuStrip1; - this.Margin = new System.Windows.Forms.Padding(10, 8, 10, 8); - 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.ResumeLayout(false); - this.PerformLayout(); + this.statusStrip1.Location = new System.Drawing.Point(0, 619); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0); + this.statusStrip1.Size = new System.Drawing.Size(895, 22); + this.statusStrip1.TabIndex = 6; + this.statusStrip1.Text = "statusStrip1"; + // + // visibleCountLbl + // + this.visibleCountLbl.Name = "visibleCountLbl"; + this.visibleCountLbl.Size = new System.Drawing.Size(53, 17); + this.visibleCountLbl.Text = "Visible: 0"; + // + // springLbl + // + this.springLbl.Name = "springLbl"; + this.springLbl.Size = new System.Drawing.Size(436, 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.Name = "pdfsCountsLbl"; + this.pdfsCountsLbl.Size = new System.Drawing.Size(171, 17); + this.pdfsCountsLbl.Text = "| [Calculating backed up PDFs]"; + // + // addFilterBtn + // + this.addFilterBtn.Location = new System.Drawing.Point(49, 27); + this.addFilterBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.addFilterBtn.Name = "addFilterBtn"; + this.addFilterBtn.Size = new System.Drawing.Size(163, 27); + this.addFilterBtn.TabIndex = 4; + this.addFilterBtn.Text = "Add To Quick Filters"; + this.addFilterBtn.UseVisualStyleBackColor = true; + this.addFilterBtn.Click += new System.EventHandler(this.AddFilterBtn_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.menuStrip1); + this.splitContainer1.Panel1.Controls.Add(this.gridPanel); + this.splitContainer1.Panel1.Controls.Add(this.filterSearchTb); + this.splitContainer1.Panel1.Controls.Add(this.addFilterBtn); + this.splitContainer1.Panel1.Controls.Add(this.filterBtn); + this.splitContainer1.Panel1.Controls.Add(this.statusStrip1); + this.splitContainer1.Panel1.Controls.Add(this.filterHelpBtn); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.processBookQueue1); + this.splitContainer1.Size = new System.Drawing.Size(1231, 641); + this.splitContainer1.SplitterDistance = 895; + this.splitContainer1.SplitterWidth = 8; + this.splitContainer1.TabIndex = 7; + // + // 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.Name = "processBookQueue1"; + this.processBookQueue1.Size = new System.Drawing.Size(328, 641); + 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, 641); + 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.ResumeLayout(false); } @@ -500,5 +537,7 @@ private System.Windows.Forms.ToolStripMenuItem setDownloadedToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem liberateVisible2ToolStripMenuItem; - } + private System.Windows.Forms.SplitContainer splitContainer1; + private LibationWinForms.ProcessQueue.ProcessBookQueue processBookQueue1; + } } diff --git a/Source/LibationWinForms/Form1.cs b/Source/LibationWinForms/Form1.cs index a4abb1ed..1e537ff5 100644 --- a/Source/LibationWinForms/Form1.cs +++ b/Source/LibationWinForms/Form1.cs @@ -10,6 +10,7 @@ using Dinah.Core.Drawing; using Dinah.Core.Threading; using LibationFileManager; using LibationWinForms.Dialogs; +using LibationWinForms.ProcessQueue; namespace LibationWinForms { @@ -31,6 +32,9 @@ namespace LibationWinForms if (this.DesignMode) return; + //splitContainer1.Panel2Collapsed = true; + processBookQueue1.popoutBtn.Click += ProcessBookQueue1_PopOut; + productsGrid = new ProductsGrid { Dock = DockStyle.Fill }; productsGrid.VisibleCountChanged += (_, qty) => visibleCountLbl.Text = string.Format("Visible: {0}", qty); gridPanel.Controls.Add(productsGrid); @@ -646,6 +650,36 @@ namespace LibationWinForms this.scanningToolStripMenuItem.Visible = false; } - #endregion - } + #endregion + + #region Process Queue + + private void ProcessBookQueue1_PopOut(object sender, EventArgs e) + { + ProcessBookForm dockForm = new(); + dockForm.WidthChange = splitContainer1.Panel2.Width + splitContainer1.SplitterWidth; + dockForm.RestoreSizeAndLocation(Configuration.Instance); + dockForm.FormClosing += DockForm_FormClosing; + splitContainer1.Panel2.Controls.Remove(processBookQueue1); + splitContainer1.Panel2Collapsed = true; + processBookQueue1.popoutBtn.Visible = false; + dockForm.PassControl(processBookQueue1); + dockForm.Show(); + this.Width -= dockForm.WidthChange; + } + + private void DockForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (sender is ProcessBookForm dockForm) + { + this.Width += dockForm.WidthChange; + splitContainer1.Panel2.Controls.Add(dockForm.RegainControl()); + splitContainer1.Panel2Collapsed = false; + processBookQueue1.popoutBtn.Visible = true; + dockForm.SaveSizeAndLocation(Configuration.Instance); + this.Focus(); + } + } + #endregion + } } diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBook.cs b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs new file mode 100644 index 00000000..df142e56 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBook.cs @@ -0,0 +1,249 @@ +using DataLayer; +using Dinah.Core; +using FileLiberator; +using LibationFileManager; +using LibationWinForms.BookLiberation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibationWinForms.ProcessQueue +{ + public enum ProcessBookResult + { + None, + Success, + Cancelled, + FailedRetry, + FailedSkip, + FailedAbort + } + + internal enum QueuePosition + { + Absent, + Current, + Fisrt, + OneUp, + OneDown, + Last + } + + internal delegate QueuePosition ProcessControlReorderHandler(ProcessBook sender, QueuePosition arg); + internal delegate void ProcessControlEventArgs(ProcessBook sender, T arg); + internal delegate void ProcessControlEventArgs(ProcessBook sender, EventArgs arg); + + internal class ProcessBook + { + public event EventHandler Completed; + public event ProcessControlEventArgs Cancelled; + public event ProcessControlReorderHandler RequestMove; + public GridEntry Entry { get; } + public ILiberationBaseForm BookControl { get; } + + private Func _makeFirstProc; + private Processable _firstProcessable; + private bool cancelled = false; + private bool running = false; + public Processable FirstProcessable => _firstProcessable ??= _makeFirstProc?.Invoke(); + private readonly Queue> Processes = new(); + + LogMe Logger; + + public ProcessBook(GridEntry entry, LogMe logme) + { + Entry = entry; + BookControl = new ProcessBookControl(Entry.Title, Entry.Cover); + BookControl.CancelAction = Cancel; + BookControl.MoveUpAction = MoveUp; + BookControl.MoveDownAction = MoveDown; + Logger = logme; + } + + public QueuePosition? MoveUp() + { + return RequestMove?.Invoke(this, QueuePosition.OneUp); + } + public QueuePosition? MoveDown() + { + return RequestMove?.Invoke(this, QueuePosition.OneDown); + } + + public void Cancel() + { + cancelled = true; + try + { + if (FirstProcessable is AudioDecodable audioDecodable) + audioDecodable.Cancel(); + } + catch(Exception ex) + { + Logger.Error(ex, "Error while cancelling"); + } + + if (!running) + Cancelled?.Invoke(this, EventArgs.Empty); + } + + public async Task ProcessOneAsync() + { + running = true; + ProcessBookResult result = ProcessBookResult.None; + try + { + var firstProc = FirstProcessable; + + LinkProcessable(firstProc); + + var statusHandler = await firstProc.ProcessSingleAsync(Entry.LibraryBook, validate: true); + + + if (statusHandler.IsSuccess) + return result = ProcessBookResult.Success; + else if (cancelled) + { + Logger.Info($"Process was cancelled {Entry.LibraryBook.Book}"); + return result = ProcessBookResult.Cancelled; + } + + foreach (var errorMessage in statusHandler.Errors) + Logger.Error(errorMessage); + } + catch (Exception ex) + { + Logger.Error(ex); + } + finally + { + if (result == ProcessBookResult.None) + result = showRetry(Entry.LibraryBook); + + BookControl.SetResult(result); + } + + return result; + } + + public void AddPdfProcessable() => AddProcessable(); + public void AddDownloadDecryptProcessable() => AddProcessable(); + public void AddConvertMp3Processable() => AddProcessable(); + + private void AddProcessable() where T : Processable, new() + { + if (FirstProcessable == null) + { + _makeFirstProc = () => new T(); + } + else + Processes.Enqueue(() => new T()); + } + + private void LinkProcessable(Processable strProc) + { + strProc.Begin += Processable_Begin; + strProc.Completed += Processable_Completed; + } + + private void Processable_Begin(object sender, LibraryBook libraryBook) + { + BookControl.RegisterFileLiberator((Processable)sender, Logger); + BookControl.Processable_Begin(sender, libraryBook); + } + + private async void Processable_Completed(object sender, LibraryBook e) + { + ((Processable)sender).Begin -= Processable_Begin; + + if (Processes.Count > 0) + { + var nextProcessFunc = Processes.Dequeue(); + var nextProcess = nextProcessFunc(); + LinkProcessable(nextProcess); + var result = await nextProcess.ProcessSingleAsync(e, true); + + if (result.HasErrors) + { + foreach (var errorMessage in result.Errors.Where(e => e != "Validation failed")) + Logger.Error(errorMessage); + + Completed?.Invoke(this, EventArgs.Empty); + running = false; + } + } + else + { + Completed?.Invoke(this, EventArgs.Empty); + running = false; + } + } + + private ProcessBookResult showRetry(LibraryBook libraryBook) + { + Logger.Error("ERROR. All books have not been processed. Most recent book: processing failed"); + + DialogResult? dialogResult = Configuration.Instance.BadBook switch + { + Configuration.BadBookAction.Abort => DialogResult.Abort, + Configuration.BadBookAction.Retry => DialogResult.Retry, + Configuration.BadBookAction.Ignore => DialogResult.Ignore, + Configuration.BadBookAction.Ask => null, + _ => null + }; + + string details; + try + { + static string trunc(string str) + => string.IsNullOrWhiteSpace(str) ? "[empty]" + : (str.Length > 50) ? $"{str.Truncate(47)}..." + : str; + + details = +$@" Title: {libraryBook.Book.Title} + ID: {libraryBook.Book.AudibleProductId} + Author: {trunc(libraryBook.Book.AuthorNames())} + Narr: {trunc(libraryBook.Book.NarratorNames())}"; + } + catch + { + details = "[Error retrieving details]"; + } + + // if null then ask user + dialogResult ??= MessageBox.Show(string.Format(SkipDialogText + "\r\n\r\nSee Settings to avoid this box in the future.", details), "Skip importing this book?", SkipDialogButtons, MessageBoxIcon.Question, SkipDialogDefaultButton); + + if (dialogResult == DialogResult.Abort) + return ProcessBookResult.FailedAbort; + + if (dialogResult == SkipResult) + { + libraryBook.Book.UserDefinedItem.BookStatus = LiberatedStatus.Error; + ApplicationServices.LibraryCommands.UpdateUserDefinedItem(libraryBook.Book); + + Logger.Info($"Error. Skip: [{libraryBook.Book.AudibleProductId}] {libraryBook.Book.Title}"); + + return ProcessBookResult.FailedSkip; + } + + return ProcessBookResult.FailedRetry; + } + + + protected string SkipDialogText => @" +An error occurred while trying to process this book. +{0} + +- ABORT: Stop processing books. + +- RETRY: retry this book later. Just skip it for now. Continue processing books. (Will try this book again later.) + +- IGNORE: Permanently ignore this book. Continue processing books. (Will not try this book again later.) +".Trim(); + protected MessageBoxButtons SkipDialogButtons => MessageBoxButtons.AbortRetryIgnore; + protected MessageBoxDefaultButton SkipDialogDefaultButton => MessageBoxDefaultButton.Button1; + protected DialogResult SkipResult => DialogResult.Ignore; + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.Designer.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.Designer.cs new file mode 100644 index 00000000..ee395dd3 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.Designer.cs @@ -0,0 +1,178 @@ +namespace LibationWinForms.ProcessQueue +{ + partial class ProcessBookControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProcessBookControl)); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.bookInfoLbl = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.remainingTimeLbl = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.cancelBtn = new System.Windows.Forms.Button(); + this.moveUpBtn = new System.Windows.Forms.Button(); + this.moveDownBtn = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(2, 2); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(80, 80); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // bookInfoLbl + // + this.bookInfoLbl.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.bookInfoLbl.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.bookInfoLbl.Location = new System.Drawing.Point(89, 3); + this.bookInfoLbl.Name = "bookInfoLbl"; + this.bookInfoLbl.Size = new System.Drawing.Size(255, 56); + this.bookInfoLbl.TabIndex = 1; + this.bookInfoLbl.Text = "[multi-\r\nline\r\nbook\r\n info]"; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(88, 65); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(212, 17); + this.progressBar1.TabIndex = 2; + // + // remainingTimeLbl + // + this.remainingTimeLbl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.remainingTimeLbl.AutoSize = true; + this.remainingTimeLbl.Location = new System.Drawing.Point(338, 65); + this.remainingTimeLbl.Name = "remainingTimeLbl"; + this.remainingTimeLbl.Size = new System.Drawing.Size(30, 15); + this.remainingTimeLbl.TabIndex = 3; + this.remainingTimeLbl.Text = "--:--"; + this.remainingTimeLbl.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.label1.Location = new System.Drawing.Point(304, 66); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(28, 13); + this.label1.TabIndex = 3; + this.label1.Text = "ETA:"; + this.label1.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // cancelBtn + // + this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.cancelBtn.BackColor = System.Drawing.Color.Transparent; + this.cancelBtn.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("cancelBtn.BackgroundImage"))); + this.cancelBtn.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.cancelBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.cancelBtn.ForeColor = System.Drawing.SystemColors.Control; + this.cancelBtn.Location = new System.Drawing.Point(352, 3); + this.cancelBtn.Margin = new System.Windows.Forms.Padding(0); + this.cancelBtn.Name = "cancelBtn"; + this.cancelBtn.Size = new System.Drawing.Size(20, 20); + this.cancelBtn.TabIndex = 4; + this.cancelBtn.UseVisualStyleBackColor = false; + this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click); + // + // moveUpBtn + // + this.moveUpBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.moveUpBtn.BackColor = System.Drawing.Color.Transparent; + this.moveUpBtn.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("moveUpBtn.BackgroundImage"))); + this.moveUpBtn.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.moveUpBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.moveUpBtn.ForeColor = System.Drawing.SystemColors.Control; + this.moveUpBtn.Location = new System.Drawing.Point(347, 39); + this.moveUpBtn.Margin = new System.Windows.Forms.Padding(0); + this.moveUpBtn.Name = "moveUpBtn"; + this.moveUpBtn.Size = new System.Drawing.Size(25, 10); + this.moveUpBtn.TabIndex = 4; + this.moveUpBtn.UseVisualStyleBackColor = false; + this.moveUpBtn.Click += new System.EventHandler(this.moveUpBtn_Click); + // + // moveDownBtn + // + this.moveDownBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.moveDownBtn.BackColor = System.Drawing.Color.Transparent; + this.moveDownBtn.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("moveDownBtn.BackgroundImage"))); + this.moveDownBtn.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.moveDownBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.moveDownBtn.ForeColor = System.Drawing.SystemColors.Control; + this.moveDownBtn.Location = new System.Drawing.Point(347, 49); + this.moveDownBtn.Margin = new System.Windows.Forms.Padding(0); + this.moveDownBtn.Name = "moveDownBtn"; + this.moveDownBtn.Size = new System.Drawing.Size(25, 10); + this.moveDownBtn.TabIndex = 5; + this.moveDownBtn.UseVisualStyleBackColor = false; + this.moveDownBtn.Click += new System.EventHandler(this.moveDownBtn_Click); + // + // ProcessBookControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.ControlLight; + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Controls.Add(this.moveDownBtn); + this.Controls.Add(this.moveUpBtn); + this.Controls.Add(this.cancelBtn); + this.Controls.Add(this.label1); + this.Controls.Add(this.remainingTimeLbl); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.bookInfoLbl); + this.Controls.Add(this.pictureBox1); + this.Margin = new System.Windows.Forms.Padding(2, 1, 2, 1); + this.Name = "ProcessBookControl"; + this.Size = new System.Drawing.Size(375, 86); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label bookInfoLbl; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Label remainingTimeLbl; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button cancelBtn; + private System.Windows.Forms.Button moveUpBtn; + private System.Windows.Forms.Button moveDownBtn; + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs new file mode 100644 index 00000000..f0875715 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs @@ -0,0 +1,302 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using DataLayer; +using Dinah.Core.Net.Http; +using Dinah.Core.Threading; +using FileLiberator; +using LibationFileManager; +using LibationWinForms.BookLiberation; +using LibationWinForms.ProcessQueue; + +namespace LibationWinForms.ProcessQueue +{ + internal interface ILiberationBaseForm + { + Action CancelAction { get; set; } + Func MoveUpAction { get; set; } + Func MoveDownAction { get; set; } + void SetResult(ProcessBookResult status); + void SetQueuePosition(QueuePosition status); + void RegisterFileLiberator(Processable streamable, LogMe logMe); + void Processable_Begin(object sender, LibraryBook libraryBook); + int Width { get; set; } + int Height { get; set; } + Padding Margin { get; set; } + } + + internal partial class ProcessBookControl : UserControl, ILiberationBaseForm + { + public Action CancelAction { get; set; } + public Func MoveUpAction { get; set; } + public Func MoveDownAction { get; set; } + public string DecodeActionName { get; } = "Decoding"; + private Func GetCoverArtDelegate; + protected Processable Processable { get; private set; } + protected LogMe LogMe { get; private set; } + public ProcessBookControl() + { + InitializeComponent(); + label1.Text = "Queued"; + remainingTimeLbl.Visible = false; + progressBar1.Visible = false; + } + + public void SetResult(ProcessBookResult status) + { + var statusTxt = status switch + { + ProcessBookResult.Success => "Finished", + ProcessBookResult.Cancelled => "Cancelled", + ProcessBookResult.FailedRetry => "Error, Retry", + ProcessBookResult.FailedSkip => "Error, Skip", + ProcessBookResult.FailedAbort => "Error, Abort", + _ => throw new NotImplementedException(), + }; + + Color backColor = status switch + { + ProcessBookResult.Success => Color.PaleGreen, + ProcessBookResult.Cancelled => Color.Khaki, + ProcessBookResult.FailedRetry => Color.LightCoral, + ProcessBookResult.FailedSkip => Color.LightCoral, + ProcessBookResult.FailedAbort => Color.Firebrick, + _ => throw new NotImplementedException(), + }; + + this.UIThreadAsync(() => + { + cancelBtn.Visible = false; + moveDownBtn.Visible = false; + moveUpBtn.Visible = false; + remainingTimeLbl.Visible = false; + progressBar1.Visible = false; + label1.Text = statusTxt; + BackColor = backColor; + }); + } + + public ProcessBookControl(string title, Image cover) : this() + { + pictureBox1.Image = cover; + bookInfoLbl.Text = title; + } + + public void RegisterFileLiberator(Processable processable, LogMe logMe = null) + { + if (processable is null) return; + + Processable = processable; + LogMe = logMe; + + Subscribe((Streamable)processable); + Subscribe(processable); + if (processable is AudioDecodable audioDecodable) + Subscribe(audioDecodable); + } + + + #region Event Subscribers and Unsubscribers + private void Subscribe(Streamable streamable) + { + UnsubscribeStreamable(this, EventArgs.Empty); + + streamable.StreamingProgressChanged += Streamable_StreamingProgressChanged; + streamable.StreamingTimeRemaining += Streamable_StreamingTimeRemaining; + + Disposed += UnsubscribeStreamable; + } + private void Subscribe(Processable processable) + { + UnsubscribeProcessable(this, null); + + processable.Begin += Processable_Begin; + processable.Completed += Processable_Completed; + + //Don't unsubscribe from Dispose because it fires when + //Streamable.StreamingCompleted closes the form, and + //the Processable events need to live past that event. + processable.Completed += UnsubscribeProcessable; + } + private void Subscribe(AudioDecodable audioDecodable) + { + UnsubscribeAudioDecodable(this, EventArgs.Empty); + + audioDecodable.RequestCoverArt += AudioDecodable_RequestCoverArt; + audioDecodable.TitleDiscovered += AudioDecodable_TitleDiscovered; + audioDecodable.AuthorsDiscovered += AudioDecodable_AuthorsDiscovered; + audioDecodable.NarratorsDiscovered += AudioDecodable_NarratorsDiscovered; + audioDecodable.CoverImageDiscovered += AudioDecodable_CoverImageDiscovered; + + Disposed += UnsubscribeAudioDecodable; + } + private void UnsubscribeStreamable(object sender, EventArgs e) + { + Disposed -= UnsubscribeStreamable; + + Processable.StreamingProgressChanged -= Streamable_StreamingProgressChanged; + Processable.StreamingTimeRemaining -= Streamable_StreamingTimeRemaining; + } + private void UnsubscribeProcessable(object sender, LibraryBook e) + { + Processable.Completed -= UnsubscribeProcessable; + Processable.Begin -= Processable_Begin; + Processable.Completed -= Processable_Completed; + } + private void UnsubscribeAudioDecodable(object sender, EventArgs e) + { + if (Processable is not AudioDecodable audioDecodable) + return; + + Disposed -= UnsubscribeAudioDecodable; + audioDecodable.RequestCoverArt -= AudioDecodable_RequestCoverArt; + audioDecodable.TitleDiscovered -= AudioDecodable_TitleDiscovered; + audioDecodable.AuthorsDiscovered -= AudioDecodable_AuthorsDiscovered; + audioDecodable.NarratorsDiscovered -= AudioDecodable_NarratorsDiscovered; + audioDecodable.CoverImageDiscovered -= AudioDecodable_CoverImageDiscovered; + + audioDecodable.Cancel(); + } + #endregion + + #region Streamable event handlers + public void Streamable_StreamingProgressChanged(object sender, DownloadProgress downloadProgress) + { + if (!downloadProgress.ProgressPercentage.HasValue) + return; + + if (downloadProgress.ProgressPercentage == 0) + updateRemainingTime(0); + else + progressBar1.UIThreadAsync(() => progressBar1.Value = (int)downloadProgress.ProgressPercentage); + } + + public void Streamable_StreamingTimeRemaining(object sender, TimeSpan timeRemaining) + { + updateRemainingTime((int)timeRemaining.TotalSeconds); + } + + private void updateRemainingTime(int remaining) + => remainingTimeLbl.UIThreadAsync(() => remainingTimeLbl.Text = formatTime(remaining)); + + private string formatTime(int seconds) + { + var timeSpan = TimeSpan.FromSeconds(seconds); + return $"{timeSpan:mm\\:ss}"; + } + + #endregion + + #region Processable event handlers + public void Processable_Begin(object sender, LibraryBook libraryBook) + { + LogMe.Info($"{Environment.NewLine}{Processable.Name} Step, Begin: {libraryBook.Book}"); + + this.UIThreadAsync(() => + { + label1.Text = "ETA:"; + remainingTimeLbl.Visible = true; + progressBar1.Visible = true; + }); + + GetCoverArtDelegate = () => PictureStorage.GetPictureSynchronously( + new PictureDefinition( + libraryBook.Book.PictureId, + PictureSize._500x500)); + + //Set default values from library + AudioDecodable_TitleDiscovered(sender, libraryBook.Book.Title); + AudioDecodable_AuthorsDiscovered(sender, libraryBook.Book.AuthorNames()); + AudioDecodable_NarratorsDiscovered(sender, libraryBook.Book.NarratorNames()); + AudioDecodable_CoverImageDiscovered(sender, + PictureStorage.GetPicture( + new PictureDefinition( + libraryBook.Book.PictureId, + PictureSize._80x80)).bytes); + } + + public void Processable_Completed(object sender, LibraryBook libraryBook) + { + LogMe.Info($"{Processable.Name} Step, Completed: {libraryBook.Book}"); + } + + #endregion + + #region AudioDecodable event handlers + + private string title; + private string authorNames; + private string narratorNames; + public void AudioDecodable_TitleDiscovered(object sender, string title) + { + this.UIThreadAsync(() => this.Text = DecodeActionName + " " + title); + this.title = title; + updateBookInfo(); + } + + public void AudioDecodable_AuthorsDiscovered(object sender, string authors) + { + authorNames = authors; + updateBookInfo(); + } + + public void AudioDecodable_NarratorsDiscovered(object sender, string narrators) + { + narratorNames = narrators; + updateBookInfo(); + } + + private void updateBookInfo() + => bookInfoLbl.UIThreadAsync(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}"); + + public void AudioDecodable_RequestCoverArt(object sender, Action setCoverArtDelegate) + { + setCoverArtDelegate(GetCoverArtDelegate?.Invoke()); + } + + public void AudioDecodable_CoverImageDiscovered(object sender, byte[] coverArt) + { + pictureBox1.UIThreadAsync(() => pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(coverArt)); + } + #endregion + + private void cancelBtn_Click(object sender, EventArgs e) + { + CancelAction?.Invoke(); + } + + private void moveUpBtn_Click(object sender, EventArgs e) + { + HandleMovePositionResult(MoveUpAction?.Invoke()); + } + + + private void moveDownBtn_Click(object sender, EventArgs e) + { + HandleMovePositionResult(MoveDownAction?.Invoke()); + } + + private void HandleMovePositionResult(QueuePosition? result) + { + if (result.HasValue) + SetQueuePosition(result.Value); + else + SetQueuePosition(QueuePosition.Absent); + } + + public void SetQueuePosition(QueuePosition status) + { + if (status is QueuePosition.Absent or QueuePosition.Current) + { + moveUpBtn.Visible = false; + moveDownBtn.Visible = false; + } + + if (status == QueuePosition.Absent) + cancelBtn.Enabled = false; + + moveUpBtn.Enabled = status != QueuePosition.Fisrt; + moveDownBtn.Enabled = status != QueuePosition.Last; + } + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.resx b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.resx new file mode 100644 index 00000000..180633dc --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.resx @@ -0,0 +1,798 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + + True + + + + + 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 + /x9W31o+WFcHNAAAAABJRU5ErkJggg== + + + + True + + + + iVBORw0KGgoAAAANSUhEUgAAAKoAAABXCAYAAACUet5FAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1 + MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAACwwAAAsMAT9AIsgAAAQvSURBVHhe7dJLbutGFEVRtzKO + DCFDzhAzA4d5cCWKvSTxSvxUFU9jdQ7AugCxPz4/PyO6xzGiNxwrPj5/i59+xxagpoRjhY5f3J+LvxZ/ + 3Gxxh5oSjhU6fmH/RLr8mF8S6wpqSjhW6PhF3UbaJNYn1JRwrNDxC1KkTWJ9QE0Jxwodv5hHkTaJ9Q41 + JRwrdPxC1kTaJFZQU8KxQscvohJpk1i/UVPCsULHL+CVSJvEekNNCccKHZ/cO5E2ifWLmhKOFTo+sS0i + bRLrQk0Jxwodn9SWkTaXj1VNCccKHZ/QHpE2l45VTQnHCh2fzJ6RNpeNVU0Jxwodn8gRkTaXjFVNCccK + HZ/EkZE2l4tVTQnHCh2fwBmRNpeKVU0JxwodH9yZkTaXiVVNCccKHR9YD5E2l4hVTQnHCh0fVE+RNtPH + qqaEY4WOD6jHSJupY1VTwrFCxwfTc6TNtLGqKeFYoeMDGSHSZspY1ZRwrNDxQYwUaTNdrGpKOFbo+ABG + jLSZKlY1JRwrdLxzI0faTBOrmhKOFTresRkibaaIVU0Jxwod79RMkTbDx6qmhGOFjndoxkiboWNVU8Kx + Qsc7M3OkzbCxqinhWKHjHblCpM2Qsaop4Vih4524UqTNcLGqKeFYoeMduGKkzVCxqinhWKHjJ7typM0w + saop4Vih4ydKpP8ZIlY1JRwrdPwkifSn7mNVU8KxQsdPkEjv6zpWNSUcK3T8YIn0uW5jVVPCsULHD5RI + 1+syVjUlHCt0/CCJtK67WNWUcKzQ8QMk0td1FauaEo4VOr6zRPq+bmJVU8KxQsd3lEi300Wsako4Vuj4 + ThLp9k6PVU0Jxwod30Ei3c+psaop4Vih4xtLpPs7LVY1JRwrdHxDifQ4p8SqpoRjhY5vJJEe7/BY1ZRw + rNDxDSTS8xwaq5oSjhU6/qZEer7DYlVTwrFCx9+QSPtxSKxqSjhW6PiLEml/do9VTQnHCh1/QSLt166x + qinhWKHjRYm0f7vFqqaEY4WOFyTScewSq5oSjhU6vlIiHc/msaop4Vih4ysk0nFtGquaEo4VOv5EIh3f + ZrGqKeFYoeMPJNJ5bBKrmhKOFTp+RyKdz9uxqinhWKHjkEjn9Vasako4Vuj4N4l0fi/HqqaEY4WO30ik + 1/FSrGpKOFbo+JdEej3lWNWUcKzQ8UUiva5SrGpKOFbgeCKN1bGqKeFY8e1wIo1mVaxqSjhW3BxNpPHd + 01jVlHCs+DqYSOOeh7GqKeFYsRxLpPHM3VjVlHBcazmUSGMtxqquhOMay5FEGlU/YlVbwvGZ5UAijVf9 + L1b1JRwfWR5PpPGuf2NVY8LxnuXhRBpb+RWrOhOOsjyaSGNrq2Pl+N3yWCKNvayKleOt5ZFEGnt7GivH + Zvk4kcZRHsbKMaI3HCN6wzGiNxwjesMxojccI/ry+fE3PPmpZVCkxQEAAAAASUVORK5CYII= + + + + True + + + + iVBORw0KGgoAAAANSUhEUgAAAKoAAABXCAYAAACUet5FAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1 + MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAACwwAAAsMAT9AIsgAAAQ+SURBVHhe7dLLcRsxFERRrRyH + Q3DICtEZ0NOy6aKoq+H0fB+AXpxNVwFvc99ut1tEeThGVINjRDU4RlSDY0Q1OEZUg6O83X78mvyeTEPE + 4d6pwzsc76bHiTXOMBup4Pho+iSxxpFeRio4Pps+S6xxhEWRCo5k+jSxxp4WRyo4kunjxBp7sSIVHMn0 + eWKNPdiRCo5kOpBYY6tVkQqOZDryLLGGY3WkgiOZDpHEGktsilRwJNOx7yTWmPM+waYcOBIdm5FYg3xE + KtSUA0dyPzgjscaj/5EKNeXAkTwenZFYQz5FKtSUA0fyfHhGYh3bl0iFmnLgSOj4jMQ6JoxUqCkHjoSO + v5BYx/JtpEJNOXAkdHyBxDqG2UiFmnLgSOj4Qom1by8jFWrKgSOh44bE2qdFkQo15cCR0HFTYu3L4kiF + mnLgSOj4Com1D1akQk05cCR0fKXE2jY7UqGmHDgSOr5BYm3TqkiFmnLgSOj4Rom1LasjFWrKgSOh4ztI + rG3YFKlQUw4cCR3fSWKtbXOkQk05cCR0fEeJtaZdIhVqyoEjoeM7S6y17BapUFMOHAkdP0BirWHXSIWa + cuBI6PhBEuu1do9UqCkHjoSOHyixXuOQSIWacuBI6PjBEuu5DotUqCkHjoSOnyCxnuPQSIWacuBI6PhJ + EuuxDo9UqCkHjoSOnyixHuOUSIWacuBI6PjJEuu+TotUqCkHjoSOXyCx7uPUSIWacuBI6PhFEus2p0cq + 1JQDR0LHL5RY17kkUqGmHDgSOn6xxOq5LFKhphw4EjpeQGJd5tJIhZpy4EjoeBGJdd7lkQo15cCR0PFC + EisrEalQUw4cCR0vJrF+ViZSoaYcOBI6XlBi/atUpEJNOXAkdLyo0WMtF6lQUw4cCR0vbNRYS0Yq1JQD + R0LHixst1rKRCjXlwJHQ8QaMEmvpSIWacuBI6Hgjeo+1fKRCTTlwJHS8Ib3G2kSkQk05cCR0vDG9xdpM + pEJNOXAkdLxBvcTaVKRCTTlwJHS8Ua3H2lykQk05cCR0vGGtxtpkpEJNOXAkdLxxrcXabKRCTTlwJHS8 + A63E2nSkQk05cCR0vBPVY20+UqGmHDgSOt6RqrF2EalQUw4cCR3vTLVYu4lUqCkHjoSOd6hKrF1FKtSU + A0dCxzt1dazdRSrUlANHQsc7dlWsXUYq1JQDR0LHO3d2rN1GKtSUA0dCxwdwVqxdRyrUlANHQscHcXSs + 3Ucq1JQDR0LHB3JUrENEKtSUA0dCxwezd6zDRCrUlANHQscHtFesQ0Uq1JQDR0LHB7U11uEiFWrKgSOh + 4wNbG+uQkQo15cCR0PHBubEOG6lQUw4cCR2PxbEOHalQUw4cCR2PD69iHT5SoaYcOBI6Hv99F2si/Yea + cuBI6Hh88hxrIn1ATTlwJHQ8vrjHmkifUFMOHAkdD/QTtuFRUw4cI6rBMaKW29sfKR2pZX+g2KEAAAAA + SUVORK5CYII= + + + + True + + \ No newline at end of file diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookForm.Designer.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.Designer.cs new file mode 100644 index 00000000..036022fb --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.Designer.cs @@ -0,0 +1,47 @@ +namespace LibationWinForms.ProcessQueue +{ + partial class ProcessBookForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // ProcessBookForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(522, 638); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; + this.Name = "ProcessBookForm"; + this.Text = "ProcessBookForm"; + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookForm.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.cs new file mode 100644 index 00000000..ebdf2784 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibationWinForms.ProcessQueue +{ + public partial class ProcessBookForm : Form + { + private Control _dockControl; + public int WidthChange { get; set; } + public ProcessBookForm() + { + InitializeComponent(); + } + + public void PassControl(Control dockControl) + { + _dockControl = dockControl; + Controls.Add(_dockControl); + } + + public Control RegainControl() + { + Controls.Remove(_dockControl); + return _dockControl; + } + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookForm.resx b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.resx new file mode 100644 index 00000000..f298a7be --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookForm.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.Designer.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.Designer.cs new file mode 100644 index 00000000..62848fbe --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.Designer.cs @@ -0,0 +1,235 @@ +namespace LibationWinForms.ProcessQueue +{ + partial class ProcessBookQueue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripProgressBar1 = new System.Windows.Forms.ToolStripProgressBar(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.btnCleanFinished = new System.Windows.Forms.Button(); + this.cancelAllBtn = new System.Windows.Forms.Button(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.panel2 = new System.Windows.Forms.Panel(); + this.clearLogBtn = new System.Windows.Forms.Button(); + this.logMeTbox = new System.Windows.Forms.TextBox(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.statusStrip1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.panel2.SuspendLayout(); + this.SuspendLayout(); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripProgressBar1, + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 486); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(359, 22); + this.statusStrip1.TabIndex = 1; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripProgressBar1 + // + this.toolStripProgressBar1.Name = "toolStripProgressBar1"; + this.toolStripProgressBar1.Size = new System.Drawing.Size(100, 16); + // + // tabControl1 + // + this.tabControl1.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.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Margin = new System.Windows.Forms.Padding(0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(360, 486); + this.tabControl1.TabIndex = 3; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.flowLayoutPanel1); + this.tabPage1.Controls.Add(this.panel1); + this.tabPage1.Location = new System.Drawing.Point(4, 24); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(352, 458); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Process Queue"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.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.flowLayoutPanel1.AutoScroll = true; + this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.ControlDarkDark; + this.flowLayoutPanel1.Location = new System.Drawing.Point(3, 3); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(346, 419); + this.flowLayoutPanel1.TabIndex = 0; + this.flowLayoutPanel1.ClientSizeChanged += new System.EventHandler(this.flowLayoutPanel1_ClientSizeChanged); + this.flowLayoutPanel1.Layout += new System.Windows.Forms.LayoutEventHandler(this.flowLayoutPanel1_Layout); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ControlDark; + this.panel1.Controls.Add(this.btnCleanFinished); + this.panel1.Controls.Add(this.cancelAllBtn); + this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel1.Location = new System.Drawing.Point(3, 425); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(346, 30); + this.panel1.TabIndex = 2; + // + // btnCleanFinished + // + this.btnCleanFinished.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnCleanFinished.Location = new System.Drawing.Point(253, 3); + this.btnCleanFinished.Name = "btnCleanFinished"; + this.btnCleanFinished.Size = new System.Drawing.Size(90, 23); + this.btnCleanFinished.TabIndex = 3; + this.btnCleanFinished.Text = "Clear Finished"; + this.btnCleanFinished.UseVisualStyleBackColor = true; + this.btnCleanFinished.Click += new System.EventHandler(this.btnCleanFinished_Click); + // + // cancelAllBtn + // + this.cancelAllBtn.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.cancelAllBtn.Location = new System.Drawing.Point(3, 3); + this.cancelAllBtn.Name = "cancelAllBtn"; + this.cancelAllBtn.Size = new System.Drawing.Size(75, 23); + this.cancelAllBtn.TabIndex = 2; + this.cancelAllBtn.Text = "Cancel All"; + this.cancelAllBtn.UseVisualStyleBackColor = true; + this.cancelAllBtn.Click += new System.EventHandler(this.cancelAllBtn_Click); + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.panel2); + this.tabPage2.Controls.Add(this.logMeTbox); + this.tabPage2.Location = new System.Drawing.Point(4, 24); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(352, 458); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Log"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // panel2 + // + this.panel2.BackColor = System.Drawing.SystemColors.ControlDark; + this.panel2.Controls.Add(this.clearLogBtn); + this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel2.Location = new System.Drawing.Point(3, 425); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(346, 30); + this.panel2.TabIndex = 1; + // + // clearLogBtn + // + this.clearLogBtn.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.clearLogBtn.Location = new System.Drawing.Point(3, 3); + this.clearLogBtn.Name = "clearLogBtn"; + this.clearLogBtn.Size = new System.Drawing.Size(75, 23); + this.clearLogBtn.TabIndex = 0; + this.clearLogBtn.Text = "Clear Log"; + this.clearLogBtn.UseVisualStyleBackColor = true; + this.clearLogBtn.Click += new System.EventHandler(this.clearLogBtn_Click); + // + // logMeTbox + // + this.logMeTbox.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.logMeTbox.Location = new System.Drawing.Point(3, 3); + this.logMeTbox.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0); + this.logMeTbox.MaxLength = 10000000; + this.logMeTbox.Multiline = true; + this.logMeTbox.Name = "logMeTbox"; + this.logMeTbox.ReadOnly = true; + this.logMeTbox.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.logMeTbox.Size = new System.Drawing.Size(346, 419); + this.logMeTbox.TabIndex = 0; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(211, 17); + this.toolStripStatusLabel1.Spring = true; + // + // ProcessBookQueue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.statusStrip1); + this.Name = "ProcessBookQueue"; + this.Size = new System.Drawing.Size(359, 508); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.panel1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabPage2.PerformLayout(); + this.panel2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.TextBox logMeTbox; + private System.Windows.Forms.Button btnCleanFinished; + private System.Windows.Forms.Button cancelAllBtn; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.Button clearLogBtn; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.cs new file mode 100644 index 00000000..af748764 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.cs @@ -0,0 +1,343 @@ +using DataLayer; +using Dinah.Core.Threading; +using LibationWinForms.BookLiberation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibationWinForms.ProcessQueue +{ + internal partial class ProcessBookQueue : UserControl, ILogForm + { + private ProcessBook CurrentBook; + private readonly LinkedList BookQueue = new(); + private readonly List CompletedBooks = new(); + private readonly LogMe Logger; + private readonly object lockObject = new(); + + + public Task QueueRunner { get; private set; } + public bool Running => !QueueRunner?.IsCompleted ?? false; + + public ToolStripButton popoutBtn = new(); + + public ProcessBookQueue() + { + InitializeComponent(); + Logger = LogMe.RegisterForm(this); + + + this.popoutBtn.DisplayStyle = ToolStripItemDisplayStyle.Text; + this.popoutBtn.Name = "popoutBtn"; + this.popoutBtn.Text = "Pop Out"; + this.popoutBtn.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.popoutBtn.Alignment = ToolStripItemAlignment.Right; + this.popoutBtn.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + + statusStrip1.Items.Add(popoutBtn); + } + public async Task AddDownloadDecrypt(IEnumerable entries) + { + foreach (var entry in entries) + await AddDownloadDecryptAsync(entry); + } + + public async Task AddDownloadDecryptAsync(GridEntry gridEntry) + { + if (BookExists(gridEntry.LibraryBook)) + return; + + ProcessBook pbook = new ProcessBook(gridEntry, Logger); + pbook.Completed += Pbook_Completed; + pbook.Cancelled += Pbook_Cancelled; + pbook.RequestMove += (o,d) => RequestMove(o, d); + + var libStatus = gridEntry.Liberate; + + if (libStatus.BookStatus != LiberatedStatus.Liberated) + pbook.AddDownloadDecryptProcessable(); + + if (libStatus.PdfStatus != LiberatedStatus.Liberated) + pbook.AddPdfProcessable(); + + EnqueueBook(pbook); + + await AddBookControlAsync(pbook.BookControl); + + if (!Running) + { + QueueRunner = QueueLoop(); + } + } + + private async void Pbook_Cancelled(ProcessBook sender, EventArgs e) + { + lock (lockObject) + { + if (BookQueue.Contains(sender)) + BookQueue.Remove(sender); + } + await RemoveBookControlAsync(sender.BookControl); + } + + /// + /// Handles requests by to change its order in the queue + /// + /// The requesting + /// The requested position + /// The resultant position + private QueuePosition RequestMove(ProcessBook sender, QueuePosition direction) + { + var node = BookQueue.Find(sender); + + if (node == null || direction == QueuePosition.Absent) + return QueuePosition.Absent; + if (CurrentBook != null && CurrentBook == sender) + return QueuePosition.Current; + if ((direction == QueuePosition.Fisrt || direction == QueuePosition.OneUp) && BookQueue.First.Value == sender) + return QueuePosition.Fisrt; + if ((direction == QueuePosition.Last || direction == QueuePosition.OneDown) && BookQueue.Last.Value == sender) + return QueuePosition.Last; + + if (direction == QueuePosition.OneUp) + { + var oneUp = node.Previous; + BookQueue.Remove(node); + BookQueue.AddBefore(oneUp, node.Value); + } + else if (direction == QueuePosition.OneDown) + { + var oneDown = node.Next; + BookQueue.Remove(node); + BookQueue.AddAfter(oneDown, node.Value); + } + else if (direction == QueuePosition.Fisrt) + { + BookQueue.Remove(node); + BookQueue.AddFirst(node); + } + else + { + BookQueue.Remove(node); + BookQueue.AddLast(node); + } + + var index = flowLayoutPanel1.Controls.IndexOf((Control)sender.BookControl); + + index = direction switch + { + QueuePosition.Fisrt => 0, + QueuePosition.OneUp => index - 1, + QueuePosition.OneDown => index + 1, + QueuePosition.Last => flowLayoutPanel1.Controls.Count - 1, + _ => throw new NotImplementedException(), + }; + + flowLayoutPanel1.Controls.SetChildIndex((Control)sender.BookControl, index); + + if (index == 0) return QueuePosition.Fisrt; + if (index == flowLayoutPanel1.Controls.Count - 1) return QueuePosition.Last; + return direction; + } + + private async Task QueueLoop() + { + while (MoreInQueue()) + { + var nextBook = NextBook(); + nextBook.BookControl.SetQueuePosition(QueuePosition.Current); + PeekBook()?.BookControl.SetQueuePosition(QueuePosition.Fisrt); + + var result = await nextBook.ProcessOneAsync(); + + AddCompletedBook(nextBook); + + switch (result) + { + case ProcessBookResult.FailedRetry: + EnqueueBook(nextBook); + break; + case ProcessBookResult.FailedAbort: + return; + } + } + } + + private bool BookExists(LibraryBook libraryBook) + { + lock (lockObject) + { + return CurrentBook?.Entry?.AudibleProductId == libraryBook.Book.AudibleProductId || + CompletedBooks.Union(BookQueue).Any(p => p.Entry.AudibleProductId == libraryBook.Book.AudibleProductId); + } + } + + private ProcessBook NextBook() + { + lock (lockObject) + { + CurrentBook = BookQueue.First.Value; + BookQueue.RemoveFirst(); + return CurrentBook; + } + } + private ProcessBook PeekBook() + { + lock (lockObject) + return BookQueue.Count > 0 ? BookQueue.First.Value : default; + } + + private void EnqueueBook(ProcessBook pbook) + { + lock (lockObject) + BookQueue.AddLast(pbook); + } + + private void AddCompletedBook(ProcessBook pbook) + { + lock (lockObject) + CompletedBooks.Add(pbook); + } + + private bool MoreInQueue() + { + lock (lockObject) + return BookQueue.Count > 0; + } + + + private void Pbook_Completed(object sender, EventArgs e) + { + if (CurrentBook == sender) + CurrentBook = default; + } + + private async void cancelAllBtn_Click(object sender, EventArgs e) + { + List l1 = new(); + lock (lockObject) + { + l1.AddRange(BookQueue); + BookQueue.Clear(); + } + CurrentBook?.Cancel(); + CurrentBook = default; + + await RemoveBookControlsAsync(l1.Select(l => l.BookControl)); + } + + private async void btnCleanFinished_Click(object sender, EventArgs e) + { + List l1 = new(); + lock (lockObject) + { + l1.AddRange(CompletedBooks); + CompletedBooks.Clear(); + } + + await RemoveBookControlsAsync(l1.Select(l => l.BookControl)); + } + + private async Task AddBookControlAsync(ILiberationBaseForm control) + { + await Task.Run(() => Invoke(() => + { + SetBookControlWidth((Control)control); + flowLayoutPanel1.Controls.Add((Control)control); + flowLayoutPanel1.SetFlowBreak((Control)control, true); + Refresh(); + })); + } + + private async Task RemoveBookControlAsync(ILiberationBaseForm control) + { + await Task.Run(() => Invoke(() => + { + flowLayoutPanel1.Controls.Remove((Control)control); + })); + } + + private async Task RemoveBookControlsAsync(IEnumerable control) + { + await Task.Run(() => Invoke(() => + { + SuspendLayout(); + foreach (var l in control) + flowLayoutPanel1.Controls.Remove((Control)l); + ResumeLayout(); + })); + } + + public void WriteLine(string text) + { + if (!IsDisposed) + logMeTbox.UIThreadAsync(() => logMeTbox.AppendText($"{DateTime.Now} {text}{Environment.NewLine}")); + } + + private void clearLogBtn_Click(object sender, EventArgs e) + { + logMeTbox.Clear(); + } + + [DllImport("user32.dll", EntryPoint = "GetWindowLong")] + private static extern long GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll")] + private static extern bool ShowScrollBar(IntPtr hWnd, SBOrientation bar, bool show); + + public const int WS_VSCROLL = 0x200000; + public const int WS_HSCROLL = 0x100000; + enum SBOrientation : int + { + SB_HORZ = 0, + SB_VERT = 1, + SB_CTL = 2, + SB_BOTH = 3 + } + + private void flowLayoutPanel1_ClientSizeChanged(object sender, EventArgs e) + { + ReorderControls(); + } + + private void flowLayoutPanel1_Layout(object sender, LayoutEventArgs e) + { + ReorderControls(); + } + + bool V_SHOWN = false; + + private void ReorderControls() + { + bool hShown = (GetWindowLongPtr(flowLayoutPanel1.Handle, -16) & WS_HSCROLL) != 0; + bool vShown = (GetWindowLongPtr(flowLayoutPanel1.Handle, -16) & WS_VSCROLL) != 0; + + if (hShown) + ShowScrollBar(flowLayoutPanel1.Handle, SBOrientation.SB_HORZ, false); + + if (vShown != V_SHOWN) + { + flowLayoutPanel1.SuspendLayout(); + + foreach (Control c in flowLayoutPanel1.Controls) + SetBookControlWidth(c); + + flowLayoutPanel1.ResumeLayout(); + V_SHOWN = vShown; + } + } + + private void SetBookControlWidth(Control book) + { + book.Width = flowLayoutPanel1.ClientRectangle.Width - book.Margin.Left - book.Margin.Right; + } + + private void toolStripSplitButton1_ButtonClick(object sender, EventArgs e) + { + + } + } +} diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.resx b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.resx new file mode 100644 index 00000000..5cb320f3 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookQueue.resx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Source/LibationWinForms/grid/ProductsGrid.cs b/Source/LibationWinForms/grid/ProductsGrid.cs index 842576cc..76fe8f42 100644 --- a/Source/LibationWinForms/grid/ProductsGrid.cs +++ b/Source/LibationWinForms/grid/ProductsGrid.cs @@ -16,6 +16,7 @@ using LibationWinForms.Dialogs; namespace LibationWinForms { + #region // legacy instructions to update data_grid_view // INSTRUCTIONS TO UPDATE DATA_GRID_VIEW // - delete current DataGridView @@ -51,12 +52,12 @@ namespace LibationWinForms _dataGridView.Sorted += Filter; _dataGridView.CellContentClick += DataGridView_CellContentClick; - this.Load += ProductsGrid_Load; + this.Load += ProductsGrid_Load; EnableDoubleBuffering(); } - private void EnableDoubleBuffering() + private void EnableDoubleBuffering() { var propertyInfo = _dataGridView.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);