From b35a831afca7330494e25934fa8607a6c863ca6a Mon Sep 17 00:00:00 2001 From: lexikins Date: Wed, 3 Dec 2025 00:30:11 +0000 Subject: [PATCH] Update to .Net 9.0 --- .gitignore | 35 + .../Audible.json.core.csproj | 2 +- src/AuxLib.core/AuxLib.core.csproj | 2 +- .../AuxWin.DialogBox.core.csproj | 2 +- src/AuxWin.lib.core/AuxWin.lib.core.csproj | 2 +- src/AuxWin32Lib.core/AuxWin32Lib.core.csproj | 2 +- .../BooksDatabase.core.csproj | 2 +- .../CommonTypes.lib.core.csproj | 2 +- .../CommonUtil.lib.core.csproj | 2 +- .../Connect.app.gui.core.csproj | 2 +- src/Connect.lib.core/Connect.lib.core.csproj | 2 +- src/Connect.ui.lib.core/BookLibDGVControl.cs | 687 +++++++------- src/Connect.ui.lib.core/BookLibForm.cs | 456 ++++----- .../Connect.ui.lib.core.csproj | 2 +- src/Connect.ui.lib.core/ConvertDGVControl.cs | 881 ++++++++++-------- src/Connect.ui.lib.core/DataGridViewEx.cs | 345 +++---- src/PropGridLib.core/PropGridLib.core.csproj | 2 +- src/PropGridLib.core/PropertyGridExtension.cs | 148 +-- src/SystemMgmt.core/SystemMgmt.core.csproj | 2 +- .../TreeDecomposition.core.csproj | 2 +- 20 files changed, 1414 insertions(+), 1166 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..912d495 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/.vs +/src/.vs +/src/Audible.json.core/bin +/src/Audible.json.core/obj +/src/AuxLib.core/bin +/src/AuxLib.core/obj +/src/AuxWin.DialogBox.core/bin +/src/AuxWin.lib.core/bin +/src/AuxWin32Lib.core/bin +/src/BooksDatabase.core/bin +/src/CommonTypes.lib.core/bin +/src/CommonUtil.lib.core/bin +/src/Connect.app.gui.core/bin +/src/Connect.lib.core/bin +/src/Connect.ui.lib.core/bin +/src/PropGridLib.core/bin +/src/SystemMgmt.core/bin +/src/TreeDecomposition.core/bin +/src/AuxWin.DialogBox.core/obj +/src/AuxWin.lib.core/obj +/src/AuxWin32Lib.core/obj +/src/BooksDatabase.core/obj +/src/CommonTypes.lib.core/obj +/src/CommonUtil.lib.core/obj +/src/Connect.app.gui.core/obj +/src/Connect.lib.core/obj +/src/Connect.ui.lib.core/obj +/src/PropGridLib.core/obj +/src/SystemMgmt.core/obj +/src/TreeDecomposition.core/obj +*.user diff --git a/src/Audible.json.core/Audible.json.core.csproj b/src/Audible.json.core/Audible.json.core.csproj index 5083fa4..4d01349 100644 --- a/src/Audible.json.core/Audible.json.core.csproj +++ b/src/Audible.json.core/Audible.json.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.adb.json audiamus.audiible.json.core audiamus diff --git a/src/AuxLib.core/AuxLib.core.csproj b/src/AuxLib.core/AuxLib.core.csproj index f694428..da4de35 100644 --- a/src/AuxLib.core/AuxLib.core.csproj +++ b/src/AuxLib.core/AuxLib.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.aux audiamus.aux.core audiamus diff --git a/src/AuxWin.DialogBox.core/AuxWin.DialogBox.core.csproj b/src/AuxWin.DialogBox.core/AuxWin.DialogBox.core.csproj index b6c320f..491007f 100644 --- a/src/AuxWin.DialogBox.core/AuxWin.DialogBox.core.csproj +++ b/src/AuxWin.DialogBox.core/AuxWin.DialogBox.core.csproj @@ -1,7 +1,7 @@ - net6.0-windows + net10.0-windows true core.audiamus.aux.win audiamus.aux.win.dialogbox.core diff --git a/src/AuxWin.lib.core/AuxWin.lib.core.csproj b/src/AuxWin.lib.core/AuxWin.lib.core.csproj index b3c301d..1287422 100644 --- a/src/AuxWin.lib.core/AuxWin.lib.core.csproj +++ b/src/AuxWin.lib.core/AuxWin.lib.core.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net10.0-windows true core.audiamus.aux.win audiamus.aux.win.core diff --git a/src/AuxWin32Lib.core/AuxWin32Lib.core.csproj b/src/AuxWin32Lib.core/AuxWin32Lib.core.csproj index 76c202a..d08b07f 100644 --- a/src/AuxWin32Lib.core/AuxWin32Lib.core.csproj +++ b/src/AuxWin32Lib.core/AuxWin32Lib.core.csproj @@ -1,7 +1,7 @@  - net6.0 + net10.0 core.audiamus.aux.w32 audiamus.aux.w32.core audiamus diff --git a/src/BooksDatabase.core/BooksDatabase.core.csproj b/src/BooksDatabase.core/BooksDatabase.core.csproj index 5408028..bf9af5d 100644 --- a/src/BooksDatabase.core/BooksDatabase.core.csproj +++ b/src/BooksDatabase.core/BooksDatabase.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.booksdb audiamus.booksdb.core audiamus diff --git a/src/CommonTypes.lib.core/CommonTypes.lib.core.csproj b/src/CommonTypes.lib.core/CommonTypes.lib.core.csproj index 12ec226..94f394b 100644 --- a/src/CommonTypes.lib.core/CommonTypes.lib.core.csproj +++ b/src/CommonTypes.lib.core/CommonTypes.lib.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.common audiamus.common.types.core audiamus diff --git a/src/CommonUtil.lib.core/CommonUtil.lib.core.csproj b/src/CommonUtil.lib.core/CommonUtil.lib.core.csproj index d3cd342..2cee77b 100644 --- a/src/CommonUtil.lib.core/CommonUtil.lib.core.csproj +++ b/src/CommonUtil.lib.core/CommonUtil.lib.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.util audiamus.common.util.core audiamus diff --git a/src/Connect.app.gui.core/Connect.app.gui.core.csproj b/src/Connect.app.gui.core/Connect.app.gui.core.csproj index 3940346..7e22c9c 100644 --- a/src/Connect.app.gui.core/Connect.app.gui.core.csproj +++ b/src/Connect.app.gui.core/Connect.app.gui.core.csproj @@ -2,7 +2,7 @@ WinExe - net6.0-windows + net10.0-windows true audiamus BookLibConnect diff --git a/src/Connect.lib.core/Connect.lib.core.csproj b/src/Connect.lib.core/Connect.lib.core.csproj index 2097691..c67873d 100644 --- a/src/Connect.lib.core/Connect.lib.core.csproj +++ b/src/Connect.lib.core/Connect.lib.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 audiamus core.audiamus.connect audiamus.connect.core diff --git a/src/Connect.ui.lib.core/BookLibDGVControl.cs b/src/Connect.ui.lib.core/BookLibDGVControl.cs index 9de0066..e7d93f0 100644 --- a/src/Connect.ui.lib.core/BookLibDGVControl.cs +++ b/src/Connect.ui.lib.core/BookLibDGVControl.cs @@ -14,375 +14,434 @@ using static core.audiamus.aux.Logging; using R = core.audiamus.connect.ui.Properties.Resources; +using System.ComponentModel; + +namespace core.audiamus.connect.ui +{ + + public partial class BookLibDGVControl : UserControl + { + private ResourceManager RM { get; } + + private SortableBindingList DataSource { get; set; } + private List CurrentlySelectedBooks { get; } = new List(); + + private bool _ignoreFlag; + private IEnumerable _allBooks; + private IEnumerable _allConversions; + private IEnumerable SelectedBooks => CurrentlySelectedBooks.Select(b => b.Book).ToList(); + private List SelectedBooksForDownload { get; } = new List(); + private bool _isSortingAftermath; + private BookDataSource _firstDisplayedBook; + private BookDataSource _firstDisplayedSelectedBook; + private int _firstDisplayedSelectedBookOffset; + private Color? _defaultCellBackColor; + private IDownloadSettings _settings; + + private static readonly Color __downloadSelectCellBackColor = Color.LightCyan; + + public event BookSelectionChangedEventHandler BookSelectionChanged; + public event BookSelectionChangedEventHandler BookDownloadSelectionChanged; + public event ConversionUpdatedEventHandler ConversionUpdated; + public event EventHandler Close; + public event EventHandler Resync; + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IEnumerable Books { set => setDataSource(value); } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDownloadSettings Settings + { + private get => _settings; + set + { + _settings = value; + _settings.ChangedSettings += settings_ChangedSettings; + } + } -namespace core.audiamus.connect.ui { - - public partial class BookLibDGVControl : UserControl { - private ResourceManager RM { get; } - - private SortableBindingList DataSource { get; set; } - private List CurrentlySelectedBooks { get; } = new List (); - - private bool _ignoreFlag; - private IEnumerable _allBooks; - private IEnumerable _allConversions; - private IEnumerable SelectedBooks => CurrentlySelectedBooks.Select (b => b.Book).ToList (); - private List SelectedBooksForDownload { get; } = new List (); - private bool _isSortingAftermath; - private BookDataSource _firstDisplayedBook; - private BookDataSource _firstDisplayedSelectedBook; - private int _firstDisplayedSelectedBookOffset; - private Color? _defaultCellBackColor; - private IDownloadSettings _settings; - - private static readonly Color __downloadSelectCellBackColor = Color.LightCyan; - - public event BookSelectionChangedEventHandler BookSelectionChanged; - public event BookSelectionChangedEventHandler BookDownloadSelectionChanged; - public event ConversionUpdatedEventHandler ConversionUpdated; - public event EventHandler Close; - public event EventHandler Resync; - - public IEnumerable Books { set => setDataSource (value); } - - public IDownloadSettings Settings { - private get => _settings; - set { - _settings = value; - _settings.ChangedSettings += settings_ChangedSettings; - } - } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DownloadSelectEnabled + { + get => panelDownloadSelect.Enabled; + set => panelDownloadSelect.Enabled = value; + } - public bool DownloadSelectEnabled { - get => panelDownloadSelect.Enabled; - set => panelDownloadSelect.Enabled = value; - } + public BookLibDGVControl() + { + InitializeComponent(); - public BookLibDGVControl () { - InitializeComponent (); + RM = this.GetDefaultResourceManager(); + } - RM = this.GetDefaultResourceManager (); - } + private void settings_ChangedSettings(object sender, EventArgs e) + { + resetDataSource(_allBooks); + onUpdatedSettings(); + } - private void settings_ChangedSettings (object sender, EventArgs e) { - resetDataSource (_allBooks); - onUpdatedSettings (); - } + public void UpdateDownloads(IEnumerable books) + { + using var lg = new LogGuard(1, this, () => $"#books={books.Count()}"); + using var rg = new ResourceGuard(x => _ignoreFlag = x); - public void UpdateDownloads (IEnumerable books) { - using var lg = new LogGuard (1, this, () => $"#books={books.Count ()}"); - using var rg = new ResourceGuard (x => _ignoreFlag = x); + var booksToBeRemoved = SelectedBooksForDownload.Except(books).ToList(); - var booksToBeRemoved = SelectedBooksForDownload.Except (books).ToList (); + revertDownloadSelection(booksToBeRemoved, true); + } - revertDownloadSelection (booksToBeRemoved, true); - } + public void UpdateConversion(Conversion conversion) + { + var book = conversion.ParentBook; + resetDataSourceItem(book); + } - public void UpdateConversion (Conversion conversion) { - var book = conversion.ParentBook; - resetDataSourceItem (book); - } + public void UpdateConversionStateFromOther(IConversion other) + { + var conv = _allConversions.FirstOrDefault(c => c.Id == other.Id); + if (conv is null) + return; + conv.State = other.State; + UpdateConversion(conv); + ConversionUpdated?.Invoke(this, new ConversionEventArgs(conv)); + } - public void UpdateConversionStateFromOther (IConversion other) { - var conv = _allConversions.FirstOrDefault (c => c.Id == other.Id); - if (conv is null) - return; - conv.State = other.State; - UpdateConversion (conv); - ConversionUpdated?.Invoke (this, new ConversionEventArgs (conv)); - } + private void resetDataSource(IEnumerable allBooks) + { + if (allBooks is null) + return; + IEnumerable books = allBooks.ToList(); + + if (!Settings.IncludeAdultProducts) + books = books.Where(b => !(b.AdultProduct ?? false)); + + if (Settings.HideUnavailableProducts) + books = books.Where(b => b.ApplicableState(Settings.MultiPartDownload) != EConversionState.unknown); + + Log(3, this, () => $"#books={allBooks.Count()} (filtered)"); + + IEnumerable initiallySortedBooks = Settings.InitialSorting switch + { + EInitialSorting.state_date => books + .OrderBy(b => b.ApplicableState(Settings.MultiPartDownload)) + .ThenByDescending(b => b.PurchaseDate), + EInitialSorting.date => books + .OrderByDescending(b => b.PurchaseDate), + EInitialSorting.author_title => books + .OrderBy(b => b.Author) + .ThenBy(b => b.Title), + EInitialSorting.author_date => books + .OrderBy(b => b.Author) + .ThenByDescending(b => b.PurchaseDate), + EInitialSorting.title_author => books + .OrderBy(b => b.Title) + .ThenBy(b => b.Author), + _ => books.OrderBy(b => b.ApplicableState(Settings.MultiPartDownload)) + }; + + books = initiallySortedBooks.ToList(); + var booksDS = new List(); + foreach (var book in books) + booksDS.Add(new BookDataSource(book, Settings)); + + DataSource = new SortableBindingList(booksDS) + { + UseBackingProperties = true + }; + + this.dataGridView1.DataSource = DataSource; + } - private void resetDataSource (IEnumerable allBooks) { - if (allBooks is null) - return; - IEnumerable books = allBooks.ToList (); - - if (!Settings.IncludeAdultProducts) - books = books.Where (b => !(b.AdultProduct ?? false)); - - if (Settings.HideUnavailableProducts) - books = books.Where (b => b.ApplicableState (Settings.MultiPartDownload) != EConversionState.unknown); - - Log (3, this, () => $"#books={allBooks.Count ()} (filtered)"); - - IEnumerable initiallySortedBooks = Settings.InitialSorting switch { - EInitialSorting.state_date => books - .OrderBy (b => b.ApplicableState (Settings.MultiPartDownload)) - .ThenByDescending (b => b.PurchaseDate), - EInitialSorting.date => books - .OrderByDescending (b => b.PurchaseDate), - EInitialSorting.author_title => books - .OrderBy (b => b.Author) - .ThenBy (b => b.Title), - EInitialSorting.author_date => books - .OrderBy (b => b.Author) - .ThenByDescending (b => b.PurchaseDate), - EInitialSorting.title_author => books - .OrderBy (b => b.Title) - .ThenBy (b => b.Author), - _ => books.OrderBy (b => b.ApplicableState (Settings.MultiPartDownload)) - }; - - books = initiallySortedBooks.ToList (); - var booksDS = new List (); - foreach (var book in books) - booksDS.Add (new BookDataSource (book, Settings)); - - DataSource = new SortableBindingList (booksDS) { - UseBackingProperties = true - }; - - this.dataGridView1.DataSource = DataSource; - } + private void setDataSource(IEnumerable allBooks) + { + if (allBooks is null) + return; - private void setDataSource (IEnumerable allBooks) { - if (allBooks is null) - return; + // HACK currently exclude podcasts + allBooks = allBooks + .Where(b => b.DeliveryType == EDeliveryType.SinglePartBook || b.DeliveryType == EDeliveryType.MultiPartBook) + .ToList(); - // HACK currently exclude podcasts - allBooks = allBooks - .Where (b => b.DeliveryType == EDeliveryType.SinglePartBook || b.DeliveryType == EDeliveryType.MultiPartBook) - .ToList (); + Log(3, this, () => $"#books={allBooks.Count()} (deliv type filtered)"); - Log (3, this, () => $"#books={allBooks.Count ()} (deliv type filtered)"); + _allBooks = allBooks; + resetDataSource(allBooks); - _allBooks = allBooks; - resetDataSource (allBooks); + var allConversions = _allBooks.Select(b => b.Conversion).ToList(); + var allCompConversions = _allBooks.SelectMany(b => b.Components).Select(c => c.Conversion).ToList(); + allConversions.AddRange(allCompConversions); + allConversions.Sort((x, y) => x.Id.CompareTo(y.Id)); + _allConversions = allConversions; - var allConversions = _allBooks.Select (b => b.Conversion).ToList (); - var allCompConversions = _allBooks.SelectMany (b => b.Components).Select (c => c.Conversion).ToList (); - allConversions.AddRange (allCompConversions); - allConversions.Sort ((x, y) => x.Id.CompareTo (y.Id)); - _allConversions = allConversions; + } - } + private void onUpdatedSettings() + { + var clm = dataGridView1.Columns[nameof(BookDataSource.Adult)]; + if (clm is null) + return; + clm.Visible = Settings.IncludeAdultProducts; + } - private void onUpdatedSettings () { - var clm = dataGridView1.Columns[nameof (BookDataSource.Adult)]; - if (clm is null) - return; - clm.Visible = Settings.IncludeAdultProducts; - } + private void resetDataSourceItem(Book book) + { + int? i = DataSource.Select((s, i) => new { s, i }).FirstOrDefault(k => k.s.DataSource == book)?.i; + if (i.HasValue) + DataSource.ResetItem(i.Value); + } - private void resetDataSourceItem (Book book) { - int? i = DataSource.Select ((s, i) => new { s, i }).FirstOrDefault (k => k.s.DataSource == book)?.i; - if (i.HasValue) - DataSource.ResetItem (i.Value); - } + private void dataGridView1_BeginSorting(object sender, EventArgs e) + { + int firstDisplayedRowIdx = dataGridView1.FirstDisplayedScrollingRowIndex; + _firstDisplayedBook = DataSource[firstDisplayedRowIdx]; + + _firstDisplayedSelectedBookOffset = 0; + _firstDisplayedSelectedBook = null; + if (dataGridView1.SelectedRows.Count > 0) + { + // is the 1st selected book visible? + int firstSelBookRowIdx = dataGridView1.SelectedRows[0].Index; + int offs = firstSelBookRowIdx - firstDisplayedRowIdx; + int nVisRows = dataGridView1.Rows.GetRowCount(DataGridViewElementStates.Displayed); + if (offs <= nVisRows) + { + _firstDisplayedSelectedBook = DataSource[firstSelBookRowIdx]; + _firstDisplayedSelectedBookOffset = offs; + } + } - private void dataGridView1_BeginSorting (object sender, EventArgs e) { - int firstDisplayedRowIdx = dataGridView1.FirstDisplayedScrollingRowIndex; - _firstDisplayedBook = DataSource[firstDisplayedRowIdx]; - - _firstDisplayedSelectedBookOffset = 0; - _firstDisplayedSelectedBook = null; - if (dataGridView1.SelectedRows.Count > 0) { - // is the 1st selected book visible? - int firstSelBookRowIdx = dataGridView1.SelectedRows[0].Index; - int offs = firstSelBookRowIdx - firstDisplayedRowIdx; - int nVisRows = dataGridView1.Rows.GetRowCount (DataGridViewElementStates.Displayed); - if (offs <= nVisRows) { - _firstDisplayedSelectedBook = DataSource[firstSelBookRowIdx]; - _firstDisplayedSelectedBookOffset = offs; } - } - } + private void dataGridView1_EndSorting(object sender, EventArgs e) + { + dataGridView1.ClearSelection(); + + if (CurrentlySelectedBooks.Any()) + { + var selectedRows = new List(); + foreach (var book in CurrentlySelectedBooks) + { + int idx = DataSource.IndexOf(book); + selectedRows.Add(idx); + } + selectedRows.Sort(); + foreach (var rowIdx in selectedRows) + dataGridView1.Rows[rowIdx].Selected = true; + } + else + _isSortingAftermath = true; + + if (SelectedBooksForDownload.Any()) + { + foreach (var book in SelectedBooksForDownload) + { + int idx = DataSource.IndexOf(book); + dataGridView1.Rows[idx].DefaultCellStyle.BackColor = Color.Azure; + } + } - private void dataGridView1_EndSorting (object sender, EventArgs e) { - dataGridView1.ClearSelection (); - - if (CurrentlySelectedBooks.Any ()) { - var selectedRows = new List (); - foreach (var book in CurrentlySelectedBooks) { - int idx = DataSource.IndexOf (book); - selectedRows.Add (idx); - } - selectedRows.Sort (); - foreach (var rowIdx in selectedRows) - dataGridView1.Rows[rowIdx].Selected = true; - } else - _isSortingAftermath = true; - - if (SelectedBooksForDownload.Any ()) { - foreach (var book in SelectedBooksForDownload) { - int idx = DataSource.IndexOf (book); - dataGridView1.Rows[idx].DefaultCellStyle.BackColor = Color.Azure; } - } - - } - private void dataGridView1_SortingCompleteToSetVerticalPosition (object sender, EventArgs e) { - int idx; - if (_firstDisplayedSelectedBook is null) { - idx = DataSource.IndexOf (_firstDisplayedBook); - } else { - int selidx = DataSource.IndexOf (_firstDisplayedSelectedBook) - _firstDisplayedSelectedBookOffset; - idx = Math.Max (0, selidx); - } - idx = Math.Min (idx, DataSource.Count - 1); - dataGridView1.FirstDisplayedScrollingRowIndex = idx; - } + private void dataGridView1_SortingCompleteToSetVerticalPosition(object sender, EventArgs e) + { + int idx; + if (_firstDisplayedSelectedBook is null) + { + idx = DataSource.IndexOf(_firstDisplayedBook); + } + else + { + int selidx = DataSource.IndexOf(_firstDisplayedSelectedBook) - _firstDisplayedSelectedBookOffset; + idx = Math.Max(0, selidx); + } + idx = Math.Min(idx, DataSource.Count - 1); + dataGridView1.FirstDisplayedScrollingRowIndex = idx; + } - private void dataGridView1_DataBindingComplete (object sender, DataGridViewBindingCompleteEventArgs e) { - onUpdatedSettings (); - } - + private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) + { + onUpdatedSettings(); + } - private void dataGridView1_SelectionChanged (object sender, EventArgs e) { - if (_isSortingAftermath) { - _isSortingAftermath = false; - dataGridView1.ClearSelection (); - return; - } - renewCurrentylSelectBooksSorted (); + private void dataGridView1_SelectionChanged(object sender, EventArgs e) + { + if (_isSortingAftermath) + { + _isSortingAftermath = false; + dataGridView1.ClearSelection(); + return; + } - enableDownloadButtons (); + renewCurrentylSelectBooksSorted(); - BookSelectionChanged?.Invoke (this, new BookEventArgs (SelectedBooks)); - } + enableDownloadButtons(); - private void renewCurrentylSelectBooksSorted () { - CurrentlySelectedBooks.Clear (); - dataGridView1.AddSelectedRowsSortedByIndex (CurrentlySelectedBooks, book => book, DataSource, selectable); - - bool selectable (int idx) { - try { - var item = DataSource[idx]; - var state = item.Book.ApplicableState (Settings.MultiPartDownload); - return state > EConversionState.unknown; - } catch (Exception exc) { - Log (1, this, exc.Summary ()); + BookSelectionChanged?.Invoke(this, new BookEventArgs(SelectedBooks)); } - return true; - } - } - - private void enableDownloadButtons () { - var selectedBooks = SelectedBooks; - var addBooks = selectedBooks.Except (SelectedBooksForDownload); - btnAddSel.Enabled = addBooks.Any (); - - var remBooks = selectedBooks.Intersect (SelectedBooksForDownload); - btnRemSel.Enabled = remBooks.Any (); - - btnRemAll.Enabled = SelectedBooksForDownload.Any (); - } + private void renewCurrentylSelectBooksSorted() + { + CurrentlySelectedBooks.Clear(); + dataGridView1.AddSelectedRowsSortedByIndex(CurrentlySelectedBooks, book => book, DataSource, selectable); + + bool selectable(int idx) + { + try + { + var item = DataSource[idx]; + var state = item.Book.ApplicableState(Settings.MultiPartDownload); + return state > EConversionState.unknown; + } + catch (Exception exc) + { + Log(1, this, exc.Summary()); + } + return true; + } + } - private void btnOk_Click (object sender, EventArgs e) { - Close?.Invoke (this, EventArgs.Empty); - } + private void enableDownloadButtons() + { + var selectedBooks = SelectedBooks; + var addBooks = selectedBooks.Except(SelectedBooksForDownload); + btnAddSel.Enabled = addBooks.Any(); - private void btnAddSel_Click (object sender, EventArgs e) { - var addBooks = SelectedBooks - .Except (SelectedBooksForDownload) - .ToList (); - - SelectedBooksForDownload.AddRange (addBooks); - - foreach (var book in addBooks) { - //book.Conversion.PrevState = book.ApplicableState (Settings); - //book.Conversion.State = EConversionState.download; - setStateForDownload (book); - int idx = DataSource.IndexOf (book); - if (!_defaultCellBackColor.HasValue) - _defaultCellBackColor = dataGridView1.Rows[idx].DefaultCellStyle.BackColor; - dataGridView1.Rows[idx].DefaultCellStyle.BackColor = __downloadSelectCellBackColor; - DataSource.ResetItem (idx); - } - - afterDownloadSelectionChanged (); - } + var remBooks = selectedBooks.Intersect(SelectedBooksForDownload); + btnRemSel.Enabled = remBooks.Any(); - private void btnRemSel_Click (object sender, EventArgs e) { - var remBooks = SelectedBooks - .Intersect (SelectedBooksForDownload) - .ToList (); + btnRemAll.Enabled = SelectedBooksForDownload.Any(); + } - revertDownloadSelection (remBooks, true); - } + private void btnOk_Click(object sender, EventArgs e) + { + Close?.Invoke(this, EventArgs.Empty); + } - private void btnRemAll_Click (object sender, EventArgs e) { - var remBooks = SelectedBooksForDownload.ToList (); - SelectedBooksForDownload.Clear (); - revertDownloadSelection (remBooks); - } + private void btnAddSel_Click(object sender, EventArgs e) + { + var addBooks = SelectedBooks + .Except(SelectedBooksForDownload) + .ToList(); + + SelectedBooksForDownload.AddRange(addBooks); + + foreach (var book in addBooks) + { + //book.Conversion.PrevState = book.ApplicableState (Settings); + //book.Conversion.State = EConversionState.download; + setStateForDownload(book); + int idx = DataSource.IndexOf(book); + if (!_defaultCellBackColor.HasValue) + _defaultCellBackColor = dataGridView1.Rows[idx].DefaultCellStyle.BackColor; + dataGridView1.Rows[idx].DefaultCellStyle.BackColor = __downloadSelectCellBackColor; + DataSource.ResetItem(idx); + } + + afterDownloadSelectionChanged(); + } - private void revertDownloadSelection (IEnumerable remBooks, bool remove = false) { - foreach (var book in remBooks) { - if (remove) - SelectedBooksForDownload.Remove (book); + private void btnRemSel_Click(object sender, EventArgs e) + { + var remBooks = SelectedBooks + .Intersect(SelectedBooksForDownload) + .ToList(); - //book.Conversion.State = book.Conversion.PrevState ?? EConversionState.remote; - resetStateForDownload (book); + revertDownloadSelection(remBooks, true); + } - int idx = DataSource.IndexOf (book); - if (idx < 0) - continue; - dataGridView1.Rows[idx].DefaultCellStyle.BackColor = _defaultCellBackColor ?? SystemColors.Window; - DataSource.ResetItem (idx); - } - afterDownloadSelectionChanged (); - } + private void btnRemAll_Click(object sender, EventArgs e) + { + var remBooks = SelectedBooksForDownload.ToList(); + SelectedBooksForDownload.Clear(); + revertDownloadSelection(remBooks); + } - private void afterDownloadSelectionChanged () { - int nBooks = SelectedBooksForDownload.Count; + private void revertDownloadSelection(IEnumerable remBooks, bool remove = false) + { + foreach (var book in remBooks) + { + if (remove) + SelectedBooksForDownload.Remove(book); - if (nBooks > 0) { - int nParts = SelectedBooksForDownload.Select (b => b.Components.Count == 0 ? 1 : b.Components.Count).Sum (); - string info = $"{nBooks} {(nBooks == 1 ? R.Book : R.Books)}" + - $" / {nParts} {(nParts == 1 ? R.Part : R.Parts)}"; + //book.Conversion.State = book.Conversion.PrevState ?? EConversionState.remote; + resetStateForDownload(book); - lblDnloadList.Text = info; - Log (3, this, () => $"download selected: #books={nBooks}, #parts={nParts}"); - } else { - lblDnloadList.Text = null; - Log (3, this, () => "download selected: none"); - } - enableDownloadButtons (); + int idx = DataSource.IndexOf(book); + if (idx < 0) + continue; + dataGridView1.Rows[idx].DefaultCellStyle.BackColor = _defaultCellBackColor ?? SystemColors.Window; + DataSource.ResetItem(idx); + } - if (_ignoreFlag) - return; + afterDownloadSelectionChanged(); + } - BookDownloadSelectionChanged?.Invoke (this, new BookEventArgs (SelectedBooksForDownload)); - } + private void afterDownloadSelectionChanged() + { + int nBooks = SelectedBooksForDownload.Count; + + if (nBooks > 0) + { + int nParts = SelectedBooksForDownload.Select(b => b.Components.Count == 0 ? 1 : b.Components.Count).Sum(); + string info = $"{nBooks} {(nBooks == 1 ? R.Book : R.Books)}" + + $" / {nParts} {(nParts == 1 ? R.Part : R.Parts)}"; + + lblDnloadList.Text = info; + Log(3, this, () => $"download selected: #books={nBooks}, #parts={nParts}"); + } + else + { + lblDnloadList.Text = null; + Log(3, this, () => "download selected: none"); + } + enableDownloadButtons(); + + if (_ignoreFlag) + return; + + BookDownloadSelectionChanged?.Invoke(this, new BookEventArgs(SelectedBooksForDownload)); + } - private void setStateForDownload (Book book) { - book.Conversion.PersistState = book.Conversion.State; - book.Conversion.State = EConversionState.download; - foreach (var comp in book.Components) { - comp.Conversion.PersistState = comp.Conversion.State; - comp.Conversion.State = EConversionState.download; - } - } + private void setStateForDownload(Book book) + { + book.Conversion.PersistState = book.Conversion.State; + book.Conversion.State = EConversionState.download; + foreach (var comp in book.Components) + { + comp.Conversion.PersistState = comp.Conversion.State; + comp.Conversion.State = EConversionState.download; + } + } - private void resetStateForDownload (Book book) { - book.Conversion.State = book.Conversion.PersistState ?? EConversionState.remote; - foreach (var comp in book.Components) { - comp.Conversion.State = comp.Conversion.PersistState ?? EConversionState.remote; - } + private void resetStateForDownload(Book book) + { + book.Conversion.State = book.Conversion.PersistState ?? EConversionState.remote; + foreach (var comp in book.Components) + { + comp.Conversion.State = comp.Conversion.PersistState ?? EConversionState.remote; + } - } + } - private void btnResync_Click (object sender, EventArgs e) { - Resync?.Invoke (this, EventArgs.Empty); - } + private void btnResync_Click(object sender, EventArgs e) + { + Resync?.Invoke(this, EventArgs.Empty); + } - private void dataGridView1_CellToolTipTextNeeded (object sender, DataGridViewCellToolTipTextNeededEventArgs e) { - if (e.ColumnIndex != 0 || e.RowIndex < 0) - return; + private void dataGridView1_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e) + { + if (e.ColumnIndex != 0 || e.RowIndex < 0) + return; - var row = DataSource[e.RowIndex]; - var state = row.StateBacking; - string ttt = RM.GetStringEx (state.ToString ()); - e.ToolTipText = ttt; + var row = DataSource[e.RowIndex]; + var state = row.StateBacking; + string ttt = RM.GetStringEx(state.ToString()); + e.ToolTipText = ttt; + } } - } } diff --git a/src/Connect.ui.lib.core/BookLibForm.cs b/src/Connect.ui.lib.core/BookLibForm.cs index 50d714d..f42687f 100644 --- a/src/Connect.ui.lib.core/BookLibForm.cs +++ b/src/Connect.ui.lib.core/BookLibForm.cs @@ -12,219 +12,249 @@ using R = core.audiamus.connect.ui.Properties.Resources; using static core.audiamus.aux.Logging; using core.audiamus.aux.win; - -namespace core.audiamus.connect.ui { - public partial class BookLibForm : Form { - const double REL_SPLITTER_DIST_BOTTOM = 0.75; - const double REL_SPLITTER_DIST_INNER = 0.40; - - private static double? __relSplitterDistBottom; - private static double? __relSplitterDistInner; - - private readonly AffineSynchronizationContext _sync; - private readonly InteractionCallbackHandler _interactionHandler; - private IDownloadSettings _downloadSettings; - private bool _shownFlag; - private bool _ignoreFlag; - - private IAudibleApi Api { get; } - - private IDownloadSettings DownloadSettings { - get => _downloadSettings; - set { - _downloadSettings = value; - _downloadSettings.ChangedSettings += settings_ChangedSettings; - } - } - private IExportSettings ExportSettings { get; } - - private BookPGA DataSource { get; set; } - - public event BookSelectionChangedEventHandler BookDownloadSelectionChanged; - public event ConversionUpdatedEventHandler ConversionUpdated; - - public bool DownloadSelectEnabled { - get => bookLibdgvControl1.DownloadSelectEnabled; - set => bookLibdgvControl1.DownloadSelectEnabled = value; - } - - public BookLibForm (IAudibleApi api, IDownloadSettings downloadSettings, IExportSettings exportSettings) { - InitializeComponent (); - _ignoreFlag = true; - - DownloadSelectEnabled = false; - - if (api is null || downloadSettings is null || exportSettings is null) - return; - - Log (3, this, () => $"{api.AccountAlias}, {api.Region}"); - - _sync = new (); - - _interactionHandler = new InteractionCallbackHandler (this, bookLibMessage); - - Api = api; - DownloadSettings = downloadSettings; - ExportSettings = exportSettings; - - bookLibdgvControl1.Settings = downloadSettings; - bookLibdgvControl1.BookSelectionChanged += bookLibdgvControl1_BookSelectionChanged; - bookLibdgvControl1.BookDownloadSelectionChanged += bookLibdgvControl1_BookDownloadSelectionChanged; - bookLibdgvControl1.ConversionUpdated += bookLibdgvControl1_ConversionUpdated; - bookLibdgvControl1.Resync += bookLibdgvControl1_Resync; - - this.Text = $"{R.Library} for \"{Api.AccountAlias}\" and region \"{Api.Region}\""; - } - - private async void bookLibdgvControl1_Resync (object sender, EventArgs e) { - this.Cursor = Cursors.AppStarting; - using var rgc = new ResourceGuard (() => Cursor = Cursors.Default); - using var rge = new ResourceGuard (x => bookLibdgvControl1.DownloadSelectEnabled = !x); - - DialogResult result = DialogResult.None; - bool resync = true; - if (DownloadSettings.AutoUpdateLibrary) { - result = MsgBox.Show (this, R.MsgFullResync, this.Text, - MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); - } else { - result = MsgBox.Show (this, R.MsgFullResyncOrElse, this.Text, - MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); - resync = result == DialogResult.Yes; - } - if (result == DialogResult.Cancel) - return; - - await Api.GetLibraryAsync (resync); - await Api.DownloadCoverImagesAsync (); - - var books = await Task.Run (() => loadBooks ()); - bookLibdgvControl1.Books = books; - } - - private string bookLibMessage (BookLibInteract arg) { - return arg.Kind switch { - EBookLibInteract.checkFile => R.MsgBookLibMissingFiles, - _ => string.Empty - }; - } - - private void settings_ChangedSettings (object sender, EventArgs e) { - DataSource?.OnUpdatedSettings (DownloadSettings.IncludeAdultProducts); - } - - public void UpdateDownloads (IEnumerable books) => - bookLibdgvControl1.UpdateDownloads (books); - - public void UpdateConversion (Conversion conversion) { - bookLibdgvControl1.UpdateConversion (conversion); - propertyGrid1.Refresh (); - } - - protected async override void OnLoad (EventArgs e) { - using var _ = new LogGuard (3, this); - base.OnLoad (e); - - this.Cursor = Cursors.AppStarting; - using (new ResourceGuard (() => Cursor = Cursors.Default)) { - var books = await Task.Run (() => loadBooks ()); - bookLibdgvControl1.Books = books; - } - - Action callback = conv => _sync.Post (bookLibdgvControl1.UpdateConversionStateFromOther, conv); - - if (_interactionHandler is null) - return; - - var interact = - new InteractionCallback, bool?> (_interactionHandler.Interact); - - await Task.Run (() => - Api?.CheckUpdateFilesAndState (DownloadSettings, ExportSettings, callback, interact)); - - DownloadSelectEnabled = true; - } - - protected override void OnShown (EventArgs e) { - using var rg = new ResourceGuard (() => _ignoreFlag = false); - base.OnShown (e); - if (_shownFlag) - return; - _shownFlag = true; - - var scb = splitContainerBottom; - var sci = splitContainerInner; - - double relSplitterDistBottom = __relSplitterDistBottom ?? REL_SPLITTER_DIST_BOTTOM; - double relSplitterDistInner = __relSplitterDistInner ?? REL_SPLITTER_DIST_INNER; - - scb.SplitterDistance = (int)(relSplitterDistBottom * scb.Width); - sci.SplitterDistance = (int)(relSplitterDistInner * scb.Width); - } - - - private IEnumerable loadBooks () { - var books = Api?.GetBooks (); - return books; - } - - private void bookLibdgvControl1_BookSelectionChanged (object sender, BookEventArgs args) { - var books = args.Books; - Log (3, this, () => $"#books={books.Count()}"); - - if (books.Count () != 1) { - propertyGrid1.SelectedObject = null; - - textBox1.Text = null; - - pictureBox1.Image = null; - } else { - var book = books.First (); - DataSource = new BookPGA (book, DownloadSettings); - DataSource.OnUpdatedSettings (DownloadSettings.IncludeAdultProducts); - propertyGrid1.SelectedObject = DataSource; - - - textBox1.Text = book.PublisherSummary.FormatLineBreaks(); - - if (File.Exists (book.CoverImageFile)) - pictureBox1.Image = Image.FromFile (book.CoverImageFile); - else - pictureBox1.Image = null; - } - - } - - private void bookLibdgvControl1_BookDownloadSelectionChanged (object sender, BookEventArgs args) { - Log (3, this, () => $"#books={args.Books.Count ()}"); - BookDownloadSelectionChanged?.Invoke (this, args); - } - - private void propertyGrid1_SelectedObjectsChanged (object sender, System.EventArgs e) { - this.propertyGrid1.MoveSplitterToLongestDisplayName (10); - } - - private void bookLibdgvControl1_ConversionUpdated (object sender, ConversionEventArgs args) { - ConversionUpdated?.Invoke (this, args); - } - - private void bookLibdgvControl1_Close (object sender, EventArgs e) { - Close (); - } - - private void splitContainerInner_SplitterMoved (object sender, SplitterEventArgs e) { - if (_ignoreFlag) - return; - var scb = splitContainerBottom; - var sci = splitContainerInner; - //__relSplitterDistInner = (double)sci.SplitterDistance / scb.Width; - } - - private void splitContainerBottom_SplitterMoved (object sender, SplitterEventArgs e) { - if (_ignoreFlag) - return; - var scb = splitContainerBottom; - //__relSplitterDistInner = (double)scb.SplitterDistance / scb.Width; +using System.ComponentModel; + +namespace core.audiamus.connect.ui +{ + public partial class BookLibForm : Form + { + const double REL_SPLITTER_DIST_BOTTOM = 0.75; + const double REL_SPLITTER_DIST_INNER = 0.40; + + private static double? __relSplitterDistBottom; + private static double? __relSplitterDistInner; + + private readonly AffineSynchronizationContext _sync; + private readonly InteractionCallbackHandler _interactionHandler; + private IDownloadSettings _downloadSettings; + private bool _shownFlag; + private bool _ignoreFlag; + + private IAudibleApi Api { get; } + + private IDownloadSettings DownloadSettings + { + get => _downloadSettings; + set + { + _downloadSettings = value; + _downloadSettings.ChangedSettings += settings_ChangedSettings; + } + } + private IExportSettings ExportSettings { get; } + + private BookPGA DataSource { get; set; } + + public event BookSelectionChangedEventHandler BookDownloadSelectionChanged; + public event ConversionUpdatedEventHandler ConversionUpdated; + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DownloadSelectEnabled + { + get => bookLibdgvControl1.DownloadSelectEnabled; + set => bookLibdgvControl1.DownloadSelectEnabled = value; + } + + public BookLibForm(IAudibleApi api, IDownloadSettings downloadSettings, IExportSettings exportSettings) + { + InitializeComponent(); + _ignoreFlag = true; + + DownloadSelectEnabled = false; + + if (api is null || downloadSettings is null || exportSettings is null) + return; + + Log(3, this, () => $"{api.AccountAlias}, {api.Region}"); + + _sync = new(); + + _interactionHandler = new InteractionCallbackHandler(this, bookLibMessage); + + Api = api; + DownloadSettings = downloadSettings; + ExportSettings = exportSettings; + + bookLibdgvControl1.Settings = downloadSettings; + bookLibdgvControl1.BookSelectionChanged += bookLibdgvControl1_BookSelectionChanged; + bookLibdgvControl1.BookDownloadSelectionChanged += bookLibdgvControl1_BookDownloadSelectionChanged; + bookLibdgvControl1.ConversionUpdated += bookLibdgvControl1_ConversionUpdated; + bookLibdgvControl1.Resync += bookLibdgvControl1_Resync; + + this.Text = $"{R.Library} for \"{Api.AccountAlias}\" and region \"{Api.Region}\""; + } + + private async void bookLibdgvControl1_Resync(object sender, EventArgs e) + { + this.Cursor = Cursors.AppStarting; + using var rgc = new ResourceGuard(() => Cursor = Cursors.Default); + using var rge = new ResourceGuard(x => bookLibdgvControl1.DownloadSelectEnabled = !x); + + DialogResult result = DialogResult.None; + bool resync = true; + if (DownloadSettings.AutoUpdateLibrary) + { + result = MsgBox.Show(this, R.MsgFullResync, this.Text, + MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); + } + else + { + result = MsgBox.Show(this, R.MsgFullResyncOrElse, this.Text, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); + resync = result == DialogResult.Yes; + } + if (result == DialogResult.Cancel) + return; + + await Api.GetLibraryAsync(resync); + await Api.DownloadCoverImagesAsync(); + + var books = await Task.Run(() => loadBooks()); + bookLibdgvControl1.Books = books; + } + + private string bookLibMessage(BookLibInteract arg) + { + return arg.Kind switch + { + EBookLibInteract.checkFile => R.MsgBookLibMissingFiles, + _ => string.Empty + }; + } + + private void settings_ChangedSettings(object sender, EventArgs e) + { + DataSource?.OnUpdatedSettings(DownloadSettings.IncludeAdultProducts); + } + + public void UpdateDownloads(IEnumerable books) => + bookLibdgvControl1.UpdateDownloads(books); + + public void UpdateConversion(Conversion conversion) + { + bookLibdgvControl1.UpdateConversion(conversion); + propertyGrid1.Refresh(); + } + + protected async override void OnLoad(EventArgs e) + { + using var _ = new LogGuard(3, this); + base.OnLoad(e); + + this.Cursor = Cursors.AppStarting; + using (new ResourceGuard(() => Cursor = Cursors.Default)) + { + var books = await Task.Run(() => loadBooks()); + bookLibdgvControl1.Books = books; + } + + Action callback = conv => _sync.Post(bookLibdgvControl1.UpdateConversionStateFromOther, conv); + + if (_interactionHandler is null) + return; + + var interact = + new InteractionCallback, bool?>(_interactionHandler.Interact); + + await Task.Run(() => + Api?.CheckUpdateFilesAndState(DownloadSettings, ExportSettings, callback, interact)); + + DownloadSelectEnabled = true; + } + + protected override void OnShown(EventArgs e) + { + using var rg = new ResourceGuard(() => _ignoreFlag = false); + base.OnShown(e); + if (_shownFlag) + return; + _shownFlag = true; + + var scb = splitContainerBottom; + var sci = splitContainerInner; + + double relSplitterDistBottom = __relSplitterDistBottom ?? REL_SPLITTER_DIST_BOTTOM; + double relSplitterDistInner = __relSplitterDistInner ?? REL_SPLITTER_DIST_INNER; + + scb.SplitterDistance = (int)(relSplitterDistBottom * scb.Width); + sci.SplitterDistance = (int)(relSplitterDistInner * scb.Width); + } + + + private IEnumerable loadBooks() + { + var books = Api?.GetBooks(); + return books; + } + + private void bookLibdgvControl1_BookSelectionChanged(object sender, BookEventArgs args) + { + var books = args.Books; + Log(3, this, () => $"#books={books.Count()}"); + + if (books.Count() != 1) + { + propertyGrid1.SelectedObject = null; + + textBox1.Text = null; + + pictureBox1.Image = null; + } + else + { + var book = books.First(); + DataSource = new BookPGA(book, DownloadSettings); + DataSource.OnUpdatedSettings(DownloadSettings.IncludeAdultProducts); + propertyGrid1.SelectedObject = DataSource; + + + textBox1.Text = book.PublisherSummary.FormatLineBreaks(); + + if (File.Exists(book.CoverImageFile)) + pictureBox1.Image = Image.FromFile(book.CoverImageFile); + else + pictureBox1.Image = null; + } + + } + + private void bookLibdgvControl1_BookDownloadSelectionChanged(object sender, BookEventArgs args) + { + Log(3, this, () => $"#books={args.Books.Count()}"); + BookDownloadSelectionChanged?.Invoke(this, args); + } + + private void propertyGrid1_SelectedObjectsChanged(object sender, System.EventArgs e) + { + this.propertyGrid1.MoveSplitterToLongestDisplayName(10); + } + + private void bookLibdgvControl1_ConversionUpdated(object sender, ConversionEventArgs args) + { + ConversionUpdated?.Invoke(this, args); + } + + private void bookLibdgvControl1_Close(object sender, EventArgs e) + { + Close(); + } + + private void splitContainerInner_SplitterMoved(object sender, SplitterEventArgs e) + { + if (_ignoreFlag) + return; + var scb = splitContainerBottom; + var sci = splitContainerInner; + //__relSplitterDistInner = (double)sci.SplitterDistance / scb.Width; + } + + private void splitContainerBottom_SplitterMoved(object sender, SplitterEventArgs e) + { + if (_ignoreFlag) + return; + var scb = splitContainerBottom; + //__relSplitterDistInner = (double)scb.SplitterDistance / scb.Width; + } } - } } diff --git a/src/Connect.ui.lib.core/Connect.ui.lib.core.csproj b/src/Connect.ui.lib.core/Connect.ui.lib.core.csproj index 5a8b0ab..2157c9d 100644 --- a/src/Connect.ui.lib.core/Connect.ui.lib.core.csproj +++ b/src/Connect.ui.lib.core/Connect.ui.lib.core.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net10.0-windows true core.audiamus.connect.ui audiamus.connect.ui.core diff --git a/src/Connect.ui.lib.core/ConvertDGVControl.cs b/src/Connect.ui.lib.core/ConvertDGVControl.cs index 2e28995..21d7d85 100644 --- a/src/Connect.ui.lib.core/ConvertDGVControl.cs +++ b/src/Connect.ui.lib.core/ConvertDGVControl.cs @@ -18,463 +18,542 @@ using abl = core.audiamus.booksdb; -namespace core.audiamus.connect.ui { - public partial class ConvertDGVControl : UserControl { - private ResourceManager RM { get; } - - private bool _ignoreFlag; - private bool _snapshotFlag; - private bool _wasIdle; - private bool _initConnectionDone; - private IAudibleApi _audibleApi; - private IDownloadSettings _downloadSettings; - private readonly AffineSynchronizationContext _sync; - private readonly HashSet _componentsForUpdate = new(); - private readonly List _selectedConversions = new(); - - private SortableBindingListSuspensible DataSourceDownload { get; set; } - private SortableBindingListSuspensible DataSourceLocal { get; set; } - - private BookLibForm BookLibForm { get; set; } - - public event EventHandler SelectionChanged; - public event BoolEventHandler IdleChanged; - - public bool PartiallyDisabled { - get => !panel1.Enabled; - set { - panel1.Enabled = !value; - dataGridView1.ClientAreaEnabled = !value; - if (BookLibForm is not null) - BookLibForm.DownloadSelectEnabled = !value; - if (value) - snapshotSelection (true); - } - } - - public IAudibleApi AudibleApi { - private get => _audibleApi; - set { - _audibleApi = value; - startWithApi (); - } - } - - public IDownloadSettings DownloadSettings { - private get => _downloadSettings; - set { - _downloadSettings = value; - _downloadSettings.ChangedSettings += settings_ChangedSettings; - } - } - - public IExportSettings ExportSettings { private get; set; } - - public bool IsIdle => BookLibForm is null && !(DataSourceDownload?.Any () ?? false); - - public IEnumerable SelectedConversions => _selectedConversions; - - //public new bool Enabled { - // get => base.Enabled; - // set { - // if (BookLibForm is not null) - // BookLibForm.DownloadSelectEnabled = value; - // base.Enabled = value; - // if (!value) - // snapshotSelection (true); - // } - //} - - public bool DownloadOnlyMode { - get => !btnAdd.Visible; - set { - btnAdd.Visible = !value; - if (value) { - btnDnload.Left = btnAdd.Left; - btnDnload.Anchor = AnchorStyles.Left | AnchorStyles.Top; - } else { - btnDnload.Left = this.Width - btnDnload.Width - 3; - btnDnload.Anchor = AnchorStyles.Right | AnchorStyles.Top; - } - } - } - - public ConvertDGVControl () { - InitializeComponent (); - RM = this.GetDefaultResourceManager (); - - _sync = new (); - - enable (); - } - - public void ResetDataSourceItem (Conversion conversion) { - _sync.Send (resetDataSourceItem, conversion); - } - - - private void resetDataSourceItem (Conversion conversion) { - int? i = DataSourceDownload.Select ((s, i) => new { s, i }).FirstOrDefault (k => k.s.DataSource == conversion)?.i; - if (i.HasValue) - DataSourceDownload.ResetItem (i.Value); - BookLibForm?.UpdateConversion (conversion); - } - - private void startWithApi () { - bool ena = enableDnload (); - if (ena && DownloadSettings.AutoOpenDownloadDialog) - btnDnload_Click (this, EventArgs.Empty); - } - - private void settings_ChangedSettings (object sender, EventArgs e) { - IEnumerable previousBooks = getCurrentDownloadBooks (); - if (previousBooks is null) - return; - - if (!DownloadSettings.IncludeAdultProducts) - previousBooks = previousBooks.Where (b => !(b.AdultProduct ?? false)); - - resetDataSource (previousBooks); - timer1.Enabled = true; - } - - private void updateDownloadDataSource (IEnumerable books) { - if (_ignoreFlag) - return; - - using var rg = new ResourceGuard (x => _ignoreFlag = x); - - if (books is null) - return; - - if (DataSourceDownload is null) { - resetDataSource (books); - } else { - IEnumerable previousBooks = getCurrentDownloadBooks (); - addDownloadBooks (books, previousBooks); - removeDownloadBooks (books, previousBooks); - } - - _snapshotFlag = true; - timer1.Enabled = true; - } - - private void resetDataSource (IEnumerable books) { - var convDS = getDownloadConversions (books); - fillMetaInfoGaps (convDS); - - DataSourceDownload = new SortableBindingListSuspensible (convDS) { - UseBackingProperties = true, - UseResorting = true - }; - DataSourceDownload.ListChanged += dataSourceDownload_ListChanged; - DataSourceDownload.EndSorting += dataSourceDownload_EndSorting; - this.dataGridView1.DataSource = DataSourceDownload; - } - - private void dataSourceDownload_ListChanged (object sender, ListChangedEventArgs e) { - timer1.Enabled = true; - } - - private void dataSourceDownload_EndSorting (object sender, EventArgs e) { - timer1.Enabled = true; - } - - private IEnumerable getCurrentDownloadBooks () => - DataSourceDownload?.Select (c => c.Conversion.ParentBook).Distinct (); - - private void addDownloadBooks (IEnumerable books, IEnumerable previousBooks) { - IEnumerable booksAdding = books.Except (previousBooks); - var convDSAdd = getDownloadConversions (booksAdding); - if (convDSAdd.Any ()) { - fillMetaInfoGaps (convDSAdd); - if (convDSAdd.Count () > 1) { - DataSourceDownload.AddRange (convDSAdd); - } else { - DataSourceDownload.Add (convDSAdd.First ()); +namespace core.audiamus.connect.ui +{ + public partial class ConvertDGVControl : UserControl + { + private ResourceManager RM { get; } + + private bool _ignoreFlag; + private bool _snapshotFlag; + private bool _wasIdle; + private bool _initConnectionDone; + private IAudibleApi _audibleApi; + private IDownloadSettings _downloadSettings; + private readonly AffineSynchronizationContext _sync; + private readonly HashSet _componentsForUpdate = new(); + private readonly List _selectedConversions = new(); + + private SortableBindingListSuspensible DataSourceDownload { get; set; } + private SortableBindingListSuspensible DataSourceLocal { get; set; } + + private BookLibForm BookLibForm { get; set; } + + public event EventHandler SelectionChanged; + public event BoolEventHandler IdleChanged; + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool PartiallyDisabled + { + get => !panel1.Enabled; + set + { + panel1.Enabled = !value; + dataGridView1.ClientAreaEnabled = !value; + if (BookLibForm is not null) + BookLibForm.DownloadSelectEnabled = !value; + if (value) + snapshotSelection(true); + } } - } - } - - private void fillMetaInfoGaps (IEnumerable conversionsToAdd) { - using var _ = new LogGuard (3, this); - var conversions = conversionsToAdd - .Where (c => c.Conversion.Component is not null && - c.Conversion.Component.RunTimeLengthSeconds is null && - !_componentsForUpdate.Contains (c.Conversion.Component)) - .ToList (); - if (!conversions.Any ()) - return; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IAudibleApi AudibleApi + { + private get => _audibleApi; + set + { + _audibleApi = value; + startWithApi(); + } + } - var components = conversions.Select (c => c.Conversion.Component).ToList (); - components.ForEach (c => _componentsForUpdate.Add (c)); + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IDownloadSettings DownloadSettings + { + private get => _downloadSettings; + set + { + _downloadSettings = value; + _downloadSettings.ChangedSettings += settings_ChangedSettings; + } + } - Task.Run (async () => await AudibleApi.UpdateMetaInfo (components, onDone)); + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IExportSettings ExportSettings { private get; set; } + public bool IsIdle => BookLibForm is null && !(DataSourceDownload?.Any() ?? false); + public IEnumerable SelectedConversions => _selectedConversions; - void onDone (IEnumerable comps) => _sync.Post (onDoneSync, comps); + //public new bool Enabled { + // get => base.Enabled; + // set { + // if (BookLibForm is not null) + // BookLibForm.DownloadSelectEnabled = value; + // base.Enabled = value; + // if (!value) + // snapshotSelection (true); + // } + //} - void onDoneSync (IEnumerable comps) { - Log (3, this, () => $"#comps={comps.Count ()}"); - foreach (var comp in comps) - _componentsForUpdate.Remove (comp); + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DownloadOnlyMode + { + get => !btnAdd.Visible; + set + { + btnAdd.Visible = !value; + if (value) + { + btnDnload.Left = btnAdd.Left; + btnDnload.Anchor = AnchorStyles.Left | AnchorStyles.Top; + } + else + { + btnDnload.Left = this.Width - btnDnload.Width - 3; + btnDnload.Anchor = AnchorStyles.Right | AnchorStyles.Top; + } + } + } - if (DataSourceDownload.IsNullOrEmpty ()) - return; + public ConvertDGVControl() + { + InitializeComponent(); + RM = this.GetDefaultResourceManager(); - if (comps.Count () > 1) { - using var rg = new ResourceGuard (x => DataSourceDownload.Suspended = x); - update (comps, conversions); - } else - update (comps, conversions); + _sync = new(); - void update (IEnumerable comps, List conversions) { - foreach (var comp in comps) { - var convDS = conversions.FirstOrDefault (c => comp.Equals (c.Conversion.Component)); - if (convDS is null) - continue; - int idx = DataSourceDownload.IndexOf (convDS); - if (idx >= 0) - DataSourceDownload.ResetItem (idx); - } + enable(); } - } - } - private void removeDownloadBooks (IEnumerable books, IEnumerable previousBooks) { - IEnumerable booksRemoving = previousBooks.Except (books); - var convDSRem = getDownloadConversions (booksRemoving); - removeConversions (convDSRem); - } - - private void removeConversions (IEnumerable convDSRem) { - if (convDSRem.Any ()) { - if (convDSRem.Count () > 1) { - DataSourceDownload.RemoveRange (convDSRem); - } else { - DataSourceDownload.Remove (convDSRem.First ()); + public void ResetDataSourceItem(Conversion conversion) + { + _sync.Send(resetDataSourceItem, conversion); } - } - } - private IEnumerable getDownloadConversions (IEnumerable books) { - var convDS = new List (); - foreach (var book in books) { - if (DownloadSettings.MultiPartDownload && book.DeliveryType == EDeliveryType.MultiPartBook && book.Components.Any ()) { - var convDSMultiPart = new List (); - foreach (var comp in book.Components) - convDSMultiPart.Add (new ConversionDataSource (comp.Conversion)); - convDSMultiPart.Sort ((x, y) => - Comparer.Default.Compare (x.Conversion.Component.PartNumber, y.Conversion.Component.PartNumber)); - convDS.AddRange (convDSMultiPart); - } else - convDS.Add (new ConversionDataSource (book.Conversion)); - } - return convDS; - } - - private void dataGridView1_DataBindingComplete (object sender, DataGridViewBindingCompleteEventArgs e) { - foreach (DataGridViewColumn clm in dataGridView1.Columns) { - if (clm.ValueType == typeof (Image)) - clm.SortMode = DataGridViewColumnSortMode.Automatic; - } - enable (); - } - private void enable () { - enableAdd (); - enableRem (); - enableDnload (); - checkIdle (); - } + private void resetDataSourceItem(Conversion conversion) + { + int? i = DataSourceDownload.Select((s, i) => new { s, i }).FirstOrDefault(k => k.s.DataSource == conversion)?.i; + if (i.HasValue) + DataSourceDownload.ResetItem(i.Value); + BookLibForm?.UpdateConversion(conversion); + } - private void checkIdle () { - bool isIdle = IsIdle; - if (isIdle != _wasIdle) { - _wasIdle = isIdle; - IdleChanged?.Invoke (this, new BoolEventArgs (isIdle)); - } - } + private void startWithApi() + { + bool ena = enableDnload(); + if (ena && DownloadSettings.AutoOpenDownloadDialog) + btnDnload_Click(this, EventArgs.Empty); + } - private void enableAdd () { - btnAdd.Enabled = BookLibForm is null && !(DataSourceDownload?.Any () ?? false); - } + private void settings_ChangedSettings(object sender, EventArgs e) + { + IEnumerable previousBooks = getCurrentDownloadBooks(); + if (previousBooks is null) + return; - private void enableRem () { - btnRem.Enabled = dataGridView1.SelectedRows.Count > 0; - } + if (!DownloadSettings.IncludeAdultProducts) + previousBooks = previousBooks.Where(b => !(b.AdultProduct ?? false)); - private bool enableDnload () { - bool ena = AudibleApi is not null; - ena &= BookLibForm is null; - ena &= !(DataSourceLocal?.Any () ?? false); - btnDnload.Enabled = ena; //AudibleApi is not null && BookLibForm is null && !(DataSourceLocal?.Any () ?? false); - return ena; - } + resetDataSource(previousBooks); + timer1.Enabled = true; + } - private void btnAdd_Click (object sender, EventArgs e) { - Log (3, this); - // TODO implement for local - MsgBox.Show (this, "Adding local files.\r\nNot yet implemented."); - enable (); - } + private void updateDownloadDataSource(IEnumerable books) + { + if (_ignoreFlag) + return; + + using var rg = new ResourceGuard(x => _ignoreFlag = x); + + if (books is null) + return; + + if (DataSourceDownload is null) + { + resetDataSource(books); + } + else + { + IEnumerable previousBooks = getCurrentDownloadBooks(); + addDownloadBooks(books, previousBooks); + removeDownloadBooks(books, previousBooks); + } + + _snapshotFlag = true; + timer1.Enabled = true; + } - private void btnRem_Click (object sender, EventArgs e) { - Log (3, this); - using (new ResourceGuard (x => _ignoreFlag = x)) { - if (DataSourceDownload?.Any () ?? false) { - var selectedConversions = new List (); - addSortedByIndex (selectedConversions); - foreach (DataGridViewRow row in dataGridView1.SelectedRows) { - int idx = row.Index; - ConversionDataSource convDS = DataSourceDownload[idx]; - selectedConversions.Add (convDS); - } + private void resetDataSource(IEnumerable books) + { + var convDS = getDownloadConversions(books); + fillMetaInfoGaps(convDS); + + DataSourceDownload = new SortableBindingListSuspensible(convDS) + { + UseBackingProperties = true, + UseResorting = true + }; + DataSourceDownload.ListChanged += dataSourceDownload_ListChanged; + DataSourceDownload.EndSorting += dataSourceDownload_EndSorting; + this.dataGridView1.DataSource = DataSourceDownload; + } - var booksToBeRemoved = selectedConversions.Select (c => c.Conversion.ParentBook).Distinct (); + private void dataSourceDownload_ListChanged(object sender, ListChangedEventArgs e) + { + timer1.Enabled = true; + } - var conversionsToBeRemoved = getDownloadConversions (booksToBeRemoved); + private void dataSourceDownload_EndSorting(object sender, EventArgs e) + { + timer1.Enabled = true; + } - removeConversions (conversionsToBeRemoved); + private IEnumerable getCurrentDownloadBooks() => + DataSourceDownload?.Select(c => c.Conversion.ParentBook).Distinct(); + + private void addDownloadBooks(IEnumerable books, IEnumerable previousBooks) + { + IEnumerable booksAdding = books.Except(previousBooks); + var convDSAdd = getDownloadConversions(booksAdding); + if (convDSAdd.Any()) + { + fillMetaInfoGaps(convDSAdd); + if (convDSAdd.Count() > 1) + { + DataSourceDownload.AddRange(convDSAdd); + } + else + { + DataSourceDownload.Add(convDSAdd.First()); + } + } + } - var remainingBooks = getCurrentDownloadBooks (); + private void fillMetaInfoGaps(IEnumerable conversionsToAdd) + { + using var _ = new LogGuard(3, this); + var conversions = conversionsToAdd + .Where(c => c.Conversion.Component is not null && + c.Conversion.Component.RunTimeLengthSeconds is null && + !_componentsForUpdate.Contains(c.Conversion.Component)) + .ToList(); + + if (!conversions.Any()) + return; + + var components = conversions.Select(c => c.Conversion.Component).ToList(); + components.ForEach(c => _componentsForUpdate.Add(c)); + + Task.Run(async () => await AudibleApi.UpdateMetaInfo(components, onDone)); + + + + void onDone(IEnumerable comps) => _sync.Post(onDoneSync, comps); + + void onDoneSync(IEnumerable comps) + { + Log(3, this, () => $"#comps={comps.Count()}"); + foreach (var comp in comps) + _componentsForUpdate.Remove(comp); + + if (DataSourceDownload.IsNullOrEmpty()) + return; + + if (comps.Count() > 1) + { + using var rg = new ResourceGuard(x => DataSourceDownload.Suspended = x); + update(comps, conversions); + } + else + update(comps, conversions); + + void update(IEnumerable comps, List conversions) + { + foreach (var comp in comps) + { + var convDS = conversions.FirstOrDefault(c => comp.Equals(c.Conversion.Component)); + if (convDS is null) + continue; + int idx = DataSourceDownload.IndexOf(convDS); + if (idx >= 0) + DataSourceDownload.ResetItem(idx); + } + } + } + } - using var rg = new ResourceGuard (x => _ignoreFlag = x); - BookLibForm?.UpdateDownloads (remainingBooks); + private void removeDownloadBooks(IEnumerable books, IEnumerable previousBooks) + { + IEnumerable booksRemoving = previousBooks.Except(books); + var convDSRem = getDownloadConversions(booksRemoving); + removeConversions(convDSRem); } - dataGridView1.ClearSelection (); - enable (); - } - snapshotSelection (false); - } + private void removeConversions(IEnumerable convDSRem) + { + if (convDSRem.Any()) + { + if (convDSRem.Count() > 1) + { + DataSourceDownload.RemoveRange(convDSRem); + } + else + { + DataSourceDownload.Remove(convDSRem.First()); + } + } + } - private void btnDnload_Click (object sender, EventArgs e) { - Log (3, this); - if (BookLibForm is not null) - return; + private IEnumerable getDownloadConversions(IEnumerable books) + { + var convDS = new List(); + foreach (var book in books) + { + if (DownloadSettings.MultiPartDownload && book.DeliveryType == EDeliveryType.MultiPartBook && book.Components.Any()) + { + var convDSMultiPart = new List(); + foreach (var comp in book.Components) + convDSMultiPart.Add(new ConversionDataSource(comp.Conversion)); + convDSMultiPart.Sort((x, y) => + Comparer.Default.Compare(x.Conversion.Component.PartNumber, y.Conversion.Component.PartNumber)); + convDS.AddRange(convDSMultiPart); + } + else + convDS.Add(new ConversionDataSource(book.Conversion)); + } + return convDS; + } - btnDnload.Enabled = false; + private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) + { + foreach (DataGridViewColumn clm in dataGridView1.Columns) + { + if (clm.ValueType == typeof(Image)) + clm.SortMode = DataGridViewColumnSortMode.Automatic; + } + enable(); + } - Cursor cursor = Cursor.Current; - Cursor.Current = Cursors.AppStarting; - var rg = new ResourceGuard (() => Cursor.Current = cursor); + private void enable() + { + enableAdd(); + enableRem(); + enableDnload(); + checkIdle(); + } - if (!_initConnectionDone) { - //var s = _downloadSettings; - //Log (3, this, () => $"settings: auto refresh={s.AutoRefresh}, auto update={s.AutoUpdateLibrary}"); - //if (!s.AutoRefresh) { - // await AudibleApi.RefreshTokenAsyncFunc (); - //} + private void checkIdle() + { + bool isIdle = IsIdle; + if (isIdle != _wasIdle) + { + _wasIdle = isIdle; + IdleChanged?.Invoke(this, new BoolEventArgs(isIdle)); + } + } - _initConnectionDone = true; - } + private void enableAdd() + { + btnAdd.Enabled = BookLibForm is null && !(DataSourceDownload?.Any() ?? false); + } - BookLibForm = new BookLibForm (AudibleApi, DownloadSettings, ExportSettings) { Owner = this.ParentForm }; - BookLibForm.FormClosed += bookLibForm_FormClosed; - BookLibForm.BookDownloadSelectionChanged += bookLibForm_BookDownloadSelectionChanged; - BookLibForm.ConversionUpdated += bookLibForm_ConversionUpdated; - //BookLibForm.DownloadSelectEnabled = dataGridView1.Enabled; - BookLibForm.SetStartPosition (EFormStartPosition.AtParentTopLeft, this); - BookLibForm.Show (); + private void enableRem() + { + btnRem.Enabled = dataGridView1.SelectedRows.Count > 0; + } - enable (); - } + private bool enableDnload() + { + bool ena = AudibleApi is not null; + ena &= BookLibForm is null; + ena &= !(DataSourceLocal?.Any() ?? false); + btnDnload.Enabled = ena; //AudibleApi is not null && BookLibForm is null && !(DataSourceLocal?.Any () ?? false); + return ena; + } - private void bookLibForm_ConversionUpdated (object sender, ConversionEventArgs args) { - Log (3, this, () => $"{args.Conversion}"); - if (DataSourceDownload is null) - return; - var conv = args.Conversion; - int idx = DataSourceDownload.IndexOf (conv); - if (idx >= 0) - DataSourceDownload.ResetItem (idx); - } + private void btnAdd_Click(object sender, EventArgs e) + { + Log(3, this); + // TODO implement for local + MsgBox.Show(this, "Adding local files.\r\nNot yet implemented."); + enable(); + } - private void bookLibForm_BookDownloadSelectionChanged (object sender, BookEventArgs args) { - Log (3, this, () => $"#books={args.Books.Count ()}"); + private void btnRem_Click(object sender, EventArgs e) + { + Log(3, this); + using (new ResourceGuard(x => _ignoreFlag = x)) + { + if (DataSourceDownload?.Any() ?? false) + { + var selectedConversions = new List(); + addSortedByIndex(selectedConversions); + foreach (DataGridViewRow row in dataGridView1.SelectedRows) + { + int idx = row.Index; + ConversionDataSource convDS = DataSourceDownload[idx]; + selectedConversions.Add(convDS); + } + + var booksToBeRemoved = selectedConversions.Select(c => c.Conversion.ParentBook).Distinct(); + + var conversionsToBeRemoved = getDownloadConversions(booksToBeRemoved); + + removeConversions(conversionsToBeRemoved); + + var remainingBooks = getCurrentDownloadBooks(); + + using var rg = new ResourceGuard(x => _ignoreFlag = x); + BookLibForm?.UpdateDownloads(remainingBooks); + } + + dataGridView1.ClearSelection(); + enable(); + } + snapshotSelection(false); + } - updateDownloadDataSource (args.Books); - dataGridView1.AutoResizeColumns (DataGridViewAutoSizeColumnsMode.DisplayedCells); - enable (); + private void btnDnload_Click(object sender, EventArgs e) + { + Log(3, this); + if (BookLibForm is not null) + return; + + btnDnload.Enabled = false; + + Cursor cursor = Cursor.Current; + Cursor.Current = Cursors.AppStarting; + var rg = new ResourceGuard(() => Cursor.Current = cursor); + + if (!_initConnectionDone) + { + //var s = _downloadSettings; + //Log (3, this, () => $"settings: auto refresh={s.AutoRefresh}, auto update={s.AutoUpdateLibrary}"); + //if (!s.AutoRefresh) { + // await AudibleApi.RefreshTokenAsyncFunc (); + //} + + _initConnectionDone = true; + } + + BookLibForm = new BookLibForm(AudibleApi, DownloadSettings, ExportSettings) { Owner = this.ParentForm }; + BookLibForm.FormClosed += bookLibForm_FormClosed; + BookLibForm.BookDownloadSelectionChanged += bookLibForm_BookDownloadSelectionChanged; + BookLibForm.ConversionUpdated += bookLibForm_ConversionUpdated; + //BookLibForm.DownloadSelectEnabled = dataGridView1.Enabled; + BookLibForm.SetStartPosition(EFormStartPosition.AtParentTopLeft, this); + BookLibForm.Show(); + + enable(); + } - Log (3, this, () => $"#conv={DataSourceDownload.Count}"); - } + private void bookLibForm_ConversionUpdated(object sender, ConversionEventArgs args) + { + Log(3, this, () => $"{args.Conversion}"); + if (DataSourceDownload is null) + return; + var conv = args.Conversion; + int idx = DataSourceDownload.IndexOf(conv); + if (idx >= 0) + DataSourceDownload.ResetItem(idx); + } - private void bookLibForm_FormClosed (object sender, FormClosedEventArgs e) { - BookLibForm = null; - enable (); - } + private void bookLibForm_BookDownloadSelectionChanged(object sender, BookEventArgs args) + { + Log(3, this, () => $"#books={args.Books.Count()}"); - private void dataGridView1_SelectionChanged (object sender, EventArgs e) { - if (_ignoreFlag) - return; - enable (); + updateDownloadDataSource(args.Books); + dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); + enable(); - snapshotSelection (false); - } + Log(3, this, () => $"#conv={DataSourceDownload.Count}"); + } - private void snapshotSelection (bool updateSelectedRows) { - Log (3, this, () => $"upd sel rows={updateSelectedRows}"); - var selectedConversions = new List (); - addSortedByIndex (selectedConversions); + private void bookLibForm_FormClosed(object sender, FormClosedEventArgs e) + { + BookLibForm = null; + enable(); + } - var books = selectedConversions.Select (c => c.ParentBook).Distinct (); - var conversionsDS = getDownloadConversions (books); - var conversions = conversionsDS.Select (c => c.Conversion); + private void dataGridView1_SelectionChanged(object sender, EventArgs e) + { + if (_ignoreFlag) + return; + enable(); - if (updateSelectedRows) { - using (new ResourceGuard (x => _ignoreFlag = x)) { - dataGridView1.ClearSelection (); - foreach (var convDS in conversionsDS) { - int idx = DataSourceDownload.IndexOf (convDS); - if (idx >= 0) - dataGridView1.Rows[idx].Selected = true; - } + snapshotSelection(false); } - } else { - _selectedConversions.Clear (); - _selectedConversions.AddRange (conversions); - SelectionChanged?.Invoke (this, EventArgs.Empty); - } - Log (3, this, () => $"#conv sel={_selectedConversions.Count ()}"); - } + private void snapshotSelection(bool updateSelectedRows) + { + Log(3, this, () => $"upd sel rows={updateSelectedRows}"); + var selectedConversions = new List(); + addSortedByIndex(selectedConversions); + + var books = selectedConversions.Select(c => c.ParentBook).Distinct(); + var conversionsDS = getDownloadConversions(books); + var conversions = conversionsDS.Select(c => c.Conversion); + + if (updateSelectedRows) + { + using (new ResourceGuard(x => _ignoreFlag = x)) + { + dataGridView1.ClearSelection(); + foreach (var convDS in conversionsDS) + { + int idx = DataSourceDownload.IndexOf(convDS); + if (idx >= 0) + dataGridView1.Rows[idx].Selected = true; + } + } + } + else + { + _selectedConversions.Clear(); + _selectedConversions.AddRange(conversions); + SelectionChanged?.Invoke(this, EventArgs.Empty); + } + + Log(3, this, () => $"#conv sel={_selectedConversions.Count()}"); + } - private void addSortedByIndex (List selectedConversions) => - addSortedByIndex (selectedConversions, c => c.Conversion); + private void addSortedByIndex(List selectedConversions) => + addSortedByIndex(selectedConversions, c => c.Conversion); - private void addSortedByIndex (List selectedConversions) => - addSortedByIndex (selectedConversions, c => c); + private void addSortedByIndex(List selectedConversions) => + addSortedByIndex(selectedConversions, c => c); - private void addSortedByIndex (List selected, Func getProp) => - dataGridView1.AddSelectedRowsSortedByIndex (selected, getProp, DataSourceDownload); + private void addSortedByIndex(List selected, Func getProp) => + dataGridView1.AddSelectedRowsSortedByIndex(selected, getProp, DataSourceDownload); - private void timer1_Tick (object sender, EventArgs e) { - timer1.Enabled = false; - dataGridView1.SelectAll (); - enable (); + private void timer1_Tick(object sender, EventArgs e) + { + timer1.Enabled = false; + dataGridView1.SelectAll(); + enable(); - if (!_snapshotFlag) - return; + if (!_snapshotFlag) + return; - _snapshotFlag = false; - snapshotSelection (false); - } + _snapshotFlag = false; + snapshotSelection(false); + } - private void dataGridView1_CellToolTipTextNeeded (object sender, DataGridViewCellToolTipTextNeededEventArgs e) { - if (e.ColumnIndex != 0 || e.RowIndex < 0) - return; + private void dataGridView1_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e) + { + if (e.ColumnIndex != 0 || e.RowIndex < 0) + return; - if (DataSourceDownload is null) - return; + if (DataSourceDownload is null) + return; - var row = DataSourceDownload[e.RowIndex]; - var state = row.StateBacking; - string ttt = RM.GetStringEx (state.ToString ()); - e.ToolTipText = ttt; + var row = DataSourceDownload[e.RowIndex]; + var state = row.StateBacking; + string ttt = RM.GetStringEx(state.ToString()); + e.ToolTipText = ttt; + } } - } } diff --git a/src/Connect.ui.lib.core/DataGridViewEx.cs b/src/Connect.ui.lib.core/DataGridViewEx.cs index d611cf0..313eae0 100644 --- a/src/Connect.ui.lib.core/DataGridViewEx.cs +++ b/src/Connect.ui.lib.core/DataGridViewEx.cs @@ -4,165 +4,192 @@ using System.Windows.Forms; using core.audiamus.aux; using core.audiamus.aux.win; +using System.ComponentModel; + +namespace core.audiamus.connect.ui +{ + class DataGridViewEx : DataGridView, ISortingEvents + { + + private readonly Timer _timer1 = new Timer(); + private readonly Timer _timer2 = new Timer(); + private bool _ignoreFlag; + private bool _isSorting; + private bool _sortEndedVertPosSet; + private int? _sortColumnRelX; + private bool _clientAreaEnabled = true; + + public event EventHandler BeginSorting; + public event EventHandler EndSorting; + public event EventHandler SortingCompleteToSetVerticalPosition; + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new ISortableBindingList DataSource + { + get => base.DataSource as ISortableBindingList; + set + { + base.DataSource = value; + value.BeginSorting += dataSource_BeginSorting; + value.EndSorting += dataSource_EndSorting; + } + } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool ClientAreaEnabled + { + get => _clientAreaEnabled; + set + { + _clientAreaEnabled = value; + var color = value ? SystemColors.ControlText : SystemColors.GrayText; + DefaultCellStyle.ForeColor = color; + DefaultCellStyle.SelectionForeColor = color; + ColumnHeadersDefaultCellStyle.ForeColor = color; + } + } + + public DataGridViewEx() + { + _timer1.Interval = 100; + _timer1.Tick += timer1_Tick; + _timer2.Interval = 10; + _timer2.Tick += timer2_Tick; + } + + public void AddSelectedRowsSortedByIndex( + List selected, + Func getProp, + IReadOnlyList dataSource, + Func approveCallback = null + ) + { + var selectedRows = new DataGridViewRow[this.SelectedRows.Count]; + this.SelectedRows.CopyTo(selectedRows, 0); + Array.Sort(selectedRows, (x, y) => x.Index.CompareTo(y.Index)); + foreach (DataGridViewRow row in selectedRows) + { + int idx = row.Index; + bool approved = approveCallback?.Invoke(idx) ?? true; + if (!approved) + continue; + S item = dataSource[idx]; + selected.Add(getProp(item)); + } + } + + protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e) + { + foreach (DataGridViewColumn clm in base.Columns) + { + if (clm.ValueType == typeof(Image)) + clm.SortMode = DataGridViewColumnSortMode.Automatic; + } + base.OnDataBindingComplete(e); + } + + protected override void OnScroll(ScrollEventArgs e) + { + if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + if (_ignoreFlag) + return; + _sortColumnRelX = null; + return; + } + _timer1.Enabled = false; + _timer1.Enabled = true; + + base.OnScroll(e); + } + + protected override void OnSelectionChanged(EventArgs e) + { + if (_isSorting) + return; + + + base.OnSelectionChanged(e); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (ClientAreaEnabled) + base.OnMouseDown(e); + } + + private void timer1_Tick(object sender, EventArgs e) + { + _timer1.Enabled = false; + base.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); + setHorizontalPos(); + } + + private void timer2_Tick(object sender, EventArgs e) + { + if (_sortEndedVertPosSet) + { + _timer2.Enabled = false; + _timer2.Interval = 10; + + setHorizontalPos(); + } + else + { + _timer2.Interval = 50; + + SortingCompleteToSetVerticalPosition?.Invoke(sender, e); + + _sortEndedVertPosSet = true; + } + + } + + private void dataSource_BeginSorting(object sender, EventArgs e) + { + _isSorting = true; + _sortEndedVertPosSet = false; + + var column = base.SortedColumn; + var clmRect = base.GetColumnDisplayRectangle(column.Index, true); + _sortColumnRelX = clmRect.X; + + BeginSorting?.Invoke(sender, e); + } + + private void dataSource_EndSorting(object sender, EventArgs e) + { + EndSorting?.Invoke(sender, e); + + _timer2.Enabled = true; + _isSorting = false; + + } + + private void setHorizontalPos() + { + if (!_sortColumnRelX.HasValue) + return; + using var rg = new ResourceGuard(x => _ignoreFlag = x); + // abs position of sort column + int aggrclmwid = absSortColumnX(); + + // offset of hor scrollbar + int offs = aggrclmwid - _sortColumnRelX.Value; + offs = Math.Max(0, offs); + base.HorizontalScrollingOffset = offs; + } + + + private int absSortColumnX() + { + if (base.SortedColumn is null) + return 0; + int aggrclmwid = 0; + for (int i = 0; i < base.SortedColumn.Index; i++) + aggrclmwid += base.Columns[i].Width; + return aggrclmwid; + } -namespace core.audiamus.connect.ui { - class DataGridViewEx : DataGridView, ISortingEvents { - - private readonly Timer _timer1 = new Timer (); - private readonly Timer _timer2 = new Timer (); - private bool _ignoreFlag; - private bool _isSorting; - private bool _sortEndedVertPosSet; - private int? _sortColumnRelX; - private bool _clientAreaEnabled = true; - - public event EventHandler BeginSorting; - public event EventHandler EndSorting; - public event EventHandler SortingCompleteToSetVerticalPosition; - - public new ISortableBindingList DataSource { - get => base.DataSource as ISortableBindingList; - set { - base.DataSource = value; - value.BeginSorting += dataSource_BeginSorting; - value.EndSorting += dataSource_EndSorting; - } } - - public bool ClientAreaEnabled { - get => _clientAreaEnabled; - set { - _clientAreaEnabled = value; - var color = value ? SystemColors.ControlText : SystemColors.GrayText; - DefaultCellStyle.ForeColor = color; - DefaultCellStyle.SelectionForeColor = color; - ColumnHeadersDefaultCellStyle.ForeColor = color; - } - } - - public DataGridViewEx () { - _timer1.Interval = 100; - _timer1.Tick += timer1_Tick; - _timer2.Interval = 10; - _timer2.Tick += timer2_Tick; - } - - public void AddSelectedRowsSortedByIndex ( - List selected, - Func getProp, - IReadOnlyList dataSource, - Func approveCallback = null - ) { - var selectedRows = new DataGridViewRow[this.SelectedRows.Count]; - this.SelectedRows.CopyTo (selectedRows, 0); - Array.Sort (selectedRows, (x, y) => x.Index.CompareTo (y.Index)); - foreach (DataGridViewRow row in selectedRows) { - int idx = row.Index; - bool approved = approveCallback?.Invoke (idx) ?? true; - if (!approved) - continue; - S item = dataSource[idx]; - selected.Add (getProp (item)); - } - } - - protected override void OnDataBindingComplete (DataGridViewBindingCompleteEventArgs e) { - foreach (DataGridViewColumn clm in base.Columns) { - if (clm.ValueType == typeof (Image)) - clm.SortMode = DataGridViewColumnSortMode.Automatic; - } - base.OnDataBindingComplete (e); - } - - protected override void OnScroll (ScrollEventArgs e) { - if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) { - if (_ignoreFlag) - return; - _sortColumnRelX = null; - return; - } - _timer1.Enabled = false; - _timer1.Enabled = true; - - base.OnScroll (e); - } - - protected override void OnSelectionChanged (EventArgs e) { - if (_isSorting) - return; - - - base.OnSelectionChanged (e); - } - - protected override void OnMouseDown (MouseEventArgs e) { - if (ClientAreaEnabled) - base.OnMouseDown (e); - } - - private void timer1_Tick (object sender, EventArgs e) { - _timer1.Enabled = false; - base.AutoResizeColumns (DataGridViewAutoSizeColumnsMode.DisplayedCells); - setHorizontalPos (); - } - - private void timer2_Tick (object sender, EventArgs e) { - if (_sortEndedVertPosSet) { - _timer2.Enabled = false; - _timer2.Interval = 10; - - setHorizontalPos (); - } else { - _timer2.Interval = 50; - - SortingCompleteToSetVerticalPosition?.Invoke (sender, e); - - _sortEndedVertPosSet = true; - } - - } - - private void dataSource_BeginSorting (object sender, EventArgs e) { - _isSorting = true; - _sortEndedVertPosSet = false; - - var column = base.SortedColumn; - var clmRect = base.GetColumnDisplayRectangle (column.Index, true); - _sortColumnRelX = clmRect.X; - - BeginSorting?.Invoke (sender, e); - } - - private void dataSource_EndSorting (object sender, EventArgs e) { - EndSorting?.Invoke (sender, e); - - _timer2.Enabled = true; - _isSorting = false; - - } - - private void setHorizontalPos () { - if (!_sortColumnRelX.HasValue) - return; - using var rg = new ResourceGuard (x => _ignoreFlag = x); - // abs position of sort column - int aggrclmwid = absSortColumnX (); - - // offset of hor scrollbar - int offs = aggrclmwid - _sortColumnRelX.Value; - offs = Math.Max (0, offs); - base.HorizontalScrollingOffset = offs; - } - - - private int absSortColumnX () { - if (base.SortedColumn is null) - return 0; - int aggrclmwid = 0; - for (int i = 0; i < base.SortedColumn.Index; i++) - aggrclmwid += base.Columns[i].Width; - return aggrclmwid; - } - - } } diff --git a/src/PropGridLib.core/PropGridLib.core.csproj b/src/PropGridLib.core/PropGridLib.core.csproj index d67bf86..4ccd2eb 100644 --- a/src/PropGridLib.core/PropGridLib.core.csproj +++ b/src/PropGridLib.core/PropGridLib.core.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net10.0-windows true core.audiamus.aux.propgrid audiamus.aux.propgrid.core diff --git a/src/PropGridLib.core/PropertyGridExtension.cs b/src/PropGridLib.core/PropertyGridExtension.cs index ab886c5..246f441 100644 --- a/src/PropGridLib.core/PropertyGridExtension.cs +++ b/src/PropGridLib.core/PropertyGridExtension.cs @@ -4,82 +4,100 @@ using System.Reflection; using System.Windows.Forms; -namespace core.audiamus.aux.propgrid { - public static class PropertyGridExtensions { +namespace core.audiamus.aux.propgrid +{ + public static class PropertyGridExtensions + { - /// - /// Moves the property Grid's splitter bar over to fit the width - /// of the longest display name string + padding - /// - /// - /// The property Grid whose splitter bar is to be moved - /// Right padding to include with longest display name width - public static void MoveSplitterToLongestDisplayName (this PropertyGrid propertyGrid, int iPadding) { - try { + /// + /// Moves the property Grid's splitter bar over to fit the width + /// of the longest display name string + padding + /// + /// + /// The property Grid whose splitter bar is to be moved + /// Right padding to include with longest display name width + public static void MoveSplitterToLongestDisplayName(this PropertyGrid propertyGrid, int iPadding) + { + try + { - if (propertyGrid.SelectedObject is null) - return; + if (propertyGrid.SelectedObject is null) + return; - Size longestTextSize = new Size (); - if (propertyGrid.SelectedObject is DynamicTypeDescriptor dtd) { - var propdescs = dtd.GetProperties (new[] { new BrowsableAttribute (true) }); - foreach (PropertyDescriptor propdesc in propdescs) { - var browsable = propdesc.Attributes[typeof (BrowsableAttribute)] as BrowsableAttribute; - if (!(browsable?.Browsable ?? false)) - continue; - string displayName = propdesc.DisplayName; - Size textSize = TextRenderer.MeasureText (displayName, propertyGrid.Font); - if (textSize.Width > longestTextSize.Width) { - longestTextSize = textSize; + Size longestTextSize = new Size(); + if (propertyGrid.SelectedObject is DynamicTypeDescriptor dtd) + { + var propdescs = dtd.GetProperties(new[] { new BrowsableAttribute(true) }); + foreach (PropertyDescriptor propdesc in propdescs) + { + var browsable = propdesc.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute; + if (!(browsable?.Browsable ?? false)) + continue; + string displayName = propdesc.DisplayName; + Size textSize = TextRenderer.MeasureText(displayName, propertyGrid.Font); + if (textSize.Width > longestTextSize.Width) + { + longestTextSize = textSize; + } + } + } + + propertyGrid.MoveSplitterTo(longestTextSize.Width + 17 + iPadding); + } + catch (Exception) + { } - } } - propertyGrid.MoveSplitterTo (longestTextSize.Width + 17 + iPadding); - } catch (Exception) { - } - } - - /// - /// Gets the width of the left column. - /// - /// The property grid. - /// - /// The width of the left column. - /// - public static int GetInternalLabelWidth (this PropertyGrid propertyGrid) { - object gridView = getPropertyGridView (propertyGrid); + /// + /// Gets the width of the left column. + /// + /// The property grid. + /// + /// The width of the left column. + /// + public static int GetInternalLabelWidth(this PropertyGrid propertyGrid) + { + object gridView = getPropertyGridView(propertyGrid); - PropertyInfo pi = gridView.GetType ().GetProperty ( - "InternalLabelWidth", BindingFlags.NonPublic | BindingFlags.Instance); - return (int)pi.GetValue (gridView); - } + PropertyInfo pi = gridView.GetType().GetProperty( + "InternalLabelWidth", BindingFlags.NonPublic | BindingFlags.Instance); + return (int)pi.GetValue(gridView); + } - /// - /// Moves the property Grid's splitter bar to given position - /// - /// - /// - public static void MoveSplitterTo (this PropertyGrid propertyGrid, int position) { - object propertyGridView = getPropertyGridView (propertyGrid); + /// + /// Moves the property Grid's splitter bar to given position + /// + /// + /// + public static void MoveSplitterTo(this PropertyGrid propertyGrid, int position) + { + object propertyGridView = getPropertyGridView(propertyGrid); + if (propertyGridView != null) + { + MethodInfo mi = propertyGridView.GetType().GetMethod( + "MoveSplitterTo", BindingFlags.NonPublic | BindingFlags.Instance); + mi.Invoke(propertyGridView, new object[] { position }); + } + } - MethodInfo mi = propertyGridView.GetType ().GetMethod ( - "MoveSplitterTo", BindingFlags.NonPublic | BindingFlags.Instance); - mi.Invoke (propertyGridView, new object[] { position }); - } + /// + /// Gets the (private) PropertyGridView instance. + /// + /// The property grid. + /// The PropertyGridView instance. + private static object getPropertyGridView(this PropertyGrid propertyGrid) + { + MethodInfo mi = typeof(PropertyGrid).GetMethod( + "GetPropertyGridView", BindingFlags.NonPublic | BindingFlags.Instance); + if (mi != null) + { + return mi.Invoke(propertyGrid, Array.Empty()); + } + return null; + } - /// - /// Gets the (private) PropertyGridView instance. - /// - /// The property grid. - /// The PropertyGridView instance. - private static object getPropertyGridView (this PropertyGrid propertyGrid) { - MethodInfo mi = typeof (PropertyGrid).GetMethod ( - "GetPropertyGridView", BindingFlags.NonPublic | BindingFlags.Instance); - return mi.Invoke (propertyGrid, Array.Empty ()); } - - } } diff --git a/src/SystemMgmt.core/SystemMgmt.core.csproj b/src/SystemMgmt.core/SystemMgmt.core.csproj index 14b942a..c424849 100644 --- a/src/SystemMgmt.core/SystemMgmt.core.csproj +++ b/src/SystemMgmt.core/SystemMgmt.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.audiamus.sysmgmt audiamus.sysmgmt.core audiamus diff --git a/src/TreeDecomposition.core/TreeDecomposition.core.csproj b/src/TreeDecomposition.core/TreeDecomposition.core.csproj index f45b020..a8163ce 100644 --- a/src/TreeDecomposition.core/TreeDecomposition.core.csproj +++ b/src/TreeDecomposition.core/TreeDecomposition.core.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 core.core.audiamus.aux.diagn audiamus.aux.treedecomp.core audiamus