Code Cleanup
This commit is contained in:
parent
95766a43c5
commit
ef35c2aee9
@ -13,7 +13,7 @@
|
|||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
<Version>5.4.9.120</Version>
|
<Version>5.4.9.140</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|||||||
@ -4,34 +4,34 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
public abstract class AsyncNotifyPropertyChanged : INotifyPropertyChanged
|
public abstract class AsyncNotifyPropertyChanged : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
private int InstanceThreadId { get; } = Thread.CurrentThread.ManagedThreadId;
|
private int InstanceThreadId { get; } = Thread.CurrentThread.ManagedThreadId;
|
||||||
private bool InvokeRequired => Thread.CurrentThread.ManagedThreadId != InstanceThreadId;
|
private bool InvokeRequired => Thread.CurrentThread.ManagedThreadId != InstanceThreadId;
|
||||||
private SynchronizationContext SyncContext { get; } = SynchronizationContext.Current;
|
private SynchronizationContext SyncContext { get; } = SynchronizationContext.Current;
|
||||||
|
|
||||||
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
||||||
{
|
{
|
||||||
var propertyChangedArgs = new PropertyChangedEventArgs(propertyName);
|
var propertyChangedArgs = new PropertyChangedEventArgs(propertyName);
|
||||||
|
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
{
|
{
|
||||||
SyncContext.Post(
|
SyncContext.Post(
|
||||||
PostPropertyChangedCallback,
|
PostPropertyChangedCallback,
|
||||||
new AsyncCompletedEventArgs(null, false, propertyChangedArgs));
|
new AsyncCompletedEventArgs(null, false, propertyChangedArgs));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnPropertyChanged(propertyChangedArgs);
|
OnPropertyChanged(propertyChangedArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void PostPropertyChangedCallback(object asyncArgs)
|
private void PostPropertyChangedCallback(object asyncArgs)
|
||||||
{
|
{
|
||||||
var e = asyncArgs as AsyncCompletedEventArgs;
|
var e = asyncArgs as AsyncCompletedEventArgs;
|
||||||
|
|
||||||
OnPropertyChanged(e.UserState as PropertyChangedEventArgs);
|
OnPropertyChanged(e.UserState as PropertyChangedEventArgs);
|
||||||
}
|
}
|
||||||
private void OnPropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);
|
private void OnPropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,34 @@
|
|||||||
using System;
|
using Dinah.Core.Windows.Forms;
|
||||||
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core.Windows.Forms;
|
|
||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
public partial class AutomatedBackupsForm : Form
|
public partial class AutomatedBackupsForm : Form
|
||||||
{
|
{
|
||||||
public bool KeepGoingChecked => keepGoingCb.Checked;
|
public bool KeepGoingChecked => keepGoingCb.Checked;
|
||||||
|
|
||||||
public bool KeepGoing => keepGoingCb.Enabled && keepGoingCb.Checked;
|
public bool KeepGoing => keepGoingCb.Enabled && keepGoingCb.Checked;
|
||||||
|
|
||||||
public AutomatedBackupsForm()
|
public AutomatedBackupsForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteLine(string text)
|
public void WriteLine(string text)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
logTb.UIThread(() => logTb.AppendText($"{DateTime.Now} {text}{Environment.NewLine}"));
|
logTb.UIThread(() => logTb.AppendText($"{DateTime.Now} {text}{Environment.NewLine}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FinalizeUI()
|
public void FinalizeUI()
|
||||||
{
|
{
|
||||||
keepGoingCb.Enabled = false;
|
keepGoingCb.Enabled = false;
|
||||||
|
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
logTb.AppendText("");
|
logTb.AppendText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AutomatedBackupsForm_FormClosing(object sender, FormClosingEventArgs e) => keepGoingCb.Checked = false;
|
private void AutomatedBackupsForm_FormClosing(object sender, FormClosingEventArgs e) => keepGoingCb.Checked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,54 +1,54 @@
|
|||||||
using System;
|
using Dinah.Core.Windows.Forms;
|
||||||
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core.Windows.Forms;
|
|
||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
public partial class DecryptForm : Form
|
public partial class DecryptForm : Form
|
||||||
{
|
{
|
||||||
public DecryptForm() => InitializeComponent();
|
public DecryptForm() => InitializeComponent();
|
||||||
|
|
||||||
// book info
|
// book info
|
||||||
private string title;
|
private string title;
|
||||||
private string authorNames;
|
private string authorNames;
|
||||||
private string narratorNames;
|
private string narratorNames;
|
||||||
|
|
||||||
public void SetTitle(string actionName, string title)
|
public void SetTitle(string actionName, string title)
|
||||||
{
|
{
|
||||||
this.UIThread(() => this.Text = actionName + " " + title);
|
this.UIThread(() => this.Text = actionName + " " + title);
|
||||||
this.title = title;
|
this.title = title;
|
||||||
updateBookInfo();
|
updateBookInfo();
|
||||||
}
|
}
|
||||||
public void SetAuthorNames(string authorNames)
|
public void SetAuthorNames(string authorNames)
|
||||||
{
|
{
|
||||||
this.authorNames = authorNames;
|
this.authorNames = authorNames;
|
||||||
updateBookInfo();
|
updateBookInfo();
|
||||||
}
|
}
|
||||||
public void SetNarratorNames(string narratorNames)
|
public void SetNarratorNames(string narratorNames)
|
||||||
{
|
{
|
||||||
this.narratorNames = narratorNames;
|
this.narratorNames = narratorNames;
|
||||||
updateBookInfo();
|
updateBookInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread-safe UI updates
|
// thread-safe UI updates
|
||||||
private void updateBookInfo()
|
private void updateBookInfo()
|
||||||
=> bookInfoLbl.UIThread(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}");
|
=> bookInfoLbl.UIThread(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}");
|
||||||
|
|
||||||
public void SetCoverImage(System.Drawing.Image coverImage)
|
public void SetCoverImage(System.Drawing.Image coverImage)
|
||||||
=> pictureBox1.UIThread(() => pictureBox1.Image = coverImage);
|
=> pictureBox1.UIThread(() => pictureBox1.Image = coverImage);
|
||||||
|
|
||||||
public void UpdateProgress(int percentage)
|
public void UpdateProgress(int percentage)
|
||||||
{
|
{
|
||||||
if (percentage == 0)
|
if (percentage == 0)
|
||||||
updateRemainingTime(0);
|
updateRemainingTime(0);
|
||||||
else
|
else
|
||||||
progressBar1.UIThread(() => progressBar1.Value = percentage);
|
progressBar1.UIThread(() => progressBar1.Value = percentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateRemainingTime(TimeSpan remaining)
|
public void UpdateRemainingTime(TimeSpan remaining)
|
||||||
=> updateRemainingTime((int)remaining.TotalSeconds);
|
=> updateRemainingTime((int)remaining.TotalSeconds);
|
||||||
|
|
||||||
private void updateRemainingTime(int remaining)
|
private void updateRemainingTime(int remaining)
|
||||||
=> remainingTimeLbl.UIThread(() => remainingTimeLbl.Text = $"ETA:\r\n{remaining} sec");
|
=> remainingTimeLbl.UIThread(() => remainingTimeLbl.Text = $"ETA:\r\n{remaining} sec");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,59 +1,59 @@
|
|||||||
using System;
|
using Dinah.Core.Windows.Forms;
|
||||||
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core.Windows.Forms;
|
|
||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
public partial class DownloadForm : Form
|
public partial class DownloadForm : Form
|
||||||
{
|
{
|
||||||
public DownloadForm()
|
public DownloadForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
progressLbl.Text = "";
|
progressLbl.Text = "";
|
||||||
filenameLbl.Text = "";
|
filenameLbl.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread-safe UI updates
|
// thread-safe UI updates
|
||||||
public void UpdateFilename(string title) => filenameLbl.UIThread(() => filenameLbl.Text = title);
|
public void UpdateFilename(string title) => filenameLbl.UIThread(() => filenameLbl.Text = title);
|
||||||
|
|
||||||
public void DownloadProgressChanged(long BytesReceived, long? TotalBytesToReceive)
|
public void DownloadProgressChanged(long BytesReceived, long? TotalBytesToReceive)
|
||||||
{
|
{
|
||||||
// this won't happen with download file. it will happen with download string
|
// this won't happen with download file. it will happen with download string
|
||||||
if (!TotalBytesToReceive.HasValue || TotalBytesToReceive.Value <= 0)
|
if (!TotalBytesToReceive.HasValue || TotalBytesToReceive.Value <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
progressLbl.UIThread(() => progressLbl.Text = $"{BytesReceived:#,##0} of {TotalBytesToReceive.Value:#,##0}");
|
progressLbl.UIThread(() => progressLbl.Text = $"{BytesReceived:#,##0} of {TotalBytesToReceive.Value:#,##0}");
|
||||||
|
|
||||||
var d = double.Parse(BytesReceived.ToString()) / double.Parse(TotalBytesToReceive.Value.ToString()) * 100.0;
|
var d = double.Parse(BytesReceived.ToString()) / double.Parse(TotalBytesToReceive.Value.ToString()) * 100.0;
|
||||||
var i = int.Parse(Math.Truncate(d).ToString());
|
var i = int.Parse(Math.Truncate(d).ToString());
|
||||||
progressBar1.UIThread(() => progressBar1.Value = i);
|
progressBar1.UIThread(() => progressBar1.Value = i);
|
||||||
|
|
||||||
lastDownloadProgress = DateTime.Now;
|
lastDownloadProgress = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region timer
|
#region timer
|
||||||
private Timer timer { get; } = new Timer { Interval = 1000 };
|
private Timer timer { get; } = new Timer { Interval = 1000 };
|
||||||
private void DownloadForm_Load(object sender, EventArgs e)
|
private void DownloadForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
timer.Tick += new EventHandler(timer_Tick);
|
timer.Tick += new EventHandler(timer_Tick);
|
||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
private DateTime lastDownloadProgress = DateTime.Now;
|
private DateTime lastDownloadProgress = DateTime.Now;
|
||||||
private void timer_Tick(object sender, EventArgs e)
|
private void timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// if no update in the last 30 seconds, display frozen label
|
// if no update in the last 30 seconds, display frozen label
|
||||||
lastUpdateLbl.UIThread(() => lastUpdateLbl.Visible = lastDownloadProgress.AddSeconds(30) < DateTime.Now);
|
lastUpdateLbl.UIThread(() => lastUpdateLbl.Visible = lastDownloadProgress.AddSeconds(30) < DateTime.Now);
|
||||||
if (lastUpdateLbl.Visible)
|
if (lastUpdateLbl.Visible)
|
||||||
{
|
{
|
||||||
var diff = DateTime.Now - lastDownloadProgress;
|
var diff = DateTime.Now - lastDownloadProgress;
|
||||||
var min = (int)diff.TotalMinutes;
|
var min = (int)diff.TotalMinutes;
|
||||||
var minText = min > 0 ? $"{min}min " : "";
|
var minText = min > 0 ? $"{min}min " : "";
|
||||||
|
|
||||||
lastUpdateLbl.UIThread(() => lastUpdateLbl.Text = $"Frozen? Last download activity: {minText}{diff.Seconds}sec ago");
|
lastUpdateLbl.UIThread(() => lastUpdateLbl.Text = $"Frozen? Last download activity: {minText}{diff.Seconds}sec ago");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void DownloadForm_FormClosing(object sender, FormClosingEventArgs e) => timer.Stop();
|
private void DownloadForm_FormClosing(object sender, FormClosingEventArgs e) => timer.Stop();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,21 @@
|
|||||||
using System;
|
using AudibleApi;
|
||||||
|
using InternalUtilities;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using AudibleApi;
|
|
||||||
using InternalUtilities;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class AccountsDialog : Form
|
public partial class AccountsDialog : Form
|
||||||
{
|
{
|
||||||
const string COL_Delete = nameof(DeleteAccount);
|
private const string COL_Delete = nameof(DeleteAccount);
|
||||||
const string COL_LibraryScan = nameof(LibraryScan);
|
private const string COL_LibraryScan = nameof(LibraryScan);
|
||||||
const string COL_AccountId = nameof(AccountId);
|
private const string COL_AccountId = nameof(AccountId);
|
||||||
const string COL_AccountName = nameof(AccountName);
|
private const string COL_AccountName = nameof(AccountName);
|
||||||
const string COL_Locale = nameof(Locale);
|
private const string COL_Locale = nameof(Locale);
|
||||||
|
|
||||||
Form1 _parent { get; }
|
private Form1 _parent { get; }
|
||||||
|
|
||||||
public AccountsDialog(Form1 parent)
|
public AccountsDialog(Form1 parent)
|
||||||
{
|
{
|
||||||
@ -100,7 +100,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
this.Close();
|
this.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountDto
|
private class AccountDto
|
||||||
{
|
{
|
||||||
public string AccountId { get; set; }
|
public string AccountId { get; set; }
|
||||||
public string AccountName { get; set; }
|
public string AccountName { get; set; }
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -3,25 +3,25 @@ using System.Windows.Forms;
|
|||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class BookDetailsDialog : Form
|
public partial class BookDetailsDialog : Form
|
||||||
{
|
{
|
||||||
public string NewTags { get; private set; }
|
public string NewTags { get; private set; }
|
||||||
|
|
||||||
public BookDetailsDialog()
|
public BookDetailsDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
public BookDetailsDialog(string title, string rawTags) : this()
|
public BookDetailsDialog(string title, string rawTags) : this()
|
||||||
{
|
{
|
||||||
this.Text = $"Edit Tags - {title}";
|
this.Text = $"Edit Tags - {title}";
|
||||||
|
|
||||||
this.newTagsTb.Text = rawTags;
|
this.newTagsTb.Text = rawTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveBtn_Click(object sender, EventArgs e)
|
private void SaveBtn_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
NewTags = this.newTagsTb.Text;
|
NewTags = this.newTagsTb.Text;
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
using System;
|
using FileManager;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core;
|
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<root>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
using System;
|
using Dinah.Core;
|
||||||
|
using FileManager;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core;
|
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
@ -13,7 +13,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
{
|
{
|
||||||
public string Description { get; }
|
public string Description { get; }
|
||||||
public Configuration.KnownDirectories Value { get; }
|
public Configuration.KnownDirectories Value { get; }
|
||||||
private DirectorySelectControl _parentControl;
|
private readonly DirectorySelectControl _parentControl;
|
||||||
|
|
||||||
public string FullPath => _parentControl.AddSubDirectoryToPath(Configuration.GetKnownDirectoryPath(Value));
|
public string FullPath => _parentControl.AddSubDirectoryToPath(Configuration.GetKnownDirectoryPath(Value));
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<root>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,101 +1,100 @@
|
|||||||
using System;
|
using FileManager;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class EditQuickFilters : Form
|
public partial class EditQuickFilters : Form
|
||||||
{
|
{
|
||||||
const string BLACK_UP_POINTING_TRIANGLE = "\u25B2";
|
private const string BLACK_UP_POINTING_TRIANGLE = "\u25B2";
|
||||||
const string BLACK_DOWN_POINTING_TRIANGLE = "\u25BC";
|
private const string BLACK_DOWN_POINTING_TRIANGLE = "\u25BC";
|
||||||
|
private const string COL_Original = nameof(Original);
|
||||||
|
private const string COL_Delete = nameof(Delete);
|
||||||
|
private const string COL_Filter = nameof(Filter);
|
||||||
|
private const string COL_MoveUp = nameof(MoveUp);
|
||||||
|
private const string COL_MoveDown = nameof(MoveDown);
|
||||||
|
|
||||||
const string COL_Original = nameof(Original);
|
private Form1 _parent { get; }
|
||||||
const string COL_Delete = nameof(Delete);
|
|
||||||
const string COL_Filter = nameof(Filter);
|
|
||||||
const string COL_MoveUp = nameof(MoveUp);
|
|
||||||
const string COL_MoveDown = nameof(MoveDown);
|
|
||||||
|
|
||||||
Form1 _parent { get; }
|
public EditQuickFilters(Form1 parent)
|
||||||
|
{
|
||||||
|
_parent = parent;
|
||||||
|
|
||||||
public EditQuickFilters(Form1 parent)
|
InitializeComponent();
|
||||||
{
|
|
||||||
_parent = parent;
|
|
||||||
|
|
||||||
InitializeComponent();
|
dataGridView1.Columns[COL_Filter].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
|
||||||
|
|
||||||
dataGridView1.Columns[COL_Filter].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
|
populateGridValues();
|
||||||
|
}
|
||||||
|
|
||||||
populateGridValues();
|
private void populateGridValues()
|
||||||
}
|
{
|
||||||
|
var filters = QuickFilters.Filters;
|
||||||
|
if (!filters.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
private void populateGridValues()
|
foreach (var filter in filters)
|
||||||
{
|
dataGridView1.Rows.Add(filter, "X", filter, BLACK_UP_POINTING_TRIANGLE, BLACK_DOWN_POINTING_TRIANGLE);
|
||||||
var filters = QuickFilters.Filters;
|
}
|
||||||
if (!filters.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var filter in filters)
|
private void dataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
|
||||||
dataGridView1.Rows.Add(filter, "X", filter, BLACK_UP_POINTING_TRIANGLE, BLACK_DOWN_POINTING_TRIANGLE);
|
{
|
||||||
}
|
e.Row.Cells[COL_Delete].Value = "X";
|
||||||
|
e.Row.Cells[COL_MoveUp].Value = BLACK_UP_POINTING_TRIANGLE;
|
||||||
|
e.Row.Cells[COL_MoveDown].Value = BLACK_DOWN_POINTING_TRIANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
private void dataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
|
private void saveBtn_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
e.Row.Cells[COL_Delete].Value = "X";
|
var list = dataGridView1.Rows
|
||||||
e.Row.Cells[COL_MoveUp].Value = BLACK_UP_POINTING_TRIANGLE;
|
.OfType<DataGridViewRow>()
|
||||||
e.Row.Cells[COL_MoveDown].Value = BLACK_DOWN_POINTING_TRIANGLE;
|
.Select(r => r.Cells[COL_Filter].Value?.ToString())
|
||||||
}
|
.ToList();
|
||||||
|
QuickFilters.ReplaceAll(list);
|
||||||
|
|
||||||
private void saveBtn_Click(object sender, EventArgs e)
|
_parent.UpdateFilterDropDown();
|
||||||
{
|
this.DialogResult = DialogResult.OK;
|
||||||
var list = dataGridView1.Rows
|
this.Close();
|
||||||
.OfType<DataGridViewRow>()
|
}
|
||||||
.Select(r => r.Cells[COL_Filter].Value?.ToString())
|
|
||||||
.ToList();
|
|
||||||
QuickFilters.ReplaceAll(list);
|
|
||||||
|
|
||||||
_parent.UpdateFilterDropDown();
|
private void cancelBtn_Click(object sender, EventArgs e)
|
||||||
this.DialogResult = DialogResult.OK;
|
{
|
||||||
this.Close();
|
this.DialogResult = DialogResult.Cancel;
|
||||||
}
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
private void cancelBtn_Click(object sender, EventArgs e)
|
private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||||
{
|
{
|
||||||
this.DialogResult = DialogResult.Cancel;
|
var dgv = (DataGridView)sender;
|
||||||
this.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
var col = dgv.Columns[e.ColumnIndex];
|
||||||
{
|
if (col is DataGridViewButtonColumn && e.RowIndex >= 0)
|
||||||
var dgv = (DataGridView)sender;
|
{
|
||||||
|
var row = dgv.Rows[e.RowIndex];
|
||||||
var col = dgv.Columns[e.ColumnIndex];
|
switch (col.Name)
|
||||||
if (col is DataGridViewButtonColumn && e.RowIndex >= 0)
|
{
|
||||||
{
|
case COL_Delete:
|
||||||
var row = dgv.Rows[e.RowIndex];
|
// if final/edit row: do nothing
|
||||||
switch (col.Name)
|
if (e.RowIndex < dgv.RowCount - 1)
|
||||||
{
|
dgv.Rows.Remove(row);
|
||||||
case COL_Delete:
|
break;
|
||||||
// if final/edit row: do nothing
|
case COL_MoveUp:
|
||||||
if (e.RowIndex < dgv.RowCount - 1)
|
// if top: do nothing
|
||||||
dgv.Rows.Remove(row);
|
if (e.RowIndex < 1)
|
||||||
break;
|
break;
|
||||||
case COL_MoveUp:
|
dgv.Rows.Remove(row);
|
||||||
// if top: do nothing
|
dgv.Rows.Insert(e.RowIndex - 1, row);
|
||||||
if (e.RowIndex < 1)
|
break;
|
||||||
break;
|
case COL_MoveDown:
|
||||||
dgv.Rows.Remove(row);
|
// if final/edit row or bottom filter row: do nothing
|
||||||
dgv.Rows.Insert(e.RowIndex - 1, row);
|
if (e.RowIndex >= dgv.RowCount - 2)
|
||||||
break;
|
break;
|
||||||
case COL_MoveDown:
|
dgv.Rows.Remove(row);
|
||||||
// if final/edit row or bottom filter row: do nothing
|
dgv.Rows.Insert(e.RowIndex + 1, row);
|
||||||
if (e.RowIndex >= dgv.RowCount - 2)
|
break;
|
||||||
break;
|
}
|
||||||
dgv.Rows.Remove(row);
|
}
|
||||||
dgv.Rows.Insert(e.RowIndex + 1, row);
|
}
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using ApplicationServices;
|
||||||
using System.Windows.Forms;
|
|
||||||
using ApplicationServices;
|
|
||||||
using InternalUtilities;
|
using InternalUtilities;
|
||||||
using LibationWinForms.Login;
|
using LibationWinForms.Login;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using FileManager;
|
||||||
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using Dinah.Core;
|
||||||
using System.Windows.Forms;
|
|
||||||
using Dinah.Core;
|
|
||||||
using InternalUtilities;
|
using InternalUtilities;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs.Login
|
namespace LibationWinForms.Dialogs.Login
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,11 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs.Login
|
namespace LibationWinForms.Dialogs.Login
|
||||||
@ -14,7 +8,7 @@ namespace LibationWinForms.Dialogs.Login
|
|||||||
{
|
{
|
||||||
private RadioButton[] radioButtons { get; }
|
private RadioButton[] radioButtons { get; }
|
||||||
|
|
||||||
AudibleApi.MfaConfig _mfaConfig { get; }
|
private AudibleApi.MfaConfig _mfaConfig { get; }
|
||||||
|
|
||||||
public MfaDialog(AudibleApi.MfaConfig mfaConfig)
|
public MfaDialog(AudibleApi.MfaConfig mfaConfig)
|
||||||
{
|
{
|
||||||
@ -32,7 +26,8 @@ namespace LibationWinForms.Dialogs.Login
|
|||||||
setRadioButton(1, this.radioButton2);
|
setRadioButton(1, this.radioButton2);
|
||||||
setRadioButton(2, this.radioButton3);
|
setRadioButton(2, this.radioButton3);
|
||||||
|
|
||||||
Serilog.Log.Logger.Information("{@DebugInfo}", new {
|
Serilog.Log.Logger.Information("{@DebugInfo}", new
|
||||||
|
{
|
||||||
paramButtonCount = mfaConfig.Buttons.Count,
|
paramButtonCount = mfaConfig.Buttons.Count,
|
||||||
visibleRadioButtonCount = radioButtons.Count(rb => rb.Visible)
|
visibleRadioButtonCount = radioButtons.Count(rb => rb.Visible)
|
||||||
});
|
});
|
||||||
@ -65,7 +60,8 @@ namespace LibationWinForms.Dialogs.Login
|
|||||||
{
|
{
|
||||||
var selected = radioButtons.FirstOrDefault(rb => rb.Checked);
|
var selected = radioButtons.FirstOrDefault(rb => rb.Checked);
|
||||||
|
|
||||||
Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new {
|
Serilog.Log.Logger.Information("Submit button clicked: {@DebugInfo}", new
|
||||||
|
{
|
||||||
rb1_visible = radioButton1.Visible,
|
rb1_visible = radioButton1.Visible,
|
||||||
rb1_checked = radioButton1.Checked,
|
rb1_checked = radioButton1.Checked,
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using AudibleApi;
|
||||||
using AudibleApi;
|
|
||||||
using InternalUtilities;
|
using InternalUtilities;
|
||||||
using LibationWinForms.Dialogs.Login;
|
using LibationWinForms.Dialogs.Login;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using Dinah.Core;
|
||||||
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,27 +3,27 @@ using DataLayer;
|
|||||||
using InternalUtilities;
|
using InternalUtilities;
|
||||||
using LibationWinForms.Login;
|
using LibationWinForms.Login;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class RemoveBooksDialog : Form
|
public partial class RemoveBooksDialog : Form
|
||||||
{
|
{
|
||||||
public bool BooksRemoved { get; private set; }
|
public bool BooksRemoved { get; private set; }
|
||||||
|
|
||||||
private Account[] _accounts { get; }
|
private Account[] _accounts { get; }
|
||||||
private List<LibraryBook> _libraryBooks;
|
private readonly List<LibraryBook> _libraryBooks;
|
||||||
private SortableBindingList2<RemovableGridEntry> _removableGridEntries;
|
private readonly SortableBindingList2<RemovableGridEntry> _removableGridEntries;
|
||||||
private string _labelFormat;
|
private readonly string _labelFormat;
|
||||||
private int SelectedCount => SelectedEntries?.Count() ?? 0;
|
private int SelectedCount => SelectedEntries?.Count() ?? 0;
|
||||||
private IEnumerable<RemovableGridEntry> SelectedEntries => _removableGridEntries?.Where(b => b.Remove);
|
private IEnumerable<RemovableGridEntry> SelectedEntries => _removableGridEntries?.Where(b => b.Remove);
|
||||||
|
|
||||||
public RemoveBooksDialog(params Account[] accounts)
|
public RemoveBooksDialog(params Account[] accounts)
|
||||||
{
|
{
|
||||||
_libraryBooks = DbContexts.GetContext().GetLibrary_Flat_NoTracking();
|
_libraryBooks = DbContexts.GetContext().GetLibrary_Flat_NoTracking();
|
||||||
_accounts = accounts;
|
_accounts = accounts;
|
||||||
@ -32,8 +32,8 @@ namespace LibationWinForms.Dialogs
|
|||||||
_labelFormat = label1.Text;
|
_labelFormat = label1.Text;
|
||||||
|
|
||||||
_dataGridView.CellContentClick += (s, e) => _dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
|
_dataGridView.CellContentClick += (s, e) => _dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
|
||||||
_dataGridView.CellValueChanged += DataGridView1_CellValueChanged;
|
_dataGridView.CellValueChanged += DataGridView1_CellValueChanged;
|
||||||
_dataGridView.BindingContextChanged += (s, e) => UpdateSelection();
|
_dataGridView.BindingContextChanged += (s, e) => UpdateSelection();
|
||||||
|
|
||||||
var orderedGridEntries = _libraryBooks
|
var orderedGridEntries = _libraryBooks
|
||||||
.Select(lb => new RemovableGridEntry(lb))
|
.Select(lb => new RemovableGridEntry(lb))
|
||||||
@ -46,7 +46,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
_dataGridView.Enabled = false;
|
_dataGridView.Enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
|
private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.ColumnIndex == 0)
|
if (e.ColumnIndex == 0)
|
||||||
UpdateSelection();
|
UpdateSelection();
|
||||||
@ -78,9 +78,9 @@ namespace LibationWinForms.Dialogs
|
|||||||
ex);
|
ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_dataGridView.Enabled = true;
|
_dataGridView.Enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnRemoveBooks_Click(object sender, EventArgs e)
|
private void btnRemoveBooks_Click(object sender, EventArgs e)
|
||||||
@ -122,15 +122,15 @@ namespace LibationWinForms.Dialogs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void UpdateSelection()
|
private void UpdateSelection()
|
||||||
{
|
{
|
||||||
_dataGridView.Sort(_dataGridView.Columns[0], ListSortDirection.Descending);
|
_dataGridView.Sort(_dataGridView.Columns[0], ListSortDirection.Descending);
|
||||||
var selectedCount = SelectedCount;
|
var selectedCount = SelectedCount;
|
||||||
label1.Text = string.Format(_labelFormat, selectedCount, selectedCount != 1 ? "s" : string.Empty);
|
label1.Text = string.Format(_labelFormat, selectedCount, selectedCount != 1 ? "s" : string.Empty);
|
||||||
btnRemoveBooks.Enabled = selectedCount > 0;
|
btnRemoveBooks.Enabled = selectedCount > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class RemovableGridEntry : GridEntry
|
internal class RemovableGridEntry : GridEntry
|
||||||
{
|
{
|
||||||
private static readonly IComparer BoolComparer = new ObjectComparer<bool>();
|
private static readonly IComparer BoolComparer = new ObjectComparer<bool>();
|
||||||
|
|
||||||
@ -153,18 +153,18 @@ namespace LibationWinForms.Dialogs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object GetMemberValue(string memberName)
|
public override object GetMemberValue(string memberName)
|
||||||
{
|
{
|
||||||
if (memberName == nameof(Remove))
|
if (memberName == nameof(Remove))
|
||||||
return Remove;
|
return Remove;
|
||||||
return base.GetMemberValue(memberName);
|
return base.GetMemberValue(memberName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IComparer GetMemberComparer(Type memberType)
|
public override IComparer GetMemberComparer(Type memberType)
|
||||||
{
|
{
|
||||||
if (memberType == typeof(bool))
|
if (memberType == typeof(bool))
|
||||||
return BoolComparer;
|
return BoolComparer;
|
||||||
return base.GetMemberComparer(memberType);
|
return base.GetMemberComparer(memberType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<root>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
@ -57,7 +58,4 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<metadata name="gridEntryBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
</root>
|
</root>
|
||||||
@ -1,10 +1,7 @@
|
|||||||
using System;
|
using InternalUtilities;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using InternalUtilities;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
@ -12,7 +9,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
{
|
{
|
||||||
public List<Account> CheckedAccounts { get; } = new List<Account>();
|
public List<Account> CheckedAccounts { get; } = new List<Account>();
|
||||||
|
|
||||||
Form1 _parent { get; }
|
private Form1 _parent { get; }
|
||||||
|
|
||||||
public ScanAccountsDialog(Form1 parent)
|
public ScanAccountsDialog(Form1 parent)
|
||||||
{
|
{
|
||||||
@ -21,7 +18,7 @@ namespace LibationWinForms.Dialogs
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
class listItem
|
private class listItem
|
||||||
{
|
{
|
||||||
public Account Account { get; set; }
|
public Account Account { get; set; }
|
||||||
public string Text { get; set; }
|
public string Text { get; set; }
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -3,18 +3,18 @@ using System.Windows.Forms;
|
|||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class SearchSyntaxDialog : Form
|
public partial class SearchSyntaxDialog : Form
|
||||||
{
|
{
|
||||||
public SearchSyntaxDialog()
|
public SearchSyntaxDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
label2.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchStringFields());
|
label2.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchStringFields());
|
||||||
label3.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchNumberFields());
|
label3.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchNumberFields());
|
||||||
label4.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchBoolFields());
|
label4.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchBoolFields());
|
||||||
label5.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchIdFields());
|
label5.Text += "\r\n\r\n" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchIdFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseBtn_Click(object sender, EventArgs e) => this.Close();
|
private void CloseBtn_Click(object sender, EventArgs e) => this.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,64 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
using System;
|
using Dinah.Core;
|
||||||
|
using FileManager;
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core;
|
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace LibationWinForms.Dialogs
|
namespace LibationWinForms.Dialogs
|
||||||
{
|
{
|
||||||
public partial class SettingsDialog : Form
|
public partial class SettingsDialog : Form
|
||||||
{
|
{
|
||||||
Configuration config { get; } = Configuration.Instance;
|
private Configuration config { get; } = Configuration.Instance;
|
||||||
Func<string, string> desc { get; } = Configuration.GetDescription;
|
private Func<string, string> desc { get; } = Configuration.GetDescription;
|
||||||
|
|
||||||
public SettingsDialog() => InitializeComponent();
|
public SettingsDialog() => InitializeComponent();
|
||||||
|
|
||||||
@ -57,13 +57,13 @@ namespace LibationWinForms.Dialogs
|
|||||||
inProgressSelectControl.SelectDirectory(config.InProgress);
|
inProgressSelectControl.SelectDirectory(config.InProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void allowLibationFixupCbox_CheckedChanged(object sender, EventArgs e)
|
private void allowLibationFixupCbox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
convertLosslessRb.Enabled = allowLibationFixupCbox.Checked;
|
convertLosslessRb.Enabled = allowLibationFixupCbox.Checked;
|
||||||
convertLossyRb.Enabled = allowLibationFixupCbox.Checked;
|
convertLossyRb.Enabled = allowLibationFixupCbox.Checked;
|
||||||
|
|
||||||
if (!allowLibationFixupCbox.Checked)
|
if (!allowLibationFixupCbox.Checked)
|
||||||
{
|
{
|
||||||
convertLosslessRb.Checked = true;
|
convertLosslessRb.Checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<root>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<root>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
using System;
|
using ApplicationServices;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using ApplicationServices;
|
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.Drawing;
|
using Dinah.Core.Drawing;
|
||||||
@ -11,371 +6,376 @@ using Dinah.Core.Windows.Forms;
|
|||||||
using FileManager;
|
using FileManager;
|
||||||
using InternalUtilities;
|
using InternalUtilities;
|
||||||
using LibationWinForms.Dialogs;
|
using LibationWinForms.Dialogs;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
public partial class Form1 : Form
|
public partial class Form1 : Form
|
||||||
{
|
{
|
||||||
private string backupsCountsLbl_Format { get; }
|
private string backupsCountsLbl_Format { get; }
|
||||||
private string pdfsCountsLbl_Format { get; }
|
private string pdfsCountsLbl_Format { get; }
|
||||||
private string visibleCountLbl_Format { get; }
|
private string visibleCountLbl_Format { get; }
|
||||||
|
|
||||||
private string beginBookBackupsToolStripMenuItem_format { get; }
|
private string beginBookBackupsToolStripMenuItem_format { get; }
|
||||||
private string beginPdfBackupsToolStripMenuItem_format { get; }
|
private string beginPdfBackupsToolStripMenuItem_format { get; }
|
||||||
|
|
||||||
public Form1()
|
public Form1()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// back up string formats
|
// back up string formats
|
||||||
backupsCountsLbl_Format = backupsCountsLbl.Text;
|
backupsCountsLbl_Format = backupsCountsLbl.Text;
|
||||||
pdfsCountsLbl_Format = pdfsCountsLbl.Text;
|
pdfsCountsLbl_Format = pdfsCountsLbl.Text;
|
||||||
visibleCountLbl_Format = visibleCountLbl.Text;
|
visibleCountLbl_Format = visibleCountLbl.Text;
|
||||||
|
|
||||||
beginBookBackupsToolStripMenuItem_format = beginBookBackupsToolStripMenuItem.Text;
|
beginBookBackupsToolStripMenuItem_format = beginBookBackupsToolStripMenuItem.Text;
|
||||||
beginPdfBackupsToolStripMenuItem_format = beginPdfBackupsToolStripMenuItem.Text;
|
beginPdfBackupsToolStripMenuItem_format = beginPdfBackupsToolStripMenuItem.Text;
|
||||||
|
|
||||||
// after backing up formats: can set default/temp visible text
|
// after backing up formats: can set default/temp visible text
|
||||||
backupsCountsLbl.Text = "[Calculating backed up book quantities]";
|
backupsCountsLbl.Text = "[Calculating backed up book quantities]";
|
||||||
pdfsCountsLbl.Text = "[Calculating backed up PDFs]";
|
pdfsCountsLbl.Text = "[Calculating backed up PDFs]";
|
||||||
setVisibleCount(null, 0);
|
setVisibleCount(null, 0);
|
||||||
|
|
||||||
if (this.DesignMode)
|
if (this.DesignMode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// independent UI updates
|
// independent UI updates
|
||||||
this.Load += setBackupCountsAsync;
|
this.Load += setBackupCountsAsync;
|
||||||
this.Load += (_, __) => RestoreSizeAndLocation();
|
this.Load += (_, __) => RestoreSizeAndLocation();
|
||||||
this.Load += (_, __) => RefreshImportMenu();
|
this.Load += (_, __) => RefreshImportMenu();
|
||||||
|
|
||||||
var format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
var format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
||||||
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
|
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
|
||||||
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));
|
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));
|
||||||
PictureStorage.SetDefaultImage(PictureSize._500x500, Properties.Resources.default_cover_500x500.ToBytes(format));
|
PictureStorage.SetDefaultImage(PictureSize._500x500, Properties.Resources.default_cover_500x500.ToBytes(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Form1_Load(object sender, EventArgs e)
|
private void Form1_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (this.DesignMode)
|
if (this.DesignMode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
reloadGrid();
|
reloadGrid();
|
||||||
|
|
||||||
// also applies filter. ONLY call AFTER loading grid
|
// also applies filter. ONLY call AFTER loading grid
|
||||||
loadInitialQuickFilterState();
|
loadInitialQuickFilterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
{
|
{
|
||||||
SaveSizeAndLocation();
|
SaveSizeAndLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreSizeAndLocation()
|
private void RestoreSizeAndLocation()
|
||||||
{
|
{
|
||||||
var config = Configuration.Instance;
|
var config = Configuration.Instance;
|
||||||
|
|
||||||
var width = config.MainFormWidth;
|
var width = config.MainFormWidth;
|
||||||
var height = config.MainFormHeight;
|
var height = config.MainFormHeight;
|
||||||
|
|
||||||
// too small -- something must have gone wrong. use defaults
|
// too small -- something must have gone wrong. use defaults
|
||||||
if (width < 25 || height < 25)
|
if (width < 25 || height < 25)
|
||||||
{
|
{
|
||||||
width = 1023;
|
width = 1023;
|
||||||
height = 578;
|
height = 578;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fit to the current screen size in case the screen resolution changed since the size was last persisted
|
// Fit to the current screen size in case the screen resolution changed since the size was last persisted
|
||||||
if (width > Screen.PrimaryScreen.WorkingArea.Width)
|
if (width > Screen.PrimaryScreen.WorkingArea.Width)
|
||||||
width = Screen.PrimaryScreen.WorkingArea.Width;
|
width = Screen.PrimaryScreen.WorkingArea.Width;
|
||||||
if (height > Screen.PrimaryScreen.WorkingArea.Height)
|
if (height > Screen.PrimaryScreen.WorkingArea.Height)
|
||||||
height = Screen.PrimaryScreen.WorkingArea.Height;
|
height = Screen.PrimaryScreen.WorkingArea.Height;
|
||||||
|
|
||||||
var x = config.MainFormX;
|
var x = config.MainFormX;
|
||||||
var y = config.MainFormY;
|
var y = config.MainFormY;
|
||||||
|
|
||||||
var rect = new System.Drawing.Rectangle(x, y, width, height);
|
var rect = new System.Drawing.Rectangle(x, y, width, height);
|
||||||
|
|
||||||
// is proposed rect on a screen?
|
// is proposed rect on a screen?
|
||||||
if (Screen.AllScreens.Any(screen => screen.WorkingArea.Contains(rect)))
|
if (Screen.AllScreens.Any(screen => screen.WorkingArea.Contains(rect)))
|
||||||
{
|
{
|
||||||
this.StartPosition = FormStartPosition.Manual;
|
this.StartPosition = FormStartPosition.Manual;
|
||||||
this.DesktopBounds = rect;
|
this.DesktopBounds = rect;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
|
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
|
||||||
this.Size = rect.Size;
|
this.Size = rect.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FINAL: for Maximized: start normal state, set size and location, THEN set max state
|
// FINAL: for Maximized: start normal state, set size and location, THEN set max state
|
||||||
this.WindowState = config.MainFormIsMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
this.WindowState = config.MainFormIsMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveSizeAndLocation()
|
private void SaveSizeAndLocation()
|
||||||
{
|
{
|
||||||
System.Drawing.Point location;
|
System.Drawing.Point location;
|
||||||
System.Drawing.Size size;
|
System.Drawing.Size size;
|
||||||
|
|
||||||
// save location and size if the state is normal
|
// save location and size if the state is normal
|
||||||
if (this.WindowState == FormWindowState.Normal)
|
if (this.WindowState == FormWindowState.Normal)
|
||||||
{
|
{
|
||||||
location = this.Location;
|
location = this.Location;
|
||||||
size = this.Size;
|
size = this.Size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// save the RestoreBounds if the form is minimized or maximized
|
// save the RestoreBounds if the form is minimized or maximized
|
||||||
location = this.RestoreBounds.Location;
|
location = this.RestoreBounds.Location;
|
||||||
size = this.RestoreBounds.Size;
|
size = this.RestoreBounds.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = Configuration.Instance;
|
var config = Configuration.Instance;
|
||||||
|
|
||||||
config.MainFormX = location.X;
|
config.MainFormX = location.X;
|
||||||
config.MainFormY = location.Y;
|
config.MainFormY = location.Y;
|
||||||
|
|
||||||
config.MainFormWidth = size.Width;
|
config.MainFormWidth = size.Width;
|
||||||
config.MainFormHeight = size.Height;
|
config.MainFormHeight = size.Height;
|
||||||
|
|
||||||
config.MainFormIsMaximized = this.WindowState == FormWindowState.Maximized;
|
config.MainFormIsMaximized = this.WindowState == FormWindowState.Maximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region reload grid
|
#region reload grid
|
||||||
bool isProcessingGridSelect = false;
|
private bool isProcessingGridSelect = false;
|
||||||
private void reloadGrid()
|
private void reloadGrid()
|
||||||
{
|
{
|
||||||
// suppressed filter while init'ing UI
|
// suppressed filter while init'ing UI
|
||||||
var prev_isProcessingGridSelect = isProcessingGridSelect;
|
var prev_isProcessingGridSelect = isProcessingGridSelect;
|
||||||
isProcessingGridSelect = true;
|
isProcessingGridSelect = true;
|
||||||
setGrid();
|
setGrid();
|
||||||
isProcessingGridSelect = prev_isProcessingGridSelect;
|
isProcessingGridSelect = prev_isProcessingGridSelect;
|
||||||
|
|
||||||
// UI init complete. now we can apply filter
|
// UI init complete. now we can apply filter
|
||||||
doFilter(lastGoodFilter);
|
doFilter(lastGoodFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProductsGrid currProductsGrid;
|
private ProductsGrid currProductsGrid;
|
||||||
private void setGrid()
|
private void setGrid()
|
||||||
{
|
{
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
{
|
{
|
||||||
if (currProductsGrid != null)
|
if (currProductsGrid != null)
|
||||||
{
|
{
|
||||||
gridPanel.Controls.Remove(currProductsGrid);
|
gridPanel.Controls.Remove(currProductsGrid);
|
||||||
currProductsGrid.VisibleCountChanged -= setVisibleCount;
|
currProductsGrid.VisibleCountChanged -= setVisibleCount;
|
||||||
currProductsGrid.BackupCountsChanged -= setBackupCountsAsync;
|
currProductsGrid.BackupCountsChanged -= setBackupCountsAsync;
|
||||||
currProductsGrid.Dispose();
|
currProductsGrid.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
currProductsGrid = new ProductsGrid { Dock = DockStyle.Fill };
|
currProductsGrid = new ProductsGrid { Dock = DockStyle.Fill };
|
||||||
currProductsGrid.VisibleCountChanged += setVisibleCount;
|
currProductsGrid.VisibleCountChanged += setVisibleCount;
|
||||||
currProductsGrid.BackupCountsChanged += setBackupCountsAsync;
|
currProductsGrid.BackupCountsChanged += setBackupCountsAsync;
|
||||||
gridPanel.UIThread(() => gridPanel.Controls.Add(currProductsGrid));
|
gridPanel.UIThread(() => gridPanel.Controls.Add(currProductsGrid));
|
||||||
currProductsGrid.Display();
|
currProductsGrid.Display();
|
||||||
}
|
}
|
||||||
ResumeLayout();
|
ResumeLayout();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region bottom: qty books visible
|
#region bottom: qty books visible
|
||||||
private void setVisibleCount(object _, int qty) => visibleCountLbl.Text = string.Format(visibleCountLbl_Format, qty);
|
private void setVisibleCount(object _, int qty) => visibleCountLbl.Text = string.Format(visibleCountLbl_Format, qty);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region bottom: backup counts
|
#region bottom: backup counts
|
||||||
private async void setBackupCountsAsync(object _, object __)
|
private async void setBackupCountsAsync(object _, object __)
|
||||||
{
|
{
|
||||||
LibraryCommands.LibraryStats libraryStats = null;
|
LibraryCommands.LibraryStats libraryStats = null;
|
||||||
await Task.Run(() => libraryStats = LibraryCommands.GetCounts());
|
await Task.Run(() => libraryStats = LibraryCommands.GetCounts());
|
||||||
|
|
||||||
setBookBackupCounts(libraryStats.booksFullyBackedUp, libraryStats.booksDownloadedOnly, libraryStats.booksNoProgress);
|
setBookBackupCounts(libraryStats.booksFullyBackedUp, libraryStats.booksDownloadedOnly, libraryStats.booksNoProgress);
|
||||||
setPdfBackupCounts(libraryStats.pdfsDownloaded, libraryStats.pdfsNotDownloaded);
|
setPdfBackupCounts(libraryStats.pdfsDownloaded, libraryStats.pdfsNotDownloaded);
|
||||||
}
|
}
|
||||||
private void setBookBackupCounts(int booksFullyBackedUp, int booksDownloadedOnly, int booksNoProgress)
|
private void setBookBackupCounts(int booksFullyBackedUp, int booksDownloadedOnly, int booksNoProgress)
|
||||||
{
|
{
|
||||||
// enable/disable export
|
// enable/disable export
|
||||||
var hasResults = 0 < (booksFullyBackedUp + booksDownloadedOnly + booksNoProgress);
|
var hasResults = 0 < (booksFullyBackedUp + booksDownloadedOnly + booksNoProgress);
|
||||||
exportLibraryToolStripMenuItem.Enabled = hasResults;
|
exportLibraryToolStripMenuItem.Enabled = hasResults;
|
||||||
|
|
||||||
// update bottom numbers
|
// update bottom numbers
|
||||||
var pending = booksNoProgress + booksDownloadedOnly;
|
var pending = booksNoProgress + booksDownloadedOnly;
|
||||||
var statusStripText
|
var statusStripText
|
||||||
= !hasResults ? "No books. Begin by importing your library"
|
= !hasResults ? "No books. Begin by importing your library"
|
||||||
: pending > 0 ? string.Format(backupsCountsLbl_Format, booksNoProgress, booksDownloadedOnly, booksFullyBackedUp)
|
: pending > 0 ? string.Format(backupsCountsLbl_Format, booksNoProgress, booksDownloadedOnly, booksFullyBackedUp)
|
||||||
: $"All {"book".PluralizeWithCount(booksFullyBackedUp)} backed up";
|
: $"All {"book".PluralizeWithCount(booksFullyBackedUp)} backed up";
|
||||||
|
|
||||||
// update menu item
|
// update menu item
|
||||||
var menuItemText
|
var menuItemText
|
||||||
= pending > 0
|
= pending > 0
|
||||||
? $"{pending} remaining"
|
? $"{pending} remaining"
|
||||||
: "All books have been liberated";
|
: "All books have been liberated";
|
||||||
|
|
||||||
// update UI
|
// update UI
|
||||||
statusStrip1.UIThread(() => backupsCountsLbl.Text = statusStripText);
|
statusStrip1.UIThread(() => backupsCountsLbl.Text = statusStripText);
|
||||||
menuStrip1.UIThread(() => beginBookBackupsToolStripMenuItem.Enabled = pending > 0);
|
menuStrip1.UIThread(() => beginBookBackupsToolStripMenuItem.Enabled = pending > 0);
|
||||||
menuStrip1.UIThread(() => beginBookBackupsToolStripMenuItem.Text = string.Format(beginBookBackupsToolStripMenuItem_format, menuItemText));
|
menuStrip1.UIThread(() => beginBookBackupsToolStripMenuItem.Text = string.Format(beginBookBackupsToolStripMenuItem_format, menuItemText));
|
||||||
}
|
}
|
||||||
private void setPdfBackupCounts(int pdfsDownloaded, int pdfsNotDownloaded)
|
private void setPdfBackupCounts(int pdfsDownloaded, int pdfsNotDownloaded)
|
||||||
{
|
{
|
||||||
// update bottom numbers
|
// update bottom numbers
|
||||||
var hasResults = 0 < (pdfsNotDownloaded + pdfsDownloaded);
|
var hasResults = 0 < (pdfsNotDownloaded + pdfsDownloaded);
|
||||||
var statusStripText
|
var statusStripText
|
||||||
= !hasResults ? ""
|
= !hasResults ? ""
|
||||||
: pdfsNotDownloaded > 0 ? string.Format(pdfsCountsLbl_Format, pdfsNotDownloaded, pdfsDownloaded)
|
: pdfsNotDownloaded > 0 ? string.Format(pdfsCountsLbl_Format, pdfsNotDownloaded, pdfsDownloaded)
|
||||||
: $"| All {pdfsDownloaded} PDFs downloaded";
|
: $"| All {pdfsDownloaded} PDFs downloaded";
|
||||||
|
|
||||||
// update menu item
|
// update menu item
|
||||||
var menuItemText
|
var menuItemText
|
||||||
= pdfsNotDownloaded > 0
|
= pdfsNotDownloaded > 0
|
||||||
? $"{pdfsNotDownloaded} remaining"
|
? $"{pdfsNotDownloaded} remaining"
|
||||||
: "All PDFs have been downloaded";
|
: "All PDFs have been downloaded";
|
||||||
|
|
||||||
// update UI
|
// update UI
|
||||||
statusStrip1.UIThread(() => pdfsCountsLbl.Text = statusStripText);
|
statusStrip1.UIThread(() => pdfsCountsLbl.Text = statusStripText);
|
||||||
menuStrip1.UIThread(() => beginPdfBackupsToolStripMenuItem.Enabled = pdfsNotDownloaded > 0);
|
menuStrip1.UIThread(() => beginPdfBackupsToolStripMenuItem.Enabled = pdfsNotDownloaded > 0);
|
||||||
menuStrip1.UIThread(() => beginPdfBackupsToolStripMenuItem.Text = string.Format(beginPdfBackupsToolStripMenuItem_format, menuItemText));
|
menuStrip1.UIThread(() => beginPdfBackupsToolStripMenuItem.Text = string.Format(beginPdfBackupsToolStripMenuItem_format, menuItemText));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region filter
|
#region filter
|
||||||
private void filterHelpBtn_Click(object sender, EventArgs e) => new SearchSyntaxDialog().ShowDialog();
|
private void filterHelpBtn_Click(object sender, EventArgs e) => new SearchSyntaxDialog().ShowDialog();
|
||||||
|
|
||||||
private void AddFilterBtn_Click(object sender, EventArgs e)
|
private void AddFilterBtn_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
QuickFilters.Add(this.filterSearchTb.Text);
|
QuickFilters.Add(this.filterSearchTb.Text);
|
||||||
UpdateFilterDropDown();
|
UpdateFilterDropDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void filterSearchTb_KeyPress(object sender, KeyPressEventArgs e)
|
private void filterSearchTb_KeyPress(object sender, KeyPressEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.KeyChar == (char)Keys.Return)
|
if (e.KeyChar == (char)Keys.Return)
|
||||||
{
|
{
|
||||||
doFilter();
|
doFilter();
|
||||||
|
|
||||||
// silence the 'ding'
|
// silence the 'ding'
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void filterBtn_Click(object sender, EventArgs e) => doFilter();
|
private void filterBtn_Click(object sender, EventArgs e) => doFilter();
|
||||||
|
|
||||||
string lastGoodFilter = "";
|
private string lastGoodFilter = "";
|
||||||
private void doFilter(string filterString)
|
private void doFilter(string filterString)
|
||||||
{
|
{
|
||||||
this.filterSearchTb.Text = filterString;
|
this.filterSearchTb.Text = filterString;
|
||||||
doFilter();
|
doFilter();
|
||||||
}
|
}
|
||||||
private void doFilter()
|
private void doFilter()
|
||||||
{
|
{
|
||||||
if (isProcessingGridSelect || currProductsGrid == null)
|
if (isProcessingGridSelect || currProductsGrid == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
currProductsGrid.Filter(filterSearchTb.Text);
|
currProductsGrid.Filter(filterSearchTb.Text);
|
||||||
lastGoodFilter = filterSearchTb.Text;
|
lastGoodFilter = filterSearchTb.Text;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MessageBox.Show($"Bad filter string:\r\n\r\n{ex.Message}", "Bad filter string", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show($"Bad filter string:\r\n\r\n{ex.Message}", "Bad filter string", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
|
||||||
// re-apply last good filter
|
// re-apply last good filter
|
||||||
doFilter(lastGoodFilter);
|
doFilter(lastGoodFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Import menu
|
#region Import menu
|
||||||
public void RefreshImportMenu()
|
public void RefreshImportMenu()
|
||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
var count = persister.AccountsSettings.Accounts.Count;
|
var count = persister.AccountsSettings.Accounts.Count;
|
||||||
|
|
||||||
noAccountsYetAddAccountToolStripMenuItem.Visible = count == 0;
|
noAccountsYetAddAccountToolStripMenuItem.Visible = count == 0;
|
||||||
scanLibraryToolStripMenuItem.Visible = count == 1;
|
scanLibraryToolStripMenuItem.Visible = count == 1;
|
||||||
scanLibraryOfAllAccountsToolStripMenuItem.Visible = count > 1;
|
scanLibraryOfAllAccountsToolStripMenuItem.Visible = count > 1;
|
||||||
scanLibraryOfSomeAccountsToolStripMenuItem.Visible = count > 1;
|
scanLibraryOfSomeAccountsToolStripMenuItem.Visible = count > 1;
|
||||||
|
|
||||||
removeLibraryBooksToolStripMenuItem.Visible = count != 0;
|
removeLibraryBooksToolStripMenuItem.Visible = count != 0;
|
||||||
|
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
{
|
{
|
||||||
removeLibraryBooksToolStripMenuItem.Click += removeThisAccountToolStripMenuItem_Click;
|
removeLibraryBooksToolStripMenuItem.Click += removeThisAccountToolStripMenuItem_Click;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSomeAccountsToolStripMenuItem.Visible = count > 1;
|
removeSomeAccountsToolStripMenuItem.Visible = count > 1;
|
||||||
removeAllAccountsToolStripMenuItem.Visible = count > 1;
|
removeAllAccountsToolStripMenuItem.Visible = count > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void noAccountsYetAddAccountToolStripMenuItem_Click(object sender, EventArgs e)
|
private void noAccountsYetAddAccountToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
MessageBox.Show("To load your Audible library, come back here to the Import menu after adding your account");
|
MessageBox.Show("To load your Audible library, come back here to the Import menu after adding your account");
|
||||||
new AccountsDialog(this).ShowDialog();
|
new AccountsDialog(this).ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLibraryToolStripMenuItem_Click(object sender, EventArgs e)
|
private void scanLibraryToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
var firstAccount = persister.AccountsSettings.GetAll().FirstOrDefault();
|
var firstAccount = persister.AccountsSettings.GetAll().FirstOrDefault();
|
||||||
scanLibraries(firstAccount);
|
scanLibraries(firstAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLibraryOfAllAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
private void scanLibraryOfAllAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
var allAccounts = persister.AccountsSettings.GetAll();
|
var allAccounts = persister.AccountsSettings.GetAll();
|
||||||
scanLibraries(allAccounts);
|
scanLibraries(allAccounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLibraryOfSomeAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
private void scanLibraryOfSomeAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var scanAccountsDialog = new ScanAccountsDialog(this);
|
using var scanAccountsDialog = new ScanAccountsDialog(this);
|
||||||
|
|
||||||
if (scanAccountsDialog.ShowDialog() != DialogResult.OK)
|
if (scanAccountsDialog.ShowDialog() != DialogResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!scanAccountsDialog.CheckedAccounts.Any())
|
if (!scanAccountsDialog.CheckedAccounts.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scanLibraries(scanAccountsDialog.CheckedAccounts);
|
scanLibraries(scanAccountsDialog.CheckedAccounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeThisAccountToolStripMenuItem_Click(object sender, EventArgs e)
|
private void removeThisAccountToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
var firstAccount = persister.AccountsSettings.GetAll().FirstOrDefault();
|
var firstAccount = persister.AccountsSettings.GetAll().FirstOrDefault();
|
||||||
scanLibrariesRemovedBooks(firstAccount);
|
scanLibrariesRemovedBooks(firstAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeAllAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
private void removeAllAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
var allAccounts = persister.AccountsSettings.GetAll();
|
var allAccounts = persister.AccountsSettings.GetAll();
|
||||||
scanLibrariesRemovedBooks(allAccounts.ToArray());
|
scanLibrariesRemovedBooks(allAccounts.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeSomeAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
private void removeSomeAccountsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using var scanAccountsDialog = new ScanAccountsDialog(this);
|
using var scanAccountsDialog = new ScanAccountsDialog(this);
|
||||||
|
|
||||||
if (scanAccountsDialog.ShowDialog() != DialogResult.OK)
|
if (scanAccountsDialog.ShowDialog() != DialogResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!scanAccountsDialog.CheckedAccounts.Any())
|
if (!scanAccountsDialog.CheckedAccounts.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scanLibrariesRemovedBooks(scanAccountsDialog.CheckedAccounts.ToArray());
|
scanLibrariesRemovedBooks(scanAccountsDialog.CheckedAccounts.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLibrariesRemovedBooks(params Account[] accounts)
|
private void scanLibrariesRemovedBooks(params Account[] accounts)
|
||||||
{
|
{
|
||||||
using var dialog = new RemoveBooksDialog(accounts);
|
using var dialog = new RemoveBooksDialog(accounts);
|
||||||
dialog.ShowDialog();
|
dialog.ShowDialog();
|
||||||
|
|
||||||
if (dialog.BooksRemoved)
|
if (dialog.BooksRemoved)
|
||||||
reloadGrid();
|
reloadGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLibraries(IEnumerable<Account> accounts) => scanLibraries(accounts.ToArray());
|
private void scanLibraries(IEnumerable<Account> accounts) => scanLibraries(accounts.ToArray());
|
||||||
private void scanLibraries(params Account[] accounts)
|
private void scanLibraries(params Account[] accounts)
|
||||||
{
|
{
|
||||||
using var dialog = new IndexLibraryDialog(accounts);
|
using var dialog = new IndexLibraryDialog(accounts);
|
||||||
dialog.ShowDialog();
|
dialog.ShowDialog();
|
||||||
@ -387,112 +387,112 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
if (totalProcessed > 0)
|
if (totalProcessed > 0)
|
||||||
reloadGrid();
|
reloadGrid();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region liberate menu
|
#region liberate menu
|
||||||
private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
=> await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync(updateGridRow);
|
=> await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync(updateGridRow);
|
||||||
|
|
||||||
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
=> await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync(updateGridRow);
|
=> await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync(updateGridRow);
|
||||||
|
|
||||||
private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e)
|
private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
=> await BookLiberation.ProcessorAutomationController.ConvertAllBooksAsync();
|
=> await BookLiberation.ProcessorAutomationController.ConvertAllBooksAsync();
|
||||||
|
|
||||||
private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshRow(libraryBook.Book.AudibleProductId);
|
private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshRow(libraryBook.Book.AudibleProductId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Export menu
|
#region Export menu
|
||||||
private void exportLibraryToolStripMenuItem_Click(object sender, EventArgs e)
|
private void exportLibraryToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var saveFileDialog = new SaveFileDialog
|
var saveFileDialog = new SaveFileDialog
|
||||||
{
|
{
|
||||||
Title = "Where to export Library",
|
Title = "Where to export Library",
|
||||||
Filter = "Excel Workbook (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv|JSON files (*.json)|*.json" // + "|All files (*.*)|*.*"
|
Filter = "Excel Workbook (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv|JSON files (*.json)|*.json" // + "|All files (*.*)|*.*"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (saveFileDialog.ShowDialog() != DialogResult.OK)
|
if (saveFileDialog.ShowDialog() != DialogResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// FilterIndex is 1-based, NOT 0-based
|
// FilterIndex is 1-based, NOT 0-based
|
||||||
switch (saveFileDialog.FilterIndex)
|
switch (saveFileDialog.FilterIndex)
|
||||||
{
|
{
|
||||||
case 1: // xlsx
|
case 1: // xlsx
|
||||||
default:
|
default:
|
||||||
LibraryExporter.ToXlsx(saveFileDialog.FileName);
|
LibraryExporter.ToXlsx(saveFileDialog.FileName);
|
||||||
break;
|
break;
|
||||||
case 2: // csv
|
case 2: // csv
|
||||||
LibraryExporter.ToCsv(saveFileDialog.FileName);
|
LibraryExporter.ToCsv(saveFileDialog.FileName);
|
||||||
break;
|
break;
|
||||||
case 3: // json
|
case 3: // json
|
||||||
LibraryExporter.ToJson(saveFileDialog.FileName);
|
LibraryExporter.ToJson(saveFileDialog.FileName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.Show("Library exported to:\r\n" + saveFileDialog.FileName);
|
MessageBox.Show("Library exported to:\r\n" + saveFileDialog.FileName);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MessageBoxAlertAdmin.Show("Error attempting to export your library.", "Error exporting", ex);
|
MessageBoxAlertAdmin.Show("Error attempting to export your library.", "Error exporting", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region quick filters menu
|
#region quick filters menu
|
||||||
private void loadInitialQuickFilterState()
|
private void loadInitialQuickFilterState()
|
||||||
{
|
{
|
||||||
// set inital state. do once only
|
// set inital state. do once only
|
||||||
firstFilterIsDefaultToolStripMenuItem.Checked = QuickFilters.UseDefault;
|
firstFilterIsDefaultToolStripMenuItem.Checked = QuickFilters.UseDefault;
|
||||||
|
|
||||||
// load default filter. do once only
|
// load default filter. do once only
|
||||||
if (QuickFilters.UseDefault)
|
if (QuickFilters.UseDefault)
|
||||||
doFilter(QuickFilters.Filters.FirstOrDefault());
|
doFilter(QuickFilters.Filters.FirstOrDefault());
|
||||||
|
|
||||||
// do after every save
|
// do after every save
|
||||||
UpdateFilterDropDown();
|
UpdateFilterDropDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FirstFilterIsDefaultToolStripMenuItem_Click(object sender, EventArgs e)
|
private void FirstFilterIsDefaultToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
firstFilterIsDefaultToolStripMenuItem.Checked = !firstFilterIsDefaultToolStripMenuItem.Checked;
|
firstFilterIsDefaultToolStripMenuItem.Checked = !firstFilterIsDefaultToolStripMenuItem.Checked;
|
||||||
QuickFilters.UseDefault = firstFilterIsDefaultToolStripMenuItem.Checked;
|
QuickFilters.UseDefault = firstFilterIsDefaultToolStripMenuItem.Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
object quickFilterTag { get; } = new object();
|
private object quickFilterTag { get; } = new object();
|
||||||
public void UpdateFilterDropDown()
|
public void UpdateFilterDropDown()
|
||||||
{
|
{
|
||||||
// remove old
|
// remove old
|
||||||
for (var i = quickFiltersToolStripMenuItem.DropDownItems.Count - 1; i >= 0; i--)
|
for (var i = quickFiltersToolStripMenuItem.DropDownItems.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var menuItem = quickFiltersToolStripMenuItem.DropDownItems[i];
|
var menuItem = quickFiltersToolStripMenuItem.DropDownItems[i];
|
||||||
if (menuItem.Tag == quickFilterTag)
|
if (menuItem.Tag == quickFilterTag)
|
||||||
quickFiltersToolStripMenuItem.DropDownItems.Remove(menuItem);
|
quickFiltersToolStripMenuItem.DropDownItems.Remove(menuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-populate
|
// re-populate
|
||||||
var index = 0;
|
var index = 0;
|
||||||
foreach (var filter in QuickFilters.Filters)
|
foreach (var filter in QuickFilters.Filters)
|
||||||
{
|
{
|
||||||
var menuItem = new ToolStripMenuItem
|
var menuItem = new ToolStripMenuItem
|
||||||
{
|
{
|
||||||
Tag = quickFilterTag,
|
Tag = quickFilterTag,
|
||||||
Text = $"&{++index}: {filter}"
|
Text = $"&{++index}: {filter}"
|
||||||
};
|
};
|
||||||
menuItem.Click += (_, __) => doFilter(filter);
|
menuItem.Click += (_, __) => doFilter(filter);
|
||||||
quickFiltersToolStripMenuItem.DropDownItems.Add(menuItem);
|
quickFiltersToolStripMenuItem.DropDownItems.Add(menuItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditQuickFiltersToolStripMenuItem_Click(object sender, EventArgs e) => new EditQuickFilters(this).ShowDialog();
|
private void EditQuickFiltersToolStripMenuItem_Click(object sender, EventArgs e) => new EditQuickFilters(this).ShowDialog();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region settings menu
|
#region settings menu
|
||||||
private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog(this).ShowDialog();
|
private void accountsToolStripMenuItem_Click(object sender, EventArgs e) => new AccountsDialog(this).ShowDialog();
|
||||||
|
|
||||||
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
using System;
|
using ApplicationServices;
|
||||||
|
using DataLayer;
|
||||||
|
using Dinah.Core.Drawing;
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ApplicationServices;
|
|
||||||
using DataLayer;
|
|
||||||
using Dinah.Core.Drawing;
|
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
@ -106,7 +106,7 @@ namespace LibationWinForms
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create getters for all member object values by name
|
/// Create getters for all member object values by name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, Func<object>> CreateMemberValueDictionary() => new()
|
private Dictionary<string, Func<object>> CreateMemberValueDictionary() => new()
|
||||||
{
|
{
|
||||||
{ nameof(Title), () => GetSortName(Book.Title) },
|
{ nameof(Title), () => GetSortName(Book.Title) },
|
||||||
{ nameof(Series), () => GetSortName(Book.SeriesNames) },
|
{ nameof(Series), () => GetSortName(Book.SeriesNames) },
|
||||||
|
|||||||
@ -3,7 +3,7 @@ using System.Collections;
|
|||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
interface IObjectMemberComparable
|
internal interface IObjectMemberComparable
|
||||||
{
|
{
|
||||||
IComparer GetMemberComparer(Type memberType);
|
IComparer GetMemberComparer(Type memberType);
|
||||||
object GetMemberValue(string memberName);
|
object GetMemberValue(string memberName);
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
using System;
|
using LibationWinForms.Dialogs;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using LibationWinForms.Dialogs;
|
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using Dinah.Core.Logging;
|
||||||
using System.Windows.Forms;
|
|
||||||
using Dinah.Core.Logging;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,7 +3,7 @@ using System.Collections;
|
|||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
class ObjectComparer<T> : IComparer where T : IComparable
|
internal class ObjectComparer<T> : IComparer where T : IComparable
|
||||||
{
|
{
|
||||||
public int Compare(object x, object y) => ((T)x).CompareTo((T)y);
|
public int Compare(object x, object y) => ((T)x).CompareTo((T)y);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,19 +3,19 @@ using System.ComponentModel;
|
|||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
class ObjectMemberComparer<T> : IComparer<T> where T : IObjectMemberComparable
|
internal class ObjectMemberComparer<T> : IComparer<T> where T : IObjectMemberComparable
|
||||||
{
|
{
|
||||||
public ListSortDirection Direction { get; set; } = ListSortDirection.Ascending;
|
public ListSortDirection Direction { get; set; } = ListSortDirection.Ascending;
|
||||||
public string PropertyName { get; set; }
|
public string PropertyName { get; set; }
|
||||||
|
|
||||||
public int Compare(T x, T y)
|
public int Compare(T x, T y)
|
||||||
{
|
{
|
||||||
var val1 = x.GetMemberValue(PropertyName);
|
var val1 = x.GetMemberValue(PropertyName);
|
||||||
var val2 = y.GetMemberValue(PropertyName);
|
var val2 = y.GetMemberValue(PropertyName);
|
||||||
|
|
||||||
return DirMult * x.GetMemberComparer(val1.GetType()).Compare(val1, val2);
|
return DirMult * x.GetMemberComparer(val1.GetType()).Compare(val1, val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int DirMult => Direction == ListSortDirection.Descending ? -1 : 1;
|
private int DirMult => Direction == ListSortDirection.Descending ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,200 +1,200 @@
|
|||||||
using System;
|
using ApplicationServices;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using ApplicationServices;
|
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.Windows.Forms;
|
using Dinah.Core.Windows.Forms;
|
||||||
using LibationWinForms.Dialogs;
|
using LibationWinForms.Dialogs;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
// INSTRUCTIONS TO UPDATE DATA_GRID_VIEW
|
// INSTRUCTIONS TO UPDATE DATA_GRID_VIEW
|
||||||
// - delete current DataGridView
|
// - delete current DataGridView
|
||||||
// - view > other windows > data sources
|
// - view > other windows > data sources
|
||||||
// - refresh
|
// - refresh
|
||||||
// OR
|
// OR
|
||||||
// - Add New Data Source
|
// - Add New Data Source
|
||||||
// Object. Next
|
// Object. Next
|
||||||
// LibationWinForms
|
// LibationWinForms
|
||||||
// AudibleDTO
|
// AudibleDTO
|
||||||
// GridEntry
|
// GridEntry
|
||||||
// - go to Design view
|
// - go to Design view
|
||||||
// - click on Data Sources > ProductItem. drowdown: DataGridView
|
// - click on Data Sources > ProductItem. drowdown: DataGridView
|
||||||
// - drag/drop ProductItem on design surface
|
// - drag/drop ProductItem on design surface
|
||||||
// AS OF AUGUST 2021 THIS DOES NOT WORK IN VS2019 WITH .NET-5 PROJECTS
|
// AS OF AUGUST 2021 THIS DOES NOT WORK IN VS2019 WITH .NET-5 PROJECTS
|
||||||
|
|
||||||
public partial class ProductsGrid : UserControl
|
public partial class ProductsGrid : UserControl
|
||||||
{
|
{
|
||||||
public event EventHandler<int> VisibleCountChanged;
|
public event EventHandler<int> VisibleCountChanged;
|
||||||
public event EventHandler BackupCountsChanged;
|
public event EventHandler BackupCountsChanged;
|
||||||
|
|
||||||
// alias
|
// alias
|
||||||
private DataGridView _dataGridView => gridEntryDataGridView;
|
private DataGridView _dataGridView => gridEntryDataGridView;
|
||||||
|
|
||||||
public ProductsGrid()
|
public ProductsGrid()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// sorting breaks filters. must reapply filters after sorting
|
// sorting breaks filters. must reapply filters after sorting
|
||||||
_dataGridView.Sorted += (_, __) => Filter();
|
_dataGridView.Sorted += (_, __) => Filter();
|
||||||
_dataGridView.CellContentClick += DataGridView_CellContentClick;
|
_dataGridView.CellContentClick += DataGridView_CellContentClick;
|
||||||
|
|
||||||
EnableDoubleBuffering();
|
EnableDoubleBuffering();
|
||||||
}
|
}
|
||||||
private void EnableDoubleBuffering()
|
private void EnableDoubleBuffering()
|
||||||
{
|
{
|
||||||
var propertyInfo = _dataGridView.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
var propertyInfo = _dataGridView.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||||
|
|
||||||
propertyInfo.SetValue(_dataGridView, true, null);
|
propertyInfo.SetValue(_dataGridView, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Button controls
|
#region Button controls
|
||||||
|
|
||||||
private async void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
private async void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||||
{
|
{
|
||||||
// handle grid button click: https://stackoverflow.com/a/13687844
|
// handle grid button click: https://stackoverflow.com/a/13687844
|
||||||
if (e.RowIndex < 0 || _dataGridView.Columns[e.ColumnIndex] is not DataGridViewButtonColumn)
|
if (e.RowIndex < 0 || _dataGridView.Columns[e.ColumnIndex] is not DataGridViewButtonColumn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var liveGridEntry = getGridEntry(e.RowIndex);
|
var liveGridEntry = getGridEntry(e.RowIndex);
|
||||||
|
|
||||||
switch (_dataGridView.Columns[e.ColumnIndex].DataPropertyName)
|
switch (_dataGridView.Columns[e.ColumnIndex].DataPropertyName)
|
||||||
{
|
{
|
||||||
case nameof(liveGridEntry.Liberate):
|
case nameof(liveGridEntry.Liberate):
|
||||||
await Liberate_Click(liveGridEntry);
|
await Liberate_Click(liveGridEntry);
|
||||||
break;
|
break;
|
||||||
case nameof(liveGridEntry.DisplayTags):
|
case nameof(liveGridEntry.DisplayTags):
|
||||||
EditTags_Click(liveGridEntry);
|
EditTags_Click(liveGridEntry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Liberate_Click(GridEntry liveGridEntry)
|
private async Task Liberate_Click(GridEntry liveGridEntry)
|
||||||
{
|
{
|
||||||
var libraryBook = liveGridEntry.LibraryBook;
|
var libraryBook = liveGridEntry.LibraryBook;
|
||||||
|
|
||||||
// liberated: open explorer to file
|
// liberated: open explorer to file
|
||||||
if (TransitionalFileLocator.Audio_Exists(libraryBook.Book))
|
if (TransitionalFileLocator.Audio_Exists(libraryBook.Book))
|
||||||
{
|
{
|
||||||
var filePath = TransitionalFileLocator.Audio_GetPath(libraryBook.Book);
|
var filePath = TransitionalFileLocator.Audio_GetPath(libraryBook.Book);
|
||||||
if (!Go.To.File(filePath))
|
if (!Go.To.File(filePath))
|
||||||
MessageBox.Show($"File not found:\r\n{filePath}");
|
MessageBox.Show($"File not found:\r\n{filePath}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// else: liberate
|
// else: liberate
|
||||||
await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(libraryBook, (_, __) => RefreshRow(libraryBook.Book.AudibleProductId));
|
await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(libraryBook, (_, __) => RefreshRow(libraryBook.Book.AudibleProductId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditTags_Click(GridEntry liveGridEntry)
|
private void EditTags_Click(GridEntry liveGridEntry)
|
||||||
{
|
{
|
||||||
var bookDetailsForm = new BookDetailsDialog(liveGridEntry.Title, liveGridEntry.LibraryBook.Book.UserDefinedItem.Tags);
|
var bookDetailsForm = new BookDetailsDialog(liveGridEntry.Title, liveGridEntry.LibraryBook.Book.UserDefinedItem.Tags);
|
||||||
if (bookDetailsForm.ShowDialog() != DialogResult.OK)
|
if (bookDetailsForm.ShowDialog() != DialogResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var qtyChanges = LibraryCommands.UpdateTags(liveGridEntry.LibraryBook.Book, bookDetailsForm.NewTags);
|
var qtyChanges = LibraryCommands.UpdateTags(liveGridEntry.LibraryBook.Book, bookDetailsForm.NewTags);
|
||||||
if (qtyChanges == 0)
|
if (qtyChanges == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Re-apply filters
|
//Re-apply filters
|
||||||
Filter();
|
Filter();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region UI display functions
|
#region UI display functions
|
||||||
|
|
||||||
private bool hasBeenDisplayed = false;
|
private bool hasBeenDisplayed = false;
|
||||||
public void Display()
|
public void Display()
|
||||||
{
|
{
|
||||||
if (hasBeenDisplayed)
|
if (hasBeenDisplayed)
|
||||||
return;
|
return;
|
||||||
hasBeenDisplayed = true;
|
hasBeenDisplayed = true;
|
||||||
|
|
||||||
//
|
//
|
||||||
// transform into sorted GridEntry.s BEFORE binding
|
// transform into sorted GridEntry.s BEFORE binding
|
||||||
//
|
//
|
||||||
using var context = DbContexts.GetContext();
|
using var context = DbContexts.GetContext();
|
||||||
var lib = context.GetLibrary_Flat_NoTracking();
|
var lib = context.GetLibrary_Flat_NoTracking();
|
||||||
|
|
||||||
// if no data. hide all columns. return
|
// if no data. hide all columns. return
|
||||||
if (!lib.Any())
|
if (!lib.Any())
|
||||||
{
|
{
|
||||||
for (var i = _dataGridView.ColumnCount - 1; i >= 0; i--)
|
for (var i = _dataGridView.ColumnCount - 1; i >= 0; i--)
|
||||||
_dataGridView.Columns.RemoveAt(i);
|
_dataGridView.Columns.RemoveAt(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var orderedGridEntries = lib
|
var orderedGridEntries = lib
|
||||||
.Select(lb => new GridEntry(lb)).ToList()
|
.Select(lb => new GridEntry(lb)).ToList()
|
||||||
// default load order
|
// default load order
|
||||||
.OrderByDescending(ge => (DateTime)ge.GetMemberValue(nameof(ge.PurchaseDate)))
|
.OrderByDescending(ge => (DateTime)ge.GetMemberValue(nameof(ge.PurchaseDate)))
|
||||||
//// more advanced example: sort by author, then series, then title
|
//// more advanced example: sort by author, then series, then title
|
||||||
//.OrderBy(ge => ge.Authors)
|
//.OrderBy(ge => ge.Authors)
|
||||||
// .ThenBy(ge => ge.Series)
|
// .ThenBy(ge => ge.Series)
|
||||||
// .ThenBy(ge => ge.Title)
|
// .ThenBy(ge => ge.Title)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// BIND
|
// BIND
|
||||||
gridEntryBindingSource.DataSource = new SortableBindingList2<GridEntry>(orderedGridEntries);
|
gridEntryBindingSource.DataSource = new SortableBindingList2<GridEntry>(orderedGridEntries);
|
||||||
|
|
||||||
// FILTER
|
// FILTER
|
||||||
Filter();
|
Filter();
|
||||||
|
|
||||||
BackupCountsChanged?.Invoke(this, EventArgs.Empty);
|
BackupCountsChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RefreshRow(string productId)
|
public void RefreshRow(string productId)
|
||||||
{
|
{
|
||||||
var rowIndex = getRowIndex((ge) => ge.AudibleProductId == productId);
|
var rowIndex = getRowIndex((ge) => ge.AudibleProductId == productId);
|
||||||
|
|
||||||
// update cells incl Liberate button text
|
// update cells incl Liberate button text
|
||||||
_dataGridView.InvalidateRow(rowIndex);
|
_dataGridView.InvalidateRow(rowIndex);
|
||||||
|
|
||||||
// needed in case filtering by -IsLiberated and it gets changed to Liberated. want to immediately show the change
|
// needed in case filtering by -IsLiberated and it gets changed to Liberated. want to immediately show the change
|
||||||
Filter();
|
Filter();
|
||||||
|
|
||||||
BackupCountsChanged?.Invoke(this, EventArgs.Empty);
|
BackupCountsChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Filter
|
#region Filter
|
||||||
|
|
||||||
string _filterSearchString;
|
private string _filterSearchString;
|
||||||
private void Filter() => Filter(_filterSearchString);
|
private void Filter() => Filter(_filterSearchString);
|
||||||
public void Filter(string searchString)
|
public void Filter(string searchString)
|
||||||
{
|
{
|
||||||
_filterSearchString = searchString;
|
_filterSearchString = searchString;
|
||||||
|
|
||||||
if (_dataGridView.Rows.Count == 0)
|
if (_dataGridView.Rows.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var searchResults = SearchEngineCommands.Search(searchString);
|
var searchResults = SearchEngineCommands.Search(searchString);
|
||||||
var productIds = searchResults.Docs.Select(d => d.ProductId).ToList();
|
var productIds = searchResults.Docs.Select(d => d.ProductId).ToList();
|
||||||
|
|
||||||
// https://stackoverflow.com/a/18942430
|
// https://stackoverflow.com/a/18942430
|
||||||
var bindingContext = BindingContext[_dataGridView.DataSource];
|
var bindingContext = BindingContext[_dataGridView.DataSource];
|
||||||
bindingContext.SuspendBinding();
|
bindingContext.SuspendBinding();
|
||||||
{
|
{
|
||||||
for (var r = _dataGridView.RowCount - 1; r >= 0; r--)
|
for (var r = _dataGridView.RowCount - 1; r >= 0; r--)
|
||||||
_dataGridView.Rows[r].Visible = productIds.Contains(getGridEntry(r).AudibleProductId);
|
_dataGridView.Rows[r].Visible = productIds.Contains(getGridEntry(r).AudibleProductId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Causes repainting of the DataGridView
|
//Causes repainting of the DataGridView
|
||||||
bindingContext.ResumeBinding();
|
bindingContext.ResumeBinding();
|
||||||
VisibleCountChanged?.Invoke(this, _dataGridView.AsEnumerable().Count(r => r.Visible));
|
VisibleCountChanged?.Invoke(this, _dataGridView.AsEnumerable().Count(r => r.Visible));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region DataGridView Macro
|
#region DataGridView Macro
|
||||||
|
|
||||||
private int getRowIndex(Func<GridEntry, bool> func) => _dataGridView.GetRowIdOfBoundItem(func);
|
private int getRowIndex(Func<GridEntry, bool> func) => _dataGridView.GetRowIdOfBoundItem(func);
|
||||||
private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem<GridEntry>(rowIndex);
|
private GridEntry getGridEntry(int rowIndex) => _dataGridView.GetBoundItem<GridEntry>(rowIndex);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,75 +1,74 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
{
|
{
|
||||||
class SortableBindingList2<T> : BindingList<T> where T : IObjectMemberComparable
|
internal class SortableBindingList2<T> : BindingList<T> where T : IObjectMemberComparable
|
||||||
{
|
{
|
||||||
private bool isSorted;
|
private bool isSorted;
|
||||||
private ListSortDirection listSortDirection;
|
private ListSortDirection listSortDirection;
|
||||||
private PropertyDescriptor propertyDescriptor;
|
private PropertyDescriptor propertyDescriptor;
|
||||||
|
|
||||||
public SortableBindingList2() : base(new List<T>()) { }
|
public SortableBindingList2() : base(new List<T>()) { }
|
||||||
public SortableBindingList2(IEnumerable<T> enumeration) : base(new List<T>(enumeration)) { }
|
public SortableBindingList2(IEnumerable<T> enumeration) : base(new List<T>(enumeration)) { }
|
||||||
|
|
||||||
private ObjectMemberComparer<T> Comparer { get; } = new();
|
private ObjectMemberComparer<T> Comparer { get; } = new();
|
||||||
protected override bool SupportsSortingCore => true;
|
protected override bool SupportsSortingCore => true;
|
||||||
protected override bool SupportsSearchingCore => true;
|
protected override bool SupportsSearchingCore => true;
|
||||||
protected override bool IsSortedCore => isSorted;
|
protected override bool IsSortedCore => isSorted;
|
||||||
protected override PropertyDescriptor SortPropertyCore => propertyDescriptor;
|
protected override PropertyDescriptor SortPropertyCore => propertyDescriptor;
|
||||||
protected override ListSortDirection SortDirectionCore => listSortDirection;
|
protected override ListSortDirection SortDirectionCore => listSortDirection;
|
||||||
|
|
||||||
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
|
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
|
||||||
{
|
{
|
||||||
List<T> itemsList = (List<T>)Items;
|
List<T> itemsList = (List<T>)Items;
|
||||||
|
|
||||||
Comparer.PropertyName = property.Name;
|
Comparer.PropertyName = property.Name;
|
||||||
Comparer.Direction = direction;
|
Comparer.Direction = direction;
|
||||||
|
|
||||||
//Array.Sort() and List<T>.Sort() are unstable sorts. OrderBy is stable.
|
//Array.Sort() and List<T>.Sort() are unstable sorts. OrderBy is stable.
|
||||||
var sortedItems = itemsList.OrderBy((ge) => ge, Comparer).ToList();
|
var sortedItems = itemsList.OrderBy((ge) => ge, Comparer).ToList();
|
||||||
|
|
||||||
itemsList.Clear();
|
itemsList.Clear();
|
||||||
itemsList.AddRange(sortedItems);
|
itemsList.AddRange(sortedItems);
|
||||||
|
|
||||||
propertyDescriptor = property;
|
propertyDescriptor = property;
|
||||||
listSortDirection = direction;
|
listSortDirection = direction;
|
||||||
isSorted = true;
|
isSorted = true;
|
||||||
|
|
||||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void RemoveSortCore()
|
protected override void RemoveSortCore()
|
||||||
{
|
{
|
||||||
isSorted = false;
|
isSorted = false;
|
||||||
propertyDescriptor = base.SortPropertyCore;
|
propertyDescriptor = base.SortPropertyCore;
|
||||||
listSortDirection = base.SortDirectionCore;
|
listSortDirection = base.SortDirectionCore;
|
||||||
|
|
||||||
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
|
||||||
}
|
}
|
||||||
//NOTE: Libation does not currently use BindingSource.Find anywhere,
|
//NOTE: Libation does not currently use BindingSource.Find anywhere,
|
||||||
//so this override may be removed (along with SupportsSearchingCore)
|
//so this override may be removed (along with SupportsSearchingCore)
|
||||||
protected override int FindCore(PropertyDescriptor property, object key)
|
protected override int FindCore(PropertyDescriptor property, object key)
|
||||||
{
|
{
|
||||||
int count = Count;
|
int count = Count;
|
||||||
|
|
||||||
System.Collections.IComparer valueComparer = null;
|
System.Collections.IComparer valueComparer = null;
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
T element = this[i];
|
T element = this[i];
|
||||||
var elemValue = element.GetMemberValue(property.Name);
|
var elemValue = element.GetMemberValue(property.Name);
|
||||||
valueComparer ??= element.GetMemberComparer(elemValue.GetType());
|
valueComparer ??= element.GetMemberComparer(elemValue.GetType());
|
||||||
|
|
||||||
if (valueComparer.Compare(elemValue, key) == 0)
|
if (valueComparer.Compare(elemValue, key) == 0)
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user