From c900fe8461f9ce595052801b7c873ff5e82b92dc Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 30 Dec 2022 17:00:16 -0700 Subject: [PATCH 01/14] Add user rating editing to grid --- Source/AppScaffolding/LibationScaffolding.cs | 2 +- Source/ApplicationServices/LibraryCommands.cs | 16 +- .../SearchEngineCommands.cs | 5 + .../AudibleUtilities/AudibleUtilities.csproj | 2 +- Source/DataLayer/EfClasses/UserDefinedItem.cs | 2 +- .../LibationAvalonia/Controls/RatingBox.axaml | 52 +++ .../Controls/RatingBox.axaml.cs | 125 +++++++ .../Dialogs/SearchSyntaxDialog.axaml | 6 +- .../LibationAvalonia/ViewModels/GridEntry.cs | 36 +- .../ViewModels/LibraryBookEntry.cs | 2 +- .../ViewModels/SeriesEntry.cs | 5 +- .../Views/MainWindow.BackupCounts.cs | 29 +- .../Views/MainWindow.VisibleBooks.cs | 6 +- .../Views/ProductsDisplay.axaml | 6 +- Source/LibationSearchEngine/SearchEngine.cs | 30 +- Source/LibationWinForms/GridView/GridEntry.cs | 43 ++- .../GridView/LibraryBookEntry.cs | 2 +- .../GridView/MyRatingGridViewColumn.cs | 73 ++++ .../GridView/ProductsGrid.Designer.cs | 6 +- .../LibationWinForms/GridView/ProductsGrid.cs | 4 + .../GridView/RatingPicker.Designer.cs | 348 ++++++++++++++++++ .../LibationWinForms/GridView/RatingPicker.cs | 142 +++++++ .../GridView/RatingPicker.resx | 60 +++ .../LibationWinForms/GridView/SeriesEntry.cs | 2 +- 24 files changed, 942 insertions(+), 62 deletions(-) create mode 100644 Source/LibationAvalonia/Controls/RatingBox.axaml create mode 100644 Source/LibationAvalonia/Controls/RatingBox.axaml.cs create mode 100644 Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs create mode 100644 Source/LibationWinForms/GridView/RatingPicker.Designer.cs create mode 100644 Source/LibationWinForms/GridView/RatingPicker.cs create mode 100644 Source/LibationWinForms/GridView/RatingPicker.resx diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index 924256db..2ab51557 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Reflection; using ApplicationServices; using AudibleUtilities; -using Dinah.Core.Collections.Generic; +using Dinah.Core; using Dinah.Core.IO; using Dinah.Core.Logging; using LibationFileManager; diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index d49c15aa..8d6f5a05 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -415,14 +415,16 @@ namespace ApplicationServices this Book book, string tags = null, LiberatedStatus? bookStatus = null, - LiberatedStatus? pdfStatus = null) - => new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus); + LiberatedStatus? pdfStatus = null, + Rating rating = null) + => new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus, rating); - public static int UpdateUserDefinedItem( + public static int UpdateUserDefinedItem( this IEnumerable books, string tags = null, LiberatedStatus? bookStatus = null, - LiberatedStatus? pdfStatus = null) + LiberatedStatus? pdfStatus = null, + Rating rating = null) => updateUserDefinedItem( books, udi => { @@ -435,6 +437,9 @@ namespace ApplicationServices // method handles null logic udi.SetPdfStatus(pdfStatus); + + if (rating is not null) + udi.Rating = rating; }); public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus) @@ -487,7 +492,10 @@ namespace ApplicationServices // Attach() NoTracking entities before SaveChanges() foreach (var book in books) + { context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + context.Attach(book.UserDefinedItem.Rating).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + } var qtyChanges = context.SaveChanges(); if (qtyChanges > 0) diff --git a/Source/ApplicationServices/SearchEngineCommands.cs b/Source/ApplicationServices/SearchEngineCommands.cs index efc21c7f..ad4b3fa8 100644 --- a/Source/ApplicationServices/SearchEngineCommands.cs +++ b/Source/ApplicationServices/SearchEngineCommands.cs @@ -46,6 +46,7 @@ namespace ApplicationServices { UpdateLiberatedStatus(book); UpdateBookTags(book); + UpdateUserRatings(book); } } } @@ -62,6 +63,10 @@ namespace ApplicationServices e.UpdateTags(book.AudibleProductId, book.UserDefinedItem.Tags) ); + internal static void UpdateUserRatings(Book book) => performSafeCommand(e => + e.UpdateUserRatings(book) + ); + private static void performSafeCommand(Action action) { try diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 963084fd..50f6bdc0 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,7 +5,7 @@ - + diff --git a/Source/DataLayer/EfClasses/UserDefinedItem.cs b/Source/DataLayer/EfClasses/UserDefinedItem.cs index 91bf236b..177eb79b 100644 --- a/Source/DataLayer/EfClasses/UserDefinedItem.cs +++ b/Source/DataLayer/EfClasses/UserDefinedItem.cs @@ -95,7 +95,7 @@ namespace DataLayer #region Rating // owned: not an optional one-to-one /// The user's individual book rating - public Rating Rating { get; private set; } = new Rating(0, 0, 0); + public Rating Rating { get; set; } = new Rating(0, 0, 0); public void UpdateRating(float overallRating, float performanceRating, float storyRating) => Rating.Update(overallRating, performanceRating, storyRating); diff --git a/Source/LibationAvalonia/Controls/RatingBox.axaml b/Source/LibationAvalonia/Controls/RatingBox.axaml new file mode 100644 index 00000000..4f3f6a03 --- /dev/null +++ b/Source/LibationAvalonia/Controls/RatingBox.axaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LibationAvalonia/Controls/RatingBox.axaml.cs b/Source/LibationAvalonia/Controls/RatingBox.axaml.cs new file mode 100644 index 00000000..f517ec5c --- /dev/null +++ b/Source/LibationAvalonia/Controls/RatingBox.axaml.cs @@ -0,0 +1,125 @@ +using Avalonia; +using Avalonia.Controls; +using DataLayer; +using NPOI.POIFS.Storage; +using System.Linq; + +namespace LibationAvalonia.Controls +{ + public partial class RatingBox : UserControl + { + private const string SOLID_STAR = "★"; + private const string HOLLOW_STAR = "☆"; + private static readonly char[] FIVE_STARS = { '★', '★', '★', '★', '★' }; + + public static readonly StyledProperty RatingProperty = + AvaloniaProperty.Register(nameof(Rating)); + + public Rating Rating + { + get { return GetValue(RatingProperty); } + set { SetValue(RatingProperty, value); } + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + if (change.Property.Name == nameof(Rating) && Rating is not null) + { + tblockOverallRating.Text = StarRating((int)Rating.OverallRating); + tblockPerformRating.Text = StarRating((int)Rating.PerformanceRating); + tblockStoryRating.Text = StarRating((int)Rating.StoryRating); + + if (this.IsPointerOver) + RatingBox_PointerEntered(this, null); + else + RatingBox_PointerExited(this, null); + } + base.OnPropertyChanged(change); + } + public RatingBox() + { + InitializeComponent(); + PointerEntered += RatingBox_PointerEntered; + PointerExited += RatingBox_PointerExited; + } + + private void RatingBox_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) + { + tblockOverall.IsVisible = Rating?.OverallRating > 0; + tblockPerform.IsVisible = Rating?.PerformanceRating > 0; + tblockStory.IsVisible = Rating?.StoryRating > 0; + } + + private void RatingBox_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) + { + tblockOverall.IsVisible = true; + tblockPerform.IsVisible = true; + tblockStory.IsVisible = true; + } + + private static string StarRating(int rating) => new string(FIVE_STARS, 0, rating); + public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) + { + var panel = sender as Panel; + var stackPanel = panel.Children.OfType().Single(); + + panel.Children.OfType().Single().IsVisible = true; + stackPanel.IsVisible = false; + + foreach (TextBlock child in stackPanel.Children) + child.Text = HOLLOW_STAR; + } + + public void Panel_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) + { + var panel = sender as Panel; + + panel.Children.OfType().Single().IsVisible = false; + panel.Children.OfType().Single().IsVisible = true; + } + + public void Star_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) + { + var thisTbox = sender as TextBlock; + var stackPanel = thisTbox.Parent as StackPanel; + + var star = SOLID_STAR; + + foreach (TextBlock child in stackPanel.Children) + { + child.Text = star; + if (child == thisTbox) star = HOLLOW_STAR; + } + } + + public void Star_Tapped(object sender, Avalonia.Input.TappedEventArgs e) + { + var overall = Rating.OverallRating; + var perform = Rating.PerformanceRating; + var story = Rating.StoryRating; + + var thisTbox = sender as TextBlock; + var stackPanel = thisTbox.Parent as StackPanel; + + int newRating = 0; + foreach (var tbox in stackPanel.Children) + { + newRating++; + if (tbox == thisTbox) break; + } + + var ratingName = ((Panel)stackPanel.Parent).Children.OfType().Single().Name; + + if (ratingName == tblockOverallRating.Name) + overall = newRating; + else if (ratingName == tblockPerformRating.Name) + perform = newRating; + else if (ratingName == tblockStoryRating.Name) + story = newRating; + + if (overall + perform + story == 0f) return; + + Rating = new Rating(overall, perform, story); + } + } +} diff --git a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml index d3ad7aa9..0e769a26 100644 --- a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml +++ b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml @@ -2,9 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="550" - MinWidth="950" MinHeight="550" - MaxWidth="950" MaxHeight="550" + mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="650" + MinWidth="950" MinHeight="650" + MaxWidth="950" MaxHeight="650" x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog" Title="Filter Options" WindowStartupLocation="CenterOwner" diff --git a/Source/LibationAvalonia/ViewModels/GridEntry.cs b/Source/LibationAvalonia/ViewModels/GridEntry.cs index 503965be..71007456 100644 --- a/Source/LibationAvalonia/ViewModels/GridEntry.cs +++ b/Source/LibationAvalonia/ViewModels/GridEntry.cs @@ -1,6 +1,8 @@ -using Avalonia.Media; +using ApplicationServices; +using Avalonia.Media; using DataLayer; using Dinah.Core; +using FileLiberator; using LibationFileManager; using ReactiveUI; using System; @@ -8,6 +10,7 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Threading.Tasks; namespace LibationAvalonia.ViewModels { @@ -42,7 +45,19 @@ namespace LibationAvalonia.ViewModels public string Misc { get; protected set; } public string Description { get; protected set; } public string ProductRating { get; protected set; } - public string MyRating { get; protected set; } + public string MyRatingString => Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + protected Rating _myRating; + public Rating MyRating + { + get => _myRating; + set + { + if (_myRating != value && updateReviewTask?.IsCompleted is not false) + { + updateReviewTask = UpdateRating(value); + } + } + } protected bool? _remove = false; public abstract bool? Remove { get; set; } @@ -56,6 +71,23 @@ namespace LibationAvalonia.ViewModels #endregion + #region User rating + + private Task updateReviewTask; + private async Task UpdateRating(Rating rating) + { + var api = await LibraryBook.GetApiAsync(); + + if (await api.ReviewAsync(Book.AudibleProductId, (int)rating.OverallRating, (int)rating.PerformanceRating, (int)rating.StoryRating)) + { + _myRating = rating; + LibraryBook.Book.UpdateUserDefinedItem(null, null, null, rating); + } + + this.RaisePropertyChanged(nameof(MyRating)); + } + #endregion + #region Sorting public GridEntry() => _memberValues = CreateMemberValueDictionary(); diff --git a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs index fce3e875..a172e87b 100644 --- a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs +++ b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs @@ -65,7 +65,7 @@ namespace LibationAvalonia.ViewModels Title = Book.Title; Series = Book.SeriesNames(); Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min"; - MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + _myRating = Book.UserDefinedItem.Rating; PurchaseDate = libraryBook.DateAdded.ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); diff --git a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs index eb82a99b..67a46db7 100644 --- a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs +++ b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs @@ -1,5 +1,4 @@ -using Avalonia.Media; -using DataLayer; +using DataLayer; using Dinah.Core; using ReactiveUI; using System; @@ -69,7 +68,7 @@ namespace LibationAvalonia.ViewModels Title = Book.Title; Series = Book.SeriesNames(); - MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + _myRating = Book.UserDefinedItem.Rating; ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); Narrators = Book.NarratorNames(); diff --git a/Source/LibationAvalonia/Views/MainWindow.BackupCounts.cs b/Source/LibationAvalonia/Views/MainWindow.BackupCounts.cs index 50521969..41a5e1a8 100644 --- a/Source/LibationAvalonia/Views/MainWindow.BackupCounts.cs +++ b/Source/LibationAvalonia/Views/MainWindow.BackupCounts.cs @@ -2,43 +2,24 @@ using System; using System.Linq; using Avalonia.Threading; -using Dinah.Core; +using System.Threading.Tasks; namespace LibationAvalonia.Views { - //DONE public partial class MainWindow { - private System.ComponentModel.BackgroundWorker updateCountsBw = new(); + private Task updateCountsTask; private void Configure_BackupCounts() { Load += setBackupCounts; LibraryCommands.LibrarySizeChanged += setBackupCounts; LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts; - - updateCountsBw.DoWork += UpdateCountsBw_DoWork; - updateCountsBw.RunWorkerCompleted += updateBottomNumbersAsync; } - private bool runBackupCountsAgain; + private void setBackupCounts(object _, object __) { - runBackupCountsAgain = true; - - if (!updateCountsBw.IsBusy) - updateCountsBw.RunWorkerAsync(); - } - private void UpdateCountsBw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) - { - while (runBackupCountsAgain) - { - runBackupCountsAgain = false; - e.Result = LibraryCommands.GetCounts(); - } - } - - private void updateBottomNumbersAsync(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) - { - _viewModel.LibraryStats = e.Result as LibraryCommands.LibraryStats; + if (updateCountsTask?.IsCompleted is not false) + updateCountsTask = Dispatcher.UIThread.InvokeAsync(() => _viewModel.LibraryStats = LibraryCommands.GetCounts()); } } } diff --git a/Source/LibationAvalonia/Views/MainWindow.VisibleBooks.cs b/Source/LibationAvalonia/Views/MainWindow.VisibleBooks.cs index 3abf0ba4..d3a2402f 100644 --- a/Source/LibationAvalonia/Views/MainWindow.VisibleBooks.cs +++ b/Source/LibationAvalonia/Views/MainWindow.VisibleBooks.cs @@ -18,7 +18,7 @@ namespace LibationAvalonia.Views } private async void setLiberatedVisibleMenuItemAsync(object _, object __) - => await Task.Run(setLiberatedVisibleMenuItem); + => await Dispatcher.UIThread.InvokeAsync(setLiberatedVisibleMenuItem); public void liberateVisible(object sender, Avalonia.Interactivity.RoutedEventArgs args) { @@ -114,7 +114,7 @@ namespace LibationAvalonia.Views return; var bulkSetStatus = new BulkSetDownloadStatus(_viewModel.ProductsDisplay.GetVisibleBookEntries(), dialog.SetDownloaded, dialog.SetNotDownloaded); - var count = await Task.Run(() => bulkSetStatus.Discover()); + var count = await Task.Run(bulkSetStatus.Discover); if (count == 0) return; @@ -154,7 +154,7 @@ namespace LibationAvalonia.Views { _viewModel.VisibleCount = qty; - await Task.Run(setLiberatedVisibleMenuItem); + await Dispatcher.UIThread.InvokeAsync(setLiberatedVisibleMenuItem); } void setLiberatedVisibleMenuItem() => _viewModel.VisibleNotLiberated diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index a4a7fbae..7175106d 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -124,7 +124,7 @@ - + @@ -160,11 +160,11 @@ - + - + diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs index e3e733d2..c4537d1f 100644 --- a/Source/LibationSearchEngine/SearchEngine.cs +++ b/Source/LibationSearchEngine/SearchEngine.cs @@ -89,9 +89,9 @@ namespace LibationSearchEngine ["Hours"] = lb => (lb.Book.LengthInMinutes / 60).ToLuceneString(), ["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), - ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), - ["UserRating"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating.ToLuceneString(), - ["MyRating"] = lb => lb.Book.UserDefinedItem.Rating.OverallRating.ToLuceneString() + ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), + ["UserRating"] = lb => userRating(lb.Book), + ["MyRating"] = lb => userRating(lb.Book) } ); @@ -136,8 +136,8 @@ namespace LibationSearchEngine var narrators = lb.Book.Narrators.Select(a => a.Name).ToArray(); return authors.Intersect(narrators).Any(); } - - private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated; + private static string userRating(Book book) => book.UserDefinedItem.Rating.OverallRating.ToLuceneString(); + private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated; private static bool liberatedError(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Error; // use these common fields in the "all" default search field @@ -289,7 +289,25 @@ namespace LibationSearchEngine d.AddBool("LiberatedError", v2); }); - private static void updateDocument(string productId, Action action) + public void UpdateUserRatings(Book book) + => updateDocument( + book.AudibleProductId, + d => + { + // + // TODO: better synonym handling. This is too easy to mess up + // + + // fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY. + // ie: must remove old before adding new else will create unwanted duplicates. + var v1 = userRating(book); + d.RemoveField("UserRating"); + d.AddNotAnalyzed("UserRating", v1); + d.RemoveField("MyRating"); + d.AddNotAnalyzed("MyRating", v1); + }); + + private static void updateDocument(string productId, Action action) { var productTerm = new Term(_ID_, productId); diff --git a/Source/LibationWinForms/GridView/GridEntry.cs b/Source/LibationWinForms/GridView/GridEntry.cs index b8cb97d2..c779d597 100644 --- a/Source/LibationWinForms/GridView/GridEntry.cs +++ b/Source/LibationWinForms/GridView/GridEntry.cs @@ -1,7 +1,9 @@ -using DataLayer; +using ApplicationServices; +using DataLayer; using Dinah.Core; using Dinah.Core.DataBinding; using Dinah.Core.WindowsDesktop.Drawing; +using FileLiberator; using LibationFileManager; using System; using System.Collections; @@ -9,6 +11,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; +using System.Threading.Tasks; namespace LibationWinForms.GridView { @@ -57,14 +60,44 @@ namespace LibationWinForms.GridView public string Misc { get; protected set; } public string Description { get; protected set; } public string ProductRating { get; protected set; } - public string MyRating { get; protected set; } + protected Rating _myRating; + public Rating MyRating + { + get => _myRating; + set + { + if (_myRating != value + && (value.OverallRating + value.PerformanceRating + value.StoryRating) > 0 + && updateReviewTask?.IsCompleted is not false) + { + updateReviewTask = UpdateRating(value); + } + } + } public abstract string DisplayTags { get; } - #endregion + #endregion - #region Sorting + #region User rating - public GridEntry() => _memberValues = CreateMemberValueDictionary(); + private Task updateReviewTask; + private async Task UpdateRating(Rating rating) + { + var api = await LibraryBook.GetApiAsync(); + + if (await api.ReviewAsync(Book.AudibleProductId, (int)rating.OverallRating, (int)rating.PerformanceRating, (int)rating.StoryRating)) + { + _myRating = rating; + LibraryBook.Book.UpdateUserDefinedItem(null, null, null, rating); + } + + this.NotifyPropertyChanged(nameof(MyRating)); + } + #endregion + + #region Sorting + + public GridEntry() => _memberValues = CreateMemberValueDictionary(); // These methods are implementation of Dinah.Core.DataBinding.IMemberComparable // Used by GridEntryBindingList for all sorting diff --git a/Source/LibationWinForms/GridView/LibraryBookEntry.cs b/Source/LibationWinForms/GridView/LibraryBookEntry.cs index 531a941d..315232b8 100644 --- a/Source/LibationWinForms/GridView/LibraryBookEntry.cs +++ b/Source/LibationWinForms/GridView/LibraryBookEntry.cs @@ -80,7 +80,7 @@ namespace LibationWinForms.GridView Title = Book.Title; Series = Book.SeriesNames(); Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min"; - MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + MyRating = Book.UserDefinedItem.Rating; PurchaseDate = libraryBook.DateAdded.ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); diff --git a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs new file mode 100644 index 00000000..fdab268e --- /dev/null +++ b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs @@ -0,0 +1,73 @@ +using DataLayer; +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; + +namespace LibationWinForms.GridView +{ + public class MyRatingGridViewColumn : DataGridViewColumn + { + public MyRatingGridViewColumn() : base(new MyRatingGridViewCell()) { } + + public override DataGridViewCell CellTemplate + { + get => base.CellTemplate; + set + { + if (value is not MyRatingGridViewCell) + throw new InvalidCastException("Must be a MyRatingGridViewCell"); + + base.CellTemplate = value; + } + } + } + + internal class MyRatingGridViewCell : DataGridViewTextBoxCell + { + public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) + { + base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); + + var ctl = DataGridView.EditingControl as RatingPicker; + + ctl.Rating = + Value is Rating rating + ? rating + : (Rating)DefaultNewRowValue; + } + + public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter) + { + const char SOLID_STAR = '★'; + if (formattedValue is string s) + { + int overall = 0, performance = 0, story = 0; + + foreach (var line in s.Split('\n')) + { + if (line.Contains("Overall")) + overall = line.Count(c => c == SOLID_STAR); + else if (line.Contains("Perform")) + performance = line.Count(c => c == SOLID_STAR); + else if (line.Contains("Story")) + story = line.Count(c => c == SOLID_STAR); + } + + return new Rating(overall, performance, story); + } + else + return DefaultNewRowValue; + } + + + protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) + => value is Rating rating + ? rating.ToStarString() + : base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context); + + public override Type EditType => typeof(RatingPicker); + public override object DefaultNewRowValue => new Rating(0, 0, 0); + public override Type ValueType => typeof(Rating); + } +} diff --git a/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs b/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs index 6da37a16..8aa2b188 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs @@ -43,7 +43,7 @@ this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.productRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.myRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.myRatingGVColumn = new MyRatingGridViewColumn(); this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn(); this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); @@ -204,7 +204,7 @@ this.myRatingGVColumn.DataPropertyName = "MyRating"; this.myRatingGVColumn.HeaderText = "My Rating"; this.myRatingGVColumn.Name = "myRatingGVColumn"; - this.myRatingGVColumn.ReadOnly = true; + this.myRatingGVColumn.ReadOnly = false; this.myRatingGVColumn.Width = 108; // // miscGVColumn @@ -265,7 +265,7 @@ private System.Windows.Forms.DataGridViewTextBoxColumn categoryGVColumn; private System.Windows.Forms.DataGridViewTextBoxColumn productRatingGVColumn; private System.Windows.Forms.DataGridViewTextBoxColumn purchaseDateGVColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn myRatingGVColumn; + private MyRatingGridViewColumn myRatingGVColumn; private System.Windows.Forms.DataGridViewTextBoxColumn miscGVColumn; private EditTagsDataGridViewImageButtonColumn tagAndDetailsGVColumn; } diff --git a/Source/LibationWinForms/GridView/ProductsGrid.cs b/Source/LibationWinForms/GridView/ProductsGrid.cs index 0ac93377..90093f27 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.cs @@ -40,6 +40,8 @@ namespace LibationWinForms.GridView EnableDoubleBuffering(); gridEntryDataGridView.Scroll += (_, s) => Scroll?.Invoke(this, s); removeGVColumn.Frozen = false; + + gridEntryDataGridView.EditMode = DataGridViewEditMode.EditOnEnter; } private void EnableDoubleBuffering() @@ -49,6 +51,8 @@ namespace LibationWinForms.GridView propertyInfo.SetValue(gridEntryDataGridView, true, null); } + + #region Button controls private void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) { diff --git a/Source/LibationWinForms/GridView/RatingPicker.Designer.cs b/Source/LibationWinForms/GridView/RatingPicker.Designer.cs new file mode 100644 index 00000000..d6705129 --- /dev/null +++ b/Source/LibationWinForms/GridView/RatingPicker.Designer.cs @@ -0,0 +1,348 @@ +namespace LibationWinForms.GridView +{ + partial class RatingPicker + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.panel2 = new System.Windows.Forms.Panel(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.panel3 = new System.Windows.Forms.Panel(); + this.label14 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.panel3.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(0, 0); + this.label1.Margin = new System.Windows.Forms.Padding(0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(12, 15); + this.label1.TabIndex = 0; + this.label1.Text = "☆"; + this.label1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label1.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label1.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label2 + // + this.label2.Location = new System.Drawing.Point(12, 0); + this.label2.Margin = new System.Windows.Forms.Padding(0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(12, 15); + this.label2.TabIndex = 1; + this.label2.Text = "☆"; + this.label2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label2.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label2.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label3 + // + this.label3.Location = new System.Drawing.Point(24, 0); + this.label3.Margin = new System.Windows.Forms.Padding(0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(12, 15); + this.label3.TabIndex = 3; + this.label3.Text = "☆"; + this.label3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label3.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label3.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label4 + // + this.label4.Location = new System.Drawing.Point(36, 0); + this.label4.Margin = new System.Windows.Forms.Padding(0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(12, 15); + this.label4.TabIndex = 2; + this.label4.Text = "☆"; + this.label4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label4.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label4.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label5 + // + this.label5.Location = new System.Drawing.Point(48, 0); + this.label5.Margin = new System.Windows.Forms.Padding(0); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(12, 15); + this.label5.TabIndex = 4; + this.label5.Text = "☆"; + this.label5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label5.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label5.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // panel1 + // + this.panel1.Controls.Add(this.label1); + this.panel1.Controls.Add(this.label2); + this.panel1.Controls.Add(this.label3); + this.panel1.Controls.Add(this.label4); + this.panel1.Controls.Add(this.label5); + this.panel1.Location = new System.Drawing.Point(45, 13); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(60, 15); + this.panel1.TabIndex = 5; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(0, 13); + this.label6.Margin = new System.Windows.Forms.Padding(0); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(47, 15); + this.label6.TabIndex = 6; + this.label6.Text = "Overall:"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.label7.Location = new System.Drawing.Point(0, 32); + this.label7.Margin = new System.Windows.Forms.Padding(0); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(46, 15); + this.label7.TabIndex = 8; + this.label7.Text = "Perfrm:"; + // + // panel2 + // + this.panel2.Controls.Add(this.label8); + this.panel2.Controls.Add(this.label9); + this.panel2.Controls.Add(this.label10); + this.panel2.Controls.Add(this.label11); + this.panel2.Controls.Add(this.label12); + this.panel2.Location = new System.Drawing.Point(45, 32); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(60, 15); + this.panel2.TabIndex = 7; + // + // label8 + // + this.label8.Location = new System.Drawing.Point(0, 0); + this.label8.Margin = new System.Windows.Forms.Padding(0); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(12, 15); + this.label8.TabIndex = 0; + this.label8.Text = "☆"; + this.label8.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label8.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label8.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label9 + // + this.label9.Location = new System.Drawing.Point(12, 0); + this.label9.Margin = new System.Windows.Forms.Padding(0); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(12, 15); + this.label9.TabIndex = 1; + this.label9.Text = "☆"; + this.label9.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label9.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label9.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label10 + // + this.label10.Location = new System.Drawing.Point(24, 0); + this.label10.Margin = new System.Windows.Forms.Padding(0); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(12, 15); + this.label10.TabIndex = 3; + this.label10.Text = "☆"; + this.label10.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label10.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label10.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label11 + // + this.label11.Location = new System.Drawing.Point(36, 0); + this.label11.Margin = new System.Windows.Forms.Padding(0); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(12, 15); + this.label11.TabIndex = 2; + this.label11.Text = "☆"; + this.label11.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label11.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label11.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label12 + // + this.label12.Location = new System.Drawing.Point(48, 0); + this.label12.Margin = new System.Windows.Forms.Padding(0); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(12, 15); + this.label12.TabIndex = 4; + this.label12.Text = "☆"; + this.label12.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label12.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label12.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(0, 51); + this.label13.Margin = new System.Windows.Forms.Padding(0); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(37, 15); + this.label13.TabIndex = 10; + this.label13.Text = "Story:"; + // + // panel3 + // + this.panel3.Controls.Add(this.label14); + this.panel3.Controls.Add(this.label15); + this.panel3.Controls.Add(this.label16); + this.panel3.Controls.Add(this.label17); + this.panel3.Controls.Add(this.label18); + this.panel3.Location = new System.Drawing.Point(45, 51); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(60, 15); + this.panel3.TabIndex = 9; + // + // label14 + // + this.label14.Location = new System.Drawing.Point(0, 0); + this.label14.Margin = new System.Windows.Forms.Padding(0); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(12, 15); + this.label14.TabIndex = 0; + this.label14.Text = "☆"; + this.label14.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label14.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label14.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label15 + // + this.label15.Location = new System.Drawing.Point(12, 0); + this.label15.Margin = new System.Windows.Forms.Padding(0); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(12, 15); + this.label15.TabIndex = 1; + this.label15.Text = "☆"; + this.label15.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label15.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label15.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label16 + // + this.label16.Location = new System.Drawing.Point(24, 0); + this.label16.Margin = new System.Windows.Forms.Padding(0); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(12, 15); + this.label16.TabIndex = 3; + this.label16.Text = "☆"; + this.label16.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label16.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label16.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label17 + // + this.label17.Location = new System.Drawing.Point(36, 0); + this.label17.Margin = new System.Windows.Forms.Padding(0); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(12, 15); + this.label17.TabIndex = 2; + this.label17.Text = "☆"; + this.label17.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label17.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label17.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // label18 + // + this.label18.Location = new System.Drawing.Point(48, 0); + this.label18.Margin = new System.Windows.Forms.Padding(0); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(12, 15); + this.label18.TabIndex = 4; + this.label18.Text = "☆"; + this.label18.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.label18.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.label18.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // RatingPicker + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.label13); + this.Controls.Add(this.panel3); + this.Controls.Add(this.label7); + this.Controls.Add(this.panel2); + this.Controls.Add(this.label6); + this.Controls.Add(this.panel1); + this.Name = "RatingPicker"; + this.Size = new System.Drawing.Size(108, 80); + this.panel1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel3.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + } +} diff --git a/Source/LibationWinForms/GridView/RatingPicker.cs b/Source/LibationWinForms/GridView/RatingPicker.cs new file mode 100644 index 00000000..94478dec --- /dev/null +++ b/Source/LibationWinForms/GridView/RatingPicker.cs @@ -0,0 +1,142 @@ +using DataLayer; +using Mpeg4Lib.Boxes; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LibationWinForms.GridView +{ + public partial class RatingPicker : UserControl, IDataGridViewEditingControl + { + private const string SOLID_STAR = "★"; + private const string HOLLOW_STAR = "☆"; + + private Rating _rating; + public Rating Rating { + get => _rating; + set + { + _rating = value; + int rating = 0; + foreach (Label star in panel1.Controls) + star.Tag = star.Text = _rating.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + + rating = 0; + foreach (Label star in panel2.Controls) + star.Tag = star.Text = _rating.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + + rating = 0; + foreach (Label star in panel3.Controls) + star.Tag = star.Text = _rating.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + } + } + public RatingPicker() + { + InitializeComponent(); + } + + private void Star_MouseEnter(object sender, EventArgs e) + { + var thisTbox = sender as Label; + var stackPanel = thisTbox.Parent as Panel; + var star = SOLID_STAR; + + foreach (Label child in stackPanel.Controls) + { + child.Text = star; + if (child == thisTbox) star = HOLLOW_STAR; + } + } + + private void Star_MouseLeave(object sender, EventArgs e) + { + var thisTbox = sender as Label; + var panel = thisTbox.Parent as Panel; + + //Artifically shrink rectangle to guarantee mouse is outside when exiting from the left (negative X) + var clientPt = panel.PointToClient(MousePosition); + var rect = new Rectangle(0, 0, panel.ClientRectangle.Width - 2, panel.ClientRectangle.Height); + if (!rect.Contains(clientPt.X - 2, clientPt.Y)) + { + //Restore defaults + foreach (Label child in panel.Controls) + child.Text = (string)child.Tag; + } + } + + private void Star_MouseClick(object sender, MouseEventArgs e) + { + var overall = Rating.OverallRating; + var perform = Rating.PerformanceRating; + var story = Rating.StoryRating; + + var thisTbox = sender as Label; + var panel = thisTbox.Parent as Panel; + + int newRating = 0; + foreach (var child in panel.Controls) + { + newRating++; + if (child == thisTbox) break; + } + + if (panel == panel1) + overall = newRating; + else if (panel == panel2) + perform = newRating; + else if (panel == panel3) + story = newRating; + + if (overall + perform + story == 0f) return; + + Rating = new Rating(overall, perform, story); + EditingControlValueChanged = true; + EditingControlDataGridView.NotifyCurrentCellDirty(true); + } + + DataGridView dataGridView; + private bool valueChanged = false; + int rowIndex; + + #region IDataGridViewEditingControl + public DataGridView EditingControlDataGridView { get => dataGridView; set => dataGridView = value; } + public object EditingControlFormattedValue { get => Rating.ToStarString(); set { } } + public int EditingControlRowIndex { get => rowIndex; set => rowIndex = value; } + public bool EditingControlValueChanged { get => valueChanged; set => valueChanged = value; } + + public Cursor EditingPanelCursor => base.Cursor; + + public bool RepositionEditingControlOnValueChange => false; + + public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) + { + this.Font = dataGridViewCellStyle.Font; + this.ForeColor = dataGridViewCellStyle.ForeColor; + this.BackColor = dataGridViewCellStyle.BackColor; + } + + public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) + { + switch (keyData & Keys.KeyCode) + { + case Keys.Enter: + case Keys.Escape: + return true; + default: + return !dataGridViewWantsInputKey; + } + } + + public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => EditingControlFormattedValue; + + public void PrepareEditingControlForEdit(bool selectAll) { } + + #endregion + } +} diff --git a/Source/LibationWinForms/GridView/RatingPicker.resx b/Source/LibationWinForms/GridView/RatingPicker.resx new file mode 100644 index 00000000..f298a7be --- /dev/null +++ b/Source/LibationWinForms/GridView/RatingPicker.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/LibationWinForms/GridView/SeriesEntry.cs b/Source/LibationWinForms/GridView/SeriesEntry.cs index 1ebe5e4f..53191808 100644 --- a/Source/LibationWinForms/GridView/SeriesEntry.cs +++ b/Source/LibationWinForms/GridView/SeriesEntry.cs @@ -89,7 +89,7 @@ namespace LibationWinForms.GridView Title = Book.Title; Series = Book.SeriesNames(); - MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + MyRating = Book.UserDefinedItem.Rating; PurchaseDate = Children.Min(c => c.LibraryBook.DateAdded).ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); From 496830d01d41c174a8a1de4f2b128e8258e205e4 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 30 Dec 2022 19:25:11 -0700 Subject: [PATCH 02/14] Fix cell editor to work with desktop scaling --- .../GridView/LibraryBookEntry.cs | 2 +- .../GridView/MyRatingCellEditor.Designer.cs | 384 ++++++++++++++++++ ...{RatingPicker.cs => MyRatingCellEditor.cs} | 51 ++- ...ingPicker.resx => MyRatingCellEditor.resx} | 0 .../GridView/MyRatingGridViewColumn.cs | 58 +-- .../GridView/RatingPicker.Designer.cs | 348 ---------------- .../LibationWinForms/GridView/SeriesEntry.cs | 2 +- 7 files changed, 431 insertions(+), 414 deletions(-) create mode 100644 Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs rename Source/LibationWinForms/GridView/{RatingPicker.cs => MyRatingCellEditor.cs} (77%) rename Source/LibationWinForms/GridView/{RatingPicker.resx => MyRatingCellEditor.resx} (100%) delete mode 100644 Source/LibationWinForms/GridView/RatingPicker.Designer.cs diff --git a/Source/LibationWinForms/GridView/LibraryBookEntry.cs b/Source/LibationWinForms/GridView/LibraryBookEntry.cs index 315232b8..ce029c79 100644 --- a/Source/LibationWinForms/GridView/LibraryBookEntry.cs +++ b/Source/LibationWinForms/GridView/LibraryBookEntry.cs @@ -80,7 +80,7 @@ namespace LibationWinForms.GridView Title = Book.Title; Series = Book.SeriesNames(); Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min"; - MyRating = Book.UserDefinedItem.Rating; + _myRating = Book.UserDefinedItem.Rating; PurchaseDate = libraryBook.DateAdded.ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); diff --git a/Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs b/Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs new file mode 100644 index 00000000..943847fc --- /dev/null +++ b/Source/LibationWinForms/GridView/MyRatingCellEditor.Designer.cs @@ -0,0 +1,384 @@ +namespace LibationWinForms.GridView +{ + partial class MyRatingCellEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblOverall = new System.Windows.Forms.Label(); + this.lblPerform = new System.Windows.Forms.Label(); + this.lblStory = new System.Windows.Forms.Label(); + this.starOverall1 = new System.Windows.Forms.Label(); + this.starOverall2 = new System.Windows.Forms.Label(); + this.starOverall3 = new System.Windows.Forms.Label(); + this.starOverall4 = new System.Windows.Forms.Label(); + this.starOverall5 = new System.Windows.Forms.Label(); + this.panelOverall = new System.Windows.Forms.Panel(); + this.panelPerform = new System.Windows.Forms.Panel(); + this.starPerform1 = new System.Windows.Forms.Label(); + this.starPerform2 = new System.Windows.Forms.Label(); + this.starPerform3 = new System.Windows.Forms.Label(); + this.starPerform4 = new System.Windows.Forms.Label(); + this.starPerform5 = new System.Windows.Forms.Label(); + this.panelStory = new System.Windows.Forms.Panel(); + this.starStory1 = new System.Windows.Forms.Label(); + this.starStory2 = new System.Windows.Forms.Label(); + this.starStory3 = new System.Windows.Forms.Label(); + this.starStory4 = new System.Windows.Forms.Label(); + this.starStory5 = new System.Windows.Forms.Label(); + this.panelOverall.SuspendLayout(); + this.panelPerform.SuspendLayout(); + this.panelStory.SuspendLayout(); + this.SuspendLayout(); + // + // lblOverall + // + this.lblOverall.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblOverall.AutoSize = true; + this.lblOverall.Location = new System.Drawing.Point(0, 0); + this.lblOverall.Margin = new System.Windows.Forms.Padding(0); + this.lblOverall.Name = "lblOverall"; + this.lblOverall.Size = new System.Drawing.Size(47, 15); + this.lblOverall.TabIndex = 6; + this.lblOverall.Text = "Overall:"; + // + // lblPerform + // + this.lblPerform.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblPerform.AutoSize = true; + this.lblPerform.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.lblPerform.Location = new System.Drawing.Point(0, 15); + this.lblPerform.Margin = new System.Windows.Forms.Padding(0); + this.lblPerform.Name = "lblPerform"; + this.lblPerform.Size = new System.Drawing.Size(53, 15); + this.lblPerform.TabIndex = 8; + this.lblPerform.Text = "Perform:"; + // + // lblStory + // + this.lblStory.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblStory.AutoSize = true; + this.lblStory.Location = new System.Drawing.Point(0, 30); + this.lblStory.Margin = new System.Windows.Forms.Padding(0); + this.lblStory.Name = "lblStory"; + this.lblStory.Size = new System.Drawing.Size(37, 15); + this.lblStory.TabIndex = 10; + this.lblStory.Text = "Story:"; + // + // starOverall1 + // + this.starOverall1.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starOverall1.Location = new System.Drawing.Point(0, 0); + this.starOverall1.Margin = new System.Windows.Forms.Padding(0); + this.starOverall1.Name = "starOverall1"; + this.starOverall1.Size = new System.Drawing.Size(9, 10); + this.starOverall1.TabIndex = 0; + this.starOverall1.Text = "☆"; + this.starOverall1.UseCompatibleTextRendering = true; + this.starOverall1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starOverall1.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starOverall1.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starOverall2 + // + this.starOverall2.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starOverall2.Location = new System.Drawing.Point(9, 0); + this.starOverall2.Margin = new System.Windows.Forms.Padding(0); + this.starOverall2.Name = "starOverall2"; + this.starOverall2.Size = new System.Drawing.Size(9, 10); + this.starOverall2.TabIndex = 1; + this.starOverall2.Text = "☆"; + this.starOverall2.UseCompatibleTextRendering = true; + this.starOverall2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starOverall2.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starOverall2.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starOverall3 + // + this.starOverall3.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starOverall3.Location = new System.Drawing.Point(18, 0); + this.starOverall3.Margin = new System.Windows.Forms.Padding(0); + this.starOverall3.Name = "starOverall3"; + this.starOverall3.Size = new System.Drawing.Size(9, 10); + this.starOverall3.TabIndex = 3; + this.starOverall3.Text = "☆"; + this.starOverall3.UseCompatibleTextRendering = true; + this.starOverall3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starOverall3.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starOverall3.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starOverall4 + // + this.starOverall4.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starOverall4.Location = new System.Drawing.Point(27, 0); + this.starOverall4.Margin = new System.Windows.Forms.Padding(0); + this.starOverall4.Name = "starOverall4"; + this.starOverall4.Size = new System.Drawing.Size(9, 10); + this.starOverall4.TabIndex = 2; + this.starOverall4.Text = "☆"; + this.starOverall4.UseCompatibleTextRendering = true; + this.starOverall4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starOverall4.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starOverall4.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starOverall5 + // + this.starOverall5.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starOverall5.Location = new System.Drawing.Point(36, 0); + this.starOverall5.Margin = new System.Windows.Forms.Padding(0); + this.starOverall5.Name = "starOverall5"; + this.starOverall5.Size = new System.Drawing.Size(9, 10); + this.starOverall5.TabIndex = 4; + this.starOverall5.Text = "☆"; + this.starOverall5.UseCompatibleTextRendering = true; + this.starOverall5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starOverall5.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starOverall5.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // panelOverall + // + this.panelOverall.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.panelOverall.Controls.Add(this.starOverall1); + this.panelOverall.Controls.Add(this.starOverall2); + this.panelOverall.Controls.Add(this.starOverall3); + this.panelOverall.Controls.Add(this.starOverall4); + this.panelOverall.Controls.Add(this.starOverall5); + this.panelOverall.Location = new System.Drawing.Point(55, 3); + this.panelOverall.Name = "panelOverall"; + this.panelOverall.Size = new System.Drawing.Size(45, 10); + this.panelOverall.TabIndex = 5; + // + // panelPerform + // + this.panelPerform.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.panelPerform.Controls.Add(this.starPerform1); + this.panelPerform.Controls.Add(this.starPerform2); + this.panelPerform.Controls.Add(this.starPerform3); + this.panelPerform.Controls.Add(this.starPerform4); + this.panelPerform.Controls.Add(this.starPerform5); + this.panelPerform.Location = new System.Drawing.Point(55, 18); + this.panelPerform.Name = "panelPerform"; + this.panelPerform.Size = new System.Drawing.Size(45, 10); + this.panelPerform.TabIndex = 7; + // + // starPerform1 + // + this.starPerform1.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starPerform1.Location = new System.Drawing.Point(0, 0); + this.starPerform1.Margin = new System.Windows.Forms.Padding(0); + this.starPerform1.Name = "starPerform1"; + this.starPerform1.Size = new System.Drawing.Size(9, 10); + this.starPerform1.TabIndex = 0; + this.starPerform1.Text = "☆"; + this.starPerform1.UseCompatibleTextRendering = true; + this.starPerform1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starPerform1.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starPerform1.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starPerform2 + // + this.starPerform2.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starPerform2.Location = new System.Drawing.Point(9, 0); + this.starPerform2.Margin = new System.Windows.Forms.Padding(0); + this.starPerform2.Name = "starPerform2"; + this.starPerform2.Size = new System.Drawing.Size(9, 10); + this.starPerform2.TabIndex = 1; + this.starPerform2.Text = "☆"; + this.starPerform2.UseCompatibleTextRendering = true; + this.starPerform2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starPerform2.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starPerform2.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starPerform3 + // + this.starPerform3.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starPerform3.Location = new System.Drawing.Point(18, 0); + this.starPerform3.Margin = new System.Windows.Forms.Padding(0); + this.starPerform3.Name = "starPerform3"; + this.starPerform3.Size = new System.Drawing.Size(9, 10); + this.starPerform3.TabIndex = 3; + this.starPerform3.Text = "☆"; + this.starPerform3.UseCompatibleTextRendering = true; + this.starPerform3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starPerform3.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starPerform3.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starPerform4 + // + this.starPerform4.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starPerform4.Location = new System.Drawing.Point(27, 0); + this.starPerform4.Margin = new System.Windows.Forms.Padding(0); + this.starPerform4.Name = "starPerform4"; + this.starPerform4.Size = new System.Drawing.Size(9, 10); + this.starPerform4.TabIndex = 2; + this.starPerform4.Text = "☆"; + this.starPerform4.UseCompatibleTextRendering = true; + this.starPerform4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starPerform4.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starPerform4.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starPerform5 + // + this.starPerform5.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starPerform5.Location = new System.Drawing.Point(36, 0); + this.starPerform5.Margin = new System.Windows.Forms.Padding(0); + this.starPerform5.Name = "starPerform5"; + this.starPerform5.Size = new System.Drawing.Size(9, 10); + this.starPerform5.TabIndex = 4; + this.starPerform5.Text = "☆"; + this.starPerform5.UseCompatibleTextRendering = true; + this.starPerform5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starPerform5.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starPerform5.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // panelStory + // + this.panelStory.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.panelStory.Controls.Add(this.starStory1); + this.panelStory.Controls.Add(this.starStory2); + this.panelStory.Controls.Add(this.starStory3); + this.panelStory.Controls.Add(this.starStory4); + this.panelStory.Controls.Add(this.starStory5); + this.panelStory.Location = new System.Drawing.Point(55, 33); + this.panelStory.Name = "panelStory"; + this.panelStory.Size = new System.Drawing.Size(45, 10); + this.panelStory.TabIndex = 9; + // + // starStory1 + // + this.starStory1.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starStory1.Location = new System.Drawing.Point(0, 0); + this.starStory1.Margin = new System.Windows.Forms.Padding(0); + this.starStory1.Name = "starStory1"; + this.starStory1.Size = new System.Drawing.Size(9, 10); + this.starStory1.TabIndex = 0; + this.starStory1.Text = "☆"; + this.starStory1.UseCompatibleTextRendering = true; + this.starStory1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starStory1.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starStory1.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starStory2 + // + this.starStory2.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starStory2.Location = new System.Drawing.Point(9, 0); + this.starStory2.Margin = new System.Windows.Forms.Padding(0); + this.starStory2.Name = "starStory2"; + this.starStory2.Size = new System.Drawing.Size(9, 10); + this.starStory2.TabIndex = 1; + this.starStory2.Text = "☆"; + this.starStory2.UseCompatibleTextRendering = true; + this.starStory2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starStory2.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starStory2.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starStory3 + // + this.starStory3.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starStory3.Location = new System.Drawing.Point(18, 0); + this.starStory3.Margin = new System.Windows.Forms.Padding(0); + this.starStory3.Name = "starStory3"; + this.starStory3.Size = new System.Drawing.Size(9, 10); + this.starStory3.TabIndex = 3; + this.starStory3.Text = "☆"; + this.starStory3.UseCompatibleTextRendering = true; + this.starStory3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starStory3.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starStory3.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starStory4 + // + this.starStory4.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starStory4.Location = new System.Drawing.Point(27, 0); + this.starStory4.Margin = new System.Windows.Forms.Padding(0); + this.starStory4.Name = "starStory4"; + this.starStory4.Size = new System.Drawing.Size(9, 10); + this.starStory4.TabIndex = 2; + this.starStory4.Text = "☆"; + this.starStory4.UseCompatibleTextRendering = true; + this.starStory4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starStory4.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starStory4.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // starStory5 + // + this.starStory5.Font = new System.Drawing.Font("Segoe UI", 6.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + this.starStory5.Location = new System.Drawing.Point(36, 0); + this.starStory5.Margin = new System.Windows.Forms.Padding(0); + this.starStory5.Name = "starStory5"; + this.starStory5.Size = new System.Drawing.Size(9, 10); + this.starStory5.TabIndex = 4; + this.starStory5.Text = "☆"; + this.starStory5.UseCompatibleTextRendering = true; + this.starStory5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); + this.starStory5.MouseEnter += new System.EventHandler(this.Star_MouseEnter); + this.starStory5.MouseLeave += new System.EventHandler(this.Star_MouseLeave); + // + // MyRatingCellEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lblStory); + this.Controls.Add(this.panelStory); + this.Controls.Add(this.lblPerform); + this.Controls.Add(this.panelPerform); + this.Controls.Add(this.lblOverall); + this.Controls.Add(this.panelOverall); + this.Name = "MyRatingCellEditor"; + this.Size = new System.Drawing.Size(108, 45); + this.panelOverall.ResumeLayout(false); + this.panelPerform.ResumeLayout(false); + this.panelStory.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label starOverall1; + private System.Windows.Forms.Label starOverall2; + private System.Windows.Forms.Label starOverall3; + private System.Windows.Forms.Label starOverall4; + private System.Windows.Forms.Label starOverall5; + private System.Windows.Forms.Panel panelOverall; + private System.Windows.Forms.Label lblOverall; + private System.Windows.Forms.Label lblPerform; + private System.Windows.Forms.Panel panelPerform; + private System.Windows.Forms.Label starPerform1; + private System.Windows.Forms.Label starPerform2; + private System.Windows.Forms.Label starPerform3; + private System.Windows.Forms.Label starPerform4; + private System.Windows.Forms.Label starPerform5; + private System.Windows.Forms.Label lblStory; + private System.Windows.Forms.Panel panelStory; + private System.Windows.Forms.Label starStory1; + private System.Windows.Forms.Label starStory2; + private System.Windows.Forms.Label starStory3; + private System.Windows.Forms.Label starStory4; + private System.Windows.Forms.Label starStory5; + } +} diff --git a/Source/LibationWinForms/GridView/RatingPicker.cs b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs similarity index 77% rename from Source/LibationWinForms/GridView/RatingPicker.cs rename to Source/LibationWinForms/GridView/MyRatingCellEditor.cs index 94478dec..53e5623e 100644 --- a/Source/LibationWinForms/GridView/RatingPicker.cs +++ b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs @@ -1,18 +1,12 @@ using DataLayer; -using Mpeg4Lib.Boxes; using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; using System.Drawing; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; namespace LibationWinForms.GridView { - public partial class RatingPicker : UserControl, IDataGridViewEditingControl + public partial class MyRatingCellEditor : UserControl, IDataGridViewEditingControl { private const string SOLID_STAR = "★"; private const string HOLLOW_STAR = "☆"; @@ -24,21 +18,22 @@ namespace LibationWinForms.GridView { _rating = value; int rating = 0; - foreach (Label star in panel1.Controls) + foreach (Label star in panelOverall.Controls) star.Tag = star.Text = _rating.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR; rating = 0; - foreach (Label star in panel2.Controls) + foreach (Label star in panelPerform.Controls) star.Tag = star.Text = _rating.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR; rating = 0; - foreach (Label star in panel3.Controls) + foreach (Label star in panelStory.Controls) star.Tag = star.Text = _rating.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR; } } - public RatingPicker() + public MyRatingCellEditor() { InitializeComponent(); + this.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Bottom; } private void Star_MouseEnter(object sender, EventArgs e) @@ -79,46 +74,48 @@ namespace LibationWinForms.GridView var thisTbox = sender as Label; var panel = thisTbox.Parent as Panel; - int newRating = 0; + int newRatingValue = 0; foreach (var child in panel.Controls) { - newRating++; + newRatingValue++; if (child == thisTbox) break; } - if (panel == panel1) - overall = newRating; - else if (panel == panel2) - perform = newRating; - else if (panel == panel3) - story = newRating; + if (panel == panelOverall) + overall = newRatingValue; + else if (panel == panelPerform) + perform = newRatingValue; + else if (panel == panelStory) + story = newRatingValue; if (overall + perform + story == 0f) return; - Rating = new Rating(overall, perform, story); + var newRating = new Rating(overall, perform, story); + + if (newRating == Rating) return; + EditingControlValueChanged = true; EditingControlDataGridView.NotifyCurrentCellDirty(true); } + #region IDataGridViewEditingControl + DataGridView dataGridView; private bool valueChanged = false; int rowIndex; - #region IDataGridViewEditingControl public DataGridView EditingControlDataGridView { get => dataGridView; set => dataGridView = value; } - public object EditingControlFormattedValue { get => Rating.ToStarString(); set { } } public int EditingControlRowIndex { get => rowIndex; set => rowIndex = value; } public bool EditingControlValueChanged { get => valueChanged; set => valueChanged = value; } - + public object EditingControlFormattedValue { get => Rating; set => Rating = (Rating)value; } public Cursor EditingPanelCursor => base.Cursor; - public bool RepositionEditingControlOnValueChange => false; public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) { - this.Font = dataGridViewCellStyle.Font; - this.ForeColor = dataGridViewCellStyle.ForeColor; - this.BackColor = dataGridViewCellStyle.BackColor; + Font = dataGridViewCellStyle.Font; + ForeColor = dataGridViewCellStyle.ForeColor; + BackColor = dataGridViewCellStyle.BackColor; } public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) diff --git a/Source/LibationWinForms/GridView/RatingPicker.resx b/Source/LibationWinForms/GridView/MyRatingCellEditor.resx similarity index 100% rename from Source/LibationWinForms/GridView/RatingPicker.resx rename to Source/LibationWinForms/GridView/MyRatingCellEditor.resx diff --git a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs index fdab268e..ea174443 100644 --- a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs +++ b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs @@ -1,6 +1,7 @@ using DataLayer; using System; using System.ComponentModel; +using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -16,7 +17,7 @@ namespace LibationWinForms.GridView set { if (value is not MyRatingGridViewCell) - throw new InvalidCastException("Must be a MyRatingGridViewCell"); + throw new InvalidCastException($"Must be a {nameof(MyRatingGridViewCell)}"); base.CellTemplate = value; } @@ -25,49 +26,32 @@ namespace LibationWinForms.GridView internal class MyRatingGridViewCell : DataGridViewTextBoxCell { + private Rating DefaultRating => new Rating(0, 0, 0); + public override object DefaultNewRowValue => DefaultRating; + public override Type EditType => typeof(MyRatingCellEditor); + public override Type ValueType => typeof(Rating); + public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) { base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); - var ctl = DataGridView.EditingControl as RatingPicker; + var ctl = DataGridView.EditingControl as MyRatingCellEditor; - ctl.Rating = - Value is Rating rating - ? rating - : (Rating)DefaultNewRowValue; + ctl.Rating = Value is Rating rating ? rating : DefaultRating; + } + + protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) + { + if (value is Rating rating) + { + var starString = rating.ToStarString(); + base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, starString, starString, errorText, cellStyle, advancedBorderStyle, paintParts); + } + else + base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); } public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter) - { - const char SOLID_STAR = '★'; - if (formattedValue is string s) - { - int overall = 0, performance = 0, story = 0; - - foreach (var line in s.Split('\n')) - { - if (line.Contains("Overall")) - overall = line.Count(c => c == SOLID_STAR); - else if (line.Contains("Perform")) - performance = line.Count(c => c == SOLID_STAR); - else if (line.Contains("Story")) - story = line.Count(c => c == SOLID_STAR); - } - - return new Rating(overall, performance, story); - } - else - return DefaultNewRowValue; - } - - - protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) - => value is Rating rating - ? rating.ToStarString() - : base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context); - - public override Type EditType => typeof(RatingPicker); - public override object DefaultNewRowValue => new Rating(0, 0, 0); - public override Type ValueType => typeof(Rating); + => formattedValue; } } diff --git a/Source/LibationWinForms/GridView/RatingPicker.Designer.cs b/Source/LibationWinForms/GridView/RatingPicker.Designer.cs deleted file mode 100644 index d6705129..00000000 --- a/Source/LibationWinForms/GridView/RatingPicker.Designer.cs +++ /dev/null @@ -1,348 +0,0 @@ -namespace LibationWinForms.GridView -{ - partial class RatingPicker - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.panel1 = new System.Windows.Forms.Panel(); - this.label6 = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.panel2 = new System.Windows.Forms.Panel(); - this.label8 = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); - this.label11 = new System.Windows.Forms.Label(); - this.label12 = new System.Windows.Forms.Label(); - this.label13 = new System.Windows.Forms.Label(); - this.panel3 = new System.Windows.Forms.Panel(); - this.label14 = new System.Windows.Forms.Label(); - this.label15 = new System.Windows.Forms.Label(); - this.label16 = new System.Windows.Forms.Label(); - this.label17 = new System.Windows.Forms.Label(); - this.label18 = new System.Windows.Forms.Label(); - this.panel1.SuspendLayout(); - this.panel2.SuspendLayout(); - this.panel3.SuspendLayout(); - this.SuspendLayout(); - // - // label1 - // - this.label1.Location = new System.Drawing.Point(0, 0); - this.label1.Margin = new System.Windows.Forms.Padding(0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(12, 15); - this.label1.TabIndex = 0; - this.label1.Text = "☆"; - this.label1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label1.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label1.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label2 - // - this.label2.Location = new System.Drawing.Point(12, 0); - this.label2.Margin = new System.Windows.Forms.Padding(0); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(12, 15); - this.label2.TabIndex = 1; - this.label2.Text = "☆"; - this.label2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label2.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label2.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label3 - // - this.label3.Location = new System.Drawing.Point(24, 0); - this.label3.Margin = new System.Windows.Forms.Padding(0); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(12, 15); - this.label3.TabIndex = 3; - this.label3.Text = "☆"; - this.label3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label3.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label3.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label4 - // - this.label4.Location = new System.Drawing.Point(36, 0); - this.label4.Margin = new System.Windows.Forms.Padding(0); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(12, 15); - this.label4.TabIndex = 2; - this.label4.Text = "☆"; - this.label4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label4.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label4.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label5 - // - this.label5.Location = new System.Drawing.Point(48, 0); - this.label5.Margin = new System.Windows.Forms.Padding(0); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(12, 15); - this.label5.TabIndex = 4; - this.label5.Text = "☆"; - this.label5.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label5.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label5.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // panel1 - // - this.panel1.Controls.Add(this.label1); - this.panel1.Controls.Add(this.label2); - this.panel1.Controls.Add(this.label3); - this.panel1.Controls.Add(this.label4); - this.panel1.Controls.Add(this.label5); - this.panel1.Location = new System.Drawing.Point(45, 13); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(60, 15); - this.panel1.TabIndex = 5; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(0, 13); - this.label6.Margin = new System.Windows.Forms.Padding(0); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(47, 15); - this.label6.TabIndex = 6; - this.label6.Text = "Overall:"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); - this.label7.Location = new System.Drawing.Point(0, 32); - this.label7.Margin = new System.Windows.Forms.Padding(0); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(46, 15); - this.label7.TabIndex = 8; - this.label7.Text = "Perfrm:"; - // - // panel2 - // - this.panel2.Controls.Add(this.label8); - this.panel2.Controls.Add(this.label9); - this.panel2.Controls.Add(this.label10); - this.panel2.Controls.Add(this.label11); - this.panel2.Controls.Add(this.label12); - this.panel2.Location = new System.Drawing.Point(45, 32); - this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(60, 15); - this.panel2.TabIndex = 7; - // - // label8 - // - this.label8.Location = new System.Drawing.Point(0, 0); - this.label8.Margin = new System.Windows.Forms.Padding(0); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(12, 15); - this.label8.TabIndex = 0; - this.label8.Text = "☆"; - this.label8.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label8.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label8.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label9 - // - this.label9.Location = new System.Drawing.Point(12, 0); - this.label9.Margin = new System.Windows.Forms.Padding(0); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(12, 15); - this.label9.TabIndex = 1; - this.label9.Text = "☆"; - this.label9.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label9.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label9.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label10 - // - this.label10.Location = new System.Drawing.Point(24, 0); - this.label10.Margin = new System.Windows.Forms.Padding(0); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(12, 15); - this.label10.TabIndex = 3; - this.label10.Text = "☆"; - this.label10.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label10.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label10.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label11 - // - this.label11.Location = new System.Drawing.Point(36, 0); - this.label11.Margin = new System.Windows.Forms.Padding(0); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(12, 15); - this.label11.TabIndex = 2; - this.label11.Text = "☆"; - this.label11.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label11.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label11.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label12 - // - this.label12.Location = new System.Drawing.Point(48, 0); - this.label12.Margin = new System.Windows.Forms.Padding(0); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(12, 15); - this.label12.TabIndex = 4; - this.label12.Text = "☆"; - this.label12.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label12.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label12.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label13 - // - this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(0, 51); - this.label13.Margin = new System.Windows.Forms.Padding(0); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(37, 15); - this.label13.TabIndex = 10; - this.label13.Text = "Story:"; - // - // panel3 - // - this.panel3.Controls.Add(this.label14); - this.panel3.Controls.Add(this.label15); - this.panel3.Controls.Add(this.label16); - this.panel3.Controls.Add(this.label17); - this.panel3.Controls.Add(this.label18); - this.panel3.Location = new System.Drawing.Point(45, 51); - this.panel3.Name = "panel3"; - this.panel3.Size = new System.Drawing.Size(60, 15); - this.panel3.TabIndex = 9; - // - // label14 - // - this.label14.Location = new System.Drawing.Point(0, 0); - this.label14.Margin = new System.Windows.Forms.Padding(0); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(12, 15); - this.label14.TabIndex = 0; - this.label14.Text = "☆"; - this.label14.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label14.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label14.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label15 - // - this.label15.Location = new System.Drawing.Point(12, 0); - this.label15.Margin = new System.Windows.Forms.Padding(0); - this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(12, 15); - this.label15.TabIndex = 1; - this.label15.Text = "☆"; - this.label15.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label15.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label15.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label16 - // - this.label16.Location = new System.Drawing.Point(24, 0); - this.label16.Margin = new System.Windows.Forms.Padding(0); - this.label16.Name = "label16"; - this.label16.Size = new System.Drawing.Size(12, 15); - this.label16.TabIndex = 3; - this.label16.Text = "☆"; - this.label16.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label16.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label16.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label17 - // - this.label17.Location = new System.Drawing.Point(36, 0); - this.label17.Margin = new System.Windows.Forms.Padding(0); - this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(12, 15); - this.label17.TabIndex = 2; - this.label17.Text = "☆"; - this.label17.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label17.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label17.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // label18 - // - this.label18.Location = new System.Drawing.Point(48, 0); - this.label18.Margin = new System.Windows.Forms.Padding(0); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(12, 15); - this.label18.TabIndex = 4; - this.label18.Text = "☆"; - this.label18.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Star_MouseClick); - this.label18.MouseEnter += new System.EventHandler(this.Star_MouseEnter); - this.label18.MouseLeave += new System.EventHandler(this.Star_MouseLeave); - // - // RatingPicker - // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.label13); - this.Controls.Add(this.panel3); - this.Controls.Add(this.label7); - this.Controls.Add(this.panel2); - this.Controls.Add(this.label6); - this.Controls.Add(this.panel1); - this.Name = "RatingPicker"; - this.Size = new System.Drawing.Size(108, 80); - this.panel1.ResumeLayout(false); - this.panel2.ResumeLayout(false); - this.panel3.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Panel panel1; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Panel panel2; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.Label label11; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.Panel panel3; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.Label label15; - private System.Windows.Forms.Label label16; - private System.Windows.Forms.Label label17; - private System.Windows.Forms.Label label18; - } -} diff --git a/Source/LibationWinForms/GridView/SeriesEntry.cs b/Source/LibationWinForms/GridView/SeriesEntry.cs index 53191808..f8d004f9 100644 --- a/Source/LibationWinForms/GridView/SeriesEntry.cs +++ b/Source/LibationWinForms/GridView/SeriesEntry.cs @@ -89,7 +89,7 @@ namespace LibationWinForms.GridView Title = Book.Title; Series = Book.SeriesNames(); - MyRating = Book.UserDefinedItem.Rating; + _myRating = Book.UserDefinedItem.Rating; PurchaseDate = Children.Min(c => c.LibraryBook.DateAdded).ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); From c9497ef39ed38c4711ed816ef56d72789556f800 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 30 Dec 2022 19:44:16 -0700 Subject: [PATCH 03/14] Make my rating column sortable --- .../GridView/MyRatingCellEditor.cs | 1 + .../GridView/ProductsGrid.Designer.cs | 404 +++++++++--------- 2 files changed, 203 insertions(+), 202 deletions(-) diff --git a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs index 53e5623e..7691b32e 100644 --- a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs +++ b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs @@ -94,6 +94,7 @@ namespace LibationWinForms.GridView if (newRating == Rating) return; + Rating = newRating; EditingControlValueChanged = true; EditingControlDataGridView.NotifyCurrentCellDirty(true); } diff --git a/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs b/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs index 8aa2b188..13a40e7f 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.Designer.cs @@ -28,39 +28,39 @@ /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); - this.gridEntryDataGridView = new System.Windows.Forms.DataGridView(); - this.removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn(); - this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn(); - this.coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn(); - this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.productRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.myRatingGVColumn = new MyRatingGridViewColumn(); - this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn(); - this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); - this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components); - ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit(); - this.SuspendLayout(); - // - // gridEntryDataGridView - // - this.gridEntryDataGridView.AllowUserToAddRows = false; - this.gridEntryDataGridView.AllowUserToDeleteRows = false; - this.gridEntryDataGridView.AllowUserToOrderColumns = true; - this.gridEntryDataGridView.AllowUserToResizeRows = false; - this.gridEntryDataGridView.AutoGenerateColumns = false; - this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + this.gridEntryDataGridView = new System.Windows.Forms.DataGridView(); + this.showHideColumnsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.syncBindingSource = new LibationWinForms.GridView.SyncBindingSource(this.components); + this.removeGVColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn(); + this.liberateGVColumn = new LibationWinForms.GridView.LiberateDataGridViewImageButtonColumn(); + this.coverGVColumn = new System.Windows.Forms.DataGridViewImageColumn(); + this.titleGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.authorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.narratorsGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.lengthGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.seriesGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.descriptionGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.categoryGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.productRatingGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.purchaseDateGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.myRatingGVColumn = new LibationWinForms.GridView.MyRatingGridViewColumn(); + this.miscGVColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.tagAndDetailsGVColumn = new LibationWinForms.GridView.EditTagsDataGridViewImageButtonColumn(); + ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).BeginInit(); + this.SuspendLayout(); + // + // gridEntryDataGridView + // + this.gridEntryDataGridView.AllowUserToAddRows = false; + this.gridEntryDataGridView.AllowUserToDeleteRows = false; + this.gridEntryDataGridView.AllowUserToOrderColumns = true; + this.gridEntryDataGridView.AllowUserToResizeRows = false; + this.gridEntryDataGridView.AutoGenerateColumns = false; + this.gridEntryDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.gridEntryDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.removeGVColumn, this.liberateGVColumn, this.coverGVColumn, @@ -76,175 +76,175 @@ this.myRatingGVColumn, this.miscGVColumn, this.tagAndDetailsGVColumn}); - this.gridEntryDataGridView.ContextMenuStrip = this.showHideColumnsContextMenuStrip; - this.gridEntryDataGridView.DataSource = this.syncBindingSource; - dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); - dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight; - dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; - this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1; - this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill; - this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0); - this.gridEntryDataGridView.Name = "gridEntryDataGridView"; - this.gridEntryDataGridView.RowHeadersVisible = false; - this.gridEntryDataGridView.RowTemplate.Height = 82; - this.gridEntryDataGridView.Size = new System.Drawing.Size(1570, 380); - this.gridEntryDataGridView.TabIndex = 0; - this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick); - this.gridEntryDataGridView.CellContextMenuStripNeeded += new System.Windows.Forms.DataGridViewCellContextMenuStripNeededEventHandler(this.gridEntryDataGridView_CellContextMenuStripNeeded); - this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded); - // - // removeGVColumn - // - this.removeGVColumn.DataPropertyName = "Remove"; - this.removeGVColumn.FalseValue = ""; - this.removeGVColumn.Frozen = true; - this.removeGVColumn.HeaderText = "Remove"; - this.removeGVColumn.IndeterminateValue = ""; - this.removeGVColumn.MinimumWidth = 60; - this.removeGVColumn.Name = "removeGVColumn"; - this.removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - this.removeGVColumn.ThreeState = true; - this.removeGVColumn.TrueValue = ""; - this.removeGVColumn.Width = 60; - // - // liberateGVColumn - // - this.liberateGVColumn.DataPropertyName = "Liberate"; - this.liberateGVColumn.HeaderText = "Liberate"; - this.liberateGVColumn.Name = "liberateGVColumn"; - this.liberateGVColumn.ReadOnly = true; - this.liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - this.liberateGVColumn.Width = 75; - // - // coverGVColumn - // - this.coverGVColumn.DataPropertyName = "Cover"; - this.coverGVColumn.HeaderText = "Cover"; - this.coverGVColumn.Name = "coverGVColumn"; - this.coverGVColumn.ReadOnly = true; - this.coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.coverGVColumn.ToolTipText = "Cover Art"; - this.coverGVColumn.Width = 80; - // - // titleGVColumn - // - this.titleGVColumn.DataPropertyName = "Title"; - this.titleGVColumn.HeaderText = "Title"; - this.titleGVColumn.Name = "titleGVColumn"; - this.titleGVColumn.ReadOnly = true; - this.titleGVColumn.Width = 200; - // - // authorsGVColumn - // - this.authorsGVColumn.DataPropertyName = "Authors"; - this.authorsGVColumn.HeaderText = "Authors"; - this.authorsGVColumn.Name = "authorsGVColumn"; - this.authorsGVColumn.ReadOnly = true; - // - // narratorsGVColumn - // - this.narratorsGVColumn.DataPropertyName = "Narrators"; - this.narratorsGVColumn.HeaderText = "Narrators"; - this.narratorsGVColumn.Name = "narratorsGVColumn"; - this.narratorsGVColumn.ReadOnly = true; - // - // lengthGVColumn - // - this.lengthGVColumn.DataPropertyName = "Length"; - this.lengthGVColumn.HeaderText = "Length"; - this.lengthGVColumn.Name = "lengthGVColumn"; - this.lengthGVColumn.ReadOnly = true; - this.lengthGVColumn.ToolTipText = "Recording Length"; - // - // seriesGVColumn - // - this.seriesGVColumn.DataPropertyName = "Series"; - this.seriesGVColumn.HeaderText = "Series"; - this.seriesGVColumn.Name = "seriesGVColumn"; - this.seriesGVColumn.ReadOnly = true; - // - // descriptionGVColumn - // - this.descriptionGVColumn.DataPropertyName = "Description"; - this.descriptionGVColumn.HeaderText = "Description"; - this.descriptionGVColumn.Name = "descriptionGVColumn"; - this.descriptionGVColumn.ReadOnly = true; - this.descriptionGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - // - // categoryGVColumn - // - this.categoryGVColumn.DataPropertyName = "Category"; - this.categoryGVColumn.HeaderText = "Category"; - this.categoryGVColumn.Name = "categoryGVColumn"; - this.categoryGVColumn.ReadOnly = true; - // - // productRatingGVColumn - // - this.productRatingGVColumn.DataPropertyName = "ProductRating"; - this.productRatingGVColumn.HeaderText = "Product Rating"; - this.productRatingGVColumn.Name = "productRatingGVColumn"; - this.productRatingGVColumn.ReadOnly = true; - this.productRatingGVColumn.Width = 108; - // - // purchaseDateGVColumn - // - this.purchaseDateGVColumn.DataPropertyName = "PurchaseDate"; - this.purchaseDateGVColumn.HeaderText = "Purchase Date"; - this.purchaseDateGVColumn.Name = "purchaseDateGVColumn"; - this.purchaseDateGVColumn.ReadOnly = true; - // - // myRatingGVColumn - // - this.myRatingGVColumn.DataPropertyName = "MyRating"; - this.myRatingGVColumn.HeaderText = "My Rating"; - this.myRatingGVColumn.Name = "myRatingGVColumn"; - this.myRatingGVColumn.ReadOnly = false; - this.myRatingGVColumn.Width = 108; - // - // miscGVColumn - // - this.miscGVColumn.DataPropertyName = "Misc"; - this.miscGVColumn.HeaderText = "Misc"; - this.miscGVColumn.Name = "miscGVColumn"; - this.miscGVColumn.ReadOnly = true; - this.miscGVColumn.Width = 135; - // - // tagAndDetailsGVColumn - // - this.tagAndDetailsGVColumn.DataPropertyName = "DisplayTags"; - this.tagAndDetailsGVColumn.HeaderText = "Tags and Details"; - this.tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn"; - this.tagAndDetailsGVColumn.ReadOnly = true; - this.tagAndDetailsGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; - this.tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - // - // showHideColumnsContextMenuStrip - // - this.showHideColumnsContextMenuStrip.Name = "contextMenuStrip1"; - this.showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(181, 26); - // - // syncBindingSource - // - this.syncBindingSource.DataSource = typeof(LibationWinForms.GridView.GridEntry); - // - // ProductsGrid - // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoScroll = true; - this.Controls.Add(this.gridEntryDataGridView); - this.Name = "ProductsGrid"; - this.Size = new System.Drawing.Size(1570, 380); - this.Load += new System.EventHandler(this.ProductsGrid_Load); - ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit(); - this.ResumeLayout(false); + this.gridEntryDataGridView.ContextMenuStrip = this.showHideColumnsContextMenuStrip; + this.gridEntryDataGridView.DataSource = this.syncBindingSource; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); + dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True; + this.gridEntryDataGridView.DefaultCellStyle = dataGridViewCellStyle1; + this.gridEntryDataGridView.Dock = System.Windows.Forms.DockStyle.Fill; + this.gridEntryDataGridView.Location = new System.Drawing.Point(0, 0); + this.gridEntryDataGridView.Name = "gridEntryDataGridView"; + this.gridEntryDataGridView.RowHeadersVisible = false; + this.gridEntryDataGridView.RowTemplate.Height = 82; + this.gridEntryDataGridView.Size = new System.Drawing.Size(1570, 380); + this.gridEntryDataGridView.TabIndex = 0; + this.gridEntryDataGridView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView_CellContentClick); + this.gridEntryDataGridView.CellContextMenuStripNeeded += new System.Windows.Forms.DataGridViewCellContextMenuStripNeededEventHandler(this.gridEntryDataGridView_CellContextMenuStripNeeded); + this.gridEntryDataGridView.CellToolTipTextNeeded += new System.Windows.Forms.DataGridViewCellToolTipTextNeededEventHandler(this.gridEntryDataGridView_CellToolTipTextNeeded); + // + // showHideColumnsContextMenuStrip + // + this.showHideColumnsContextMenuStrip.Name = "contextMenuStrip1"; + this.showHideColumnsContextMenuStrip.Size = new System.Drawing.Size(61, 4); + // + // syncBindingSource + // + this.syncBindingSource.DataSource = typeof(LibationWinForms.GridView.GridEntry); + // + // removeGVColumn + // + this.removeGVColumn.DataPropertyName = "Remove"; + this.removeGVColumn.FalseValue = ""; + this.removeGVColumn.Frozen = true; + this.removeGVColumn.HeaderText = "Remove"; + this.removeGVColumn.IndeterminateValue = ""; + this.removeGVColumn.MinimumWidth = 60; + this.removeGVColumn.Name = "removeGVColumn"; + this.removeGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.removeGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + this.removeGVColumn.ThreeState = true; + this.removeGVColumn.TrueValue = ""; + this.removeGVColumn.Width = 60; + // + // liberateGVColumn + // + this.liberateGVColumn.DataPropertyName = "Liberate"; + this.liberateGVColumn.HeaderText = "Liberate"; + this.liberateGVColumn.Name = "liberateGVColumn"; + this.liberateGVColumn.ReadOnly = true; + this.liberateGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.liberateGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + this.liberateGVColumn.Width = 75; + // + // coverGVColumn + // + this.coverGVColumn.DataPropertyName = "Cover"; + this.coverGVColumn.HeaderText = "Cover"; + this.coverGVColumn.Name = "coverGVColumn"; + this.coverGVColumn.ReadOnly = true; + this.coverGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.coverGVColumn.ToolTipText = "Cover Art"; + this.coverGVColumn.Width = 80; + // + // titleGVColumn + // + this.titleGVColumn.DataPropertyName = "Title"; + this.titleGVColumn.HeaderText = "Title"; + this.titleGVColumn.Name = "titleGVColumn"; + this.titleGVColumn.ReadOnly = true; + this.titleGVColumn.Width = 200; + // + // authorsGVColumn + // + this.authorsGVColumn.DataPropertyName = "Authors"; + this.authorsGVColumn.HeaderText = "Authors"; + this.authorsGVColumn.Name = "authorsGVColumn"; + this.authorsGVColumn.ReadOnly = true; + // + // narratorsGVColumn + // + this.narratorsGVColumn.DataPropertyName = "Narrators"; + this.narratorsGVColumn.HeaderText = "Narrators"; + this.narratorsGVColumn.Name = "narratorsGVColumn"; + this.narratorsGVColumn.ReadOnly = true; + // + // lengthGVColumn + // + this.lengthGVColumn.DataPropertyName = "Length"; + this.lengthGVColumn.HeaderText = "Length"; + this.lengthGVColumn.Name = "lengthGVColumn"; + this.lengthGVColumn.ReadOnly = true; + this.lengthGVColumn.ToolTipText = "Recording Length"; + // + // seriesGVColumn + // + this.seriesGVColumn.DataPropertyName = "Series"; + this.seriesGVColumn.HeaderText = "Series"; + this.seriesGVColumn.Name = "seriesGVColumn"; + this.seriesGVColumn.ReadOnly = true; + // + // descriptionGVColumn + // + this.descriptionGVColumn.DataPropertyName = "Description"; + this.descriptionGVColumn.HeaderText = "Description"; + this.descriptionGVColumn.Name = "descriptionGVColumn"; + this.descriptionGVColumn.ReadOnly = true; + this.descriptionGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + // + // categoryGVColumn + // + this.categoryGVColumn.DataPropertyName = "Category"; + this.categoryGVColumn.HeaderText = "Category"; + this.categoryGVColumn.Name = "categoryGVColumn"; + this.categoryGVColumn.ReadOnly = true; + // + // productRatingGVColumn + // + this.productRatingGVColumn.DataPropertyName = "ProductRating"; + this.productRatingGVColumn.HeaderText = "Product Rating"; + this.productRatingGVColumn.Name = "productRatingGVColumn"; + this.productRatingGVColumn.ReadOnly = true; + this.productRatingGVColumn.Width = 108; + // + // purchaseDateGVColumn + // + this.purchaseDateGVColumn.DataPropertyName = "PurchaseDate"; + this.purchaseDateGVColumn.HeaderText = "Purchase Date"; + this.purchaseDateGVColumn.Name = "purchaseDateGVColumn"; + this.purchaseDateGVColumn.ReadOnly = true; + // + // myRatingGVColumn + // + this.myRatingGVColumn.DataPropertyName = "MyRating"; + this.myRatingGVColumn.HeaderText = "My Rating"; + this.myRatingGVColumn.Name = "myRatingGVColumn"; + this.myRatingGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + this.myRatingGVColumn.Width = 108; + // + // miscGVColumn + // + this.miscGVColumn.DataPropertyName = "Misc"; + this.miscGVColumn.HeaderText = "Misc"; + this.miscGVColumn.Name = "miscGVColumn"; + this.miscGVColumn.ReadOnly = true; + this.miscGVColumn.Width = 135; + // + // tagAndDetailsGVColumn + // + this.tagAndDetailsGVColumn.DataPropertyName = "DisplayTags"; + this.tagAndDetailsGVColumn.HeaderText = "Tags and Details"; + this.tagAndDetailsGVColumn.Name = "tagAndDetailsGVColumn"; + this.tagAndDetailsGVColumn.ReadOnly = true; + this.tagAndDetailsGVColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.tagAndDetailsGVColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + // + // ProductsGrid + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.Controls.Add(this.gridEntryDataGridView); + this.Name = "ProductsGrid"; + this.Size = new System.Drawing.Size(1570, 380); + this.Load += new System.EventHandler(this.ProductsGrid_Load); + ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.syncBindingSource)).EndInit(); + this.ResumeLayout(false); } From 874bf9e7c0b635a57c523ecfa6ab77469830be7c Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 10:02:30 -0700 Subject: [PATCH 04/14] Improve classic and chardonnay rating editor simmilarity --- Source/ApplicationServices/LibraryCommands.cs | 4 +- Source/DataLayer/EfClasses/UserDefinedItem.cs | 4 +- ...tingBox.axaml => MyRatingCellEditor.axaml} | 58 ++++---- .../Controls/MyRatingCellEditor.axaml.cs | 108 +++++++++++++++ .../Controls/MyRatingGridColumn.axaml | 8 ++ .../Controls/MyRatingGridColumn.axaml.cs | 66 +++++++++ .../Controls/RatingBox.axaml.cs | 125 ------------------ .../LibationAvalonia/ViewModels/GridEntry.cs | 2 +- .../ViewModels/LibraryBookEntry.cs | 4 +- .../ViewModels/SeriesEntry.cs | 4 +- .../Views/ProductsDisplay.axaml | 13 +- Source/LibationSearchEngine/SearchEngine.cs | 8 +- .../GridView/MyRatingCellEditor.cs | 4 +- .../GridView/MyRatingGridViewColumn.cs | 3 +- 14 files changed, 233 insertions(+), 178 deletions(-) rename Source/LibationAvalonia/Controls/{RatingBox.axaml => MyRatingCellEditor.axaml} (59%) create mode 100644 Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs create mode 100644 Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml create mode 100644 Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs delete mode 100644 Source/LibationAvalonia/Controls/RatingBox.axaml.cs diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index 8d6f5a05..21123ec5 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -439,7 +439,7 @@ namespace ApplicationServices udi.SetPdfStatus(pdfStatus); if (rating is not null) - udi.Rating = rating; + udi.UpdateRating(rating.OverallRating, rating.PerformanceRating, rating.StoryRating); }); public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus) @@ -497,7 +497,7 @@ namespace ApplicationServices context.Attach(book.UserDefinedItem.Rating).State = Microsoft.EntityFrameworkCore.EntityState.Modified; } - var qtyChanges = context.SaveChanges(); + var qtyChanges = context.SaveChanges(); if (qtyChanges > 0) BookUserDefinedItemCommitted?.Invoke(null, books); diff --git a/Source/DataLayer/EfClasses/UserDefinedItem.cs b/Source/DataLayer/EfClasses/UserDefinedItem.cs index 177eb79b..e97387ae 100644 --- a/Source/DataLayer/EfClasses/UserDefinedItem.cs +++ b/Source/DataLayer/EfClasses/UserDefinedItem.cs @@ -95,9 +95,9 @@ namespace DataLayer #region Rating // owned: not an optional one-to-one /// The user's individual book rating - public Rating Rating { get; set; } = new Rating(0, 0, 0); + public Rating Rating { get; private set; } = new Rating(0, 0, 0); - public void UpdateRating(float overallRating, float performanceRating, float storyRating) + public void UpdateRating(float overallRating, float performanceRating, float storyRating) => Rating.Update(overallRating, performanceRating, storyRating); #endregion diff --git a/Source/LibationAvalonia/Controls/RatingBox.axaml b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml similarity index 59% rename from Source/LibationAvalonia/Controls/RatingBox.axaml rename to Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml index 4f3f6a03..27b2592d 100644 --- a/Source/LibationAvalonia/Controls/RatingBox.axaml +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml @@ -3,49 +3,49 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="LibationAvalonia.Controls.RatingBox"> - + x:Class="LibationAvalonia.Controls.MyRatingCellEditor"> + + - - + + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs new file mode 100644 index 00000000..89a5ec91 --- /dev/null +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs @@ -0,0 +1,108 @@ +using Avalonia; +using Avalonia.Controls; +using DataLayer; +using System.Linq; + +namespace LibationAvalonia.Controls +{ + public partial class MyRatingCellEditor : UserControl + { + private const string SOLID_STAR = "★"; + private const string HOLLOW_STAR = "☆"; + + public static readonly StyledProperty RatingProperty = + AvaloniaProperty.Register(nameof(Rating)); + + public bool AllRatingsVisible { get; set; } + public Rating Rating + { + get { return GetValue(RatingProperty); } + set { SetValue(RatingProperty, value); } + } + public MyRatingCellEditor() + { + InitializeComponent(); + if (Design.IsDesignMode) + Rating = new Rating(5, 4, 3); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + if (change.Property.Name == nameof(Rating) && Rating is not null) + { + int rating = 0; + foreach (TextBlock star in panelOverall.Children) + star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + + rating = 0; + foreach (TextBlock star in panelPerform.Children) + star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + + rating = 0; + foreach (TextBlock star in panelStory.Children) + star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + + SetVisible(AllRatingsVisible); + } + base.OnPropertyChanged(change); + } + + private void SetVisible(bool allVisible) + { + tblockOverall.IsVisible = panelOverall.IsVisible = allVisible || Rating?.OverallRating > 0; + tblockPerform.IsVisible = panelPerform.IsVisible = allVisible || Rating?.PerformanceRating > 0; + tblockStory.IsVisible = panelStory.IsVisible = allVisible || Rating?.StoryRating > 0; + } + + public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) + { + var panel = sender as Panel; + var stackPanel = panel.Children.OfType().Single(); + + //Restore defaults + foreach (TextBlock child in stackPanel.Children) + child.Text = (string)child.Tag; + } + + public void Star_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) + { + var thisTbox = sender as TextBlock; + var stackPanel = thisTbox.Parent as StackPanel; + var star = SOLID_STAR; + + foreach (TextBlock child in stackPanel.Children) + { + child.Text = star; + if (child == thisTbox) star = HOLLOW_STAR; + } + } + + public void Star_Tapped(object sender, Avalonia.Input.TappedEventArgs e) + { + var overall = Rating.OverallRating; + var perform = Rating.PerformanceRating; + var story = Rating.StoryRating; + + var thisTbox = sender as TextBlock; + var stackPanel = thisTbox.Parent as StackPanel; + + int newRatingValue = 0; + foreach (var tbox in stackPanel.Children) + { + newRatingValue++; + if (tbox == thisTbox) break; + } + + if (stackPanel == panelOverall) + overall = newRatingValue; + else if (stackPanel == panelPerform) + perform = newRatingValue; + else if (stackPanel == panelStory) + story = newRatingValue; + + if (overall + perform + story == 0f) return; + + Rating = new Rating(overall, perform, story); + } + } +} diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml new file mode 100644 index 00000000..3c77bb14 --- /dev/null +++ b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml @@ -0,0 +1,8 @@ + + + diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs new file mode 100644 index 00000000..c9e67099 --- /dev/null +++ b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs @@ -0,0 +1,66 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using Avalonia.Media; +using DataLayer; + +namespace LibationAvalonia.Controls +{ + public partial class MyRatingGridColumn : DataGridBoundColumn + { + private static Rating DefaultRating => new Rating(0, 0, 0); + public MyRatingGridColumn() + { + AvaloniaXamlLoader.Load(this); + BindingTarget = MyRatingCellEditor.RatingProperty; + } + + protected override IControl GenerateElement(DataGridCell cell, object dataItem) + { + var myRatingElement = new MyRatingCellEditor + { + Name = "CellMyRatingDisplay", + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, + AllRatingsVisible = false, + Margin = new Thickness(3), + IsEnabled = false + }; + + if (Binding != null) + { + myRatingElement.Bind(BindingTarget, Binding); + } + return myRatingElement; + } + + protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem) + { + var myRatingElement = new MyRatingCellEditor + { + Name = "CellMyRatingCellEditor", + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, + AllRatingsVisible = true, + Margin = new Thickness(3) + }; + + return myRatingElement; + } + + protected override object PrepareCellForEdit(IControl editingElement, RoutedEventArgs editingEventArgs) + => editingElement is MyRatingCellEditor myRating + ? myRating.Rating + : DefaultRating; + + protected override void CancelCellEdit(IControl editingElement, object uneditedValue) + { + if (editingElement is MyRatingCellEditor myRating) + { + var uneditedRating = uneditedValue as Rating; + myRating.Rating = uneditedRating ?? DefaultRating; + } + } + } +} diff --git a/Source/LibationAvalonia/Controls/RatingBox.axaml.cs b/Source/LibationAvalonia/Controls/RatingBox.axaml.cs deleted file mode 100644 index f517ec5c..00000000 --- a/Source/LibationAvalonia/Controls/RatingBox.axaml.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using DataLayer; -using NPOI.POIFS.Storage; -using System.Linq; - -namespace LibationAvalonia.Controls -{ - public partial class RatingBox : UserControl - { - private const string SOLID_STAR = "★"; - private const string HOLLOW_STAR = "☆"; - private static readonly char[] FIVE_STARS = { '★', '★', '★', '★', '★' }; - - public static readonly StyledProperty RatingProperty = - AvaloniaProperty.Register(nameof(Rating)); - - public Rating Rating - { - get { return GetValue(RatingProperty); } - set { SetValue(RatingProperty, value); } - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - if (change.Property.Name == nameof(Rating) && Rating is not null) - { - tblockOverallRating.Text = StarRating((int)Rating.OverallRating); - tblockPerformRating.Text = StarRating((int)Rating.PerformanceRating); - tblockStoryRating.Text = StarRating((int)Rating.StoryRating); - - if (this.IsPointerOver) - RatingBox_PointerEntered(this, null); - else - RatingBox_PointerExited(this, null); - } - base.OnPropertyChanged(change); - } - public RatingBox() - { - InitializeComponent(); - PointerEntered += RatingBox_PointerEntered; - PointerExited += RatingBox_PointerExited; - } - - private void RatingBox_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) - { - tblockOverall.IsVisible = Rating?.OverallRating > 0; - tblockPerform.IsVisible = Rating?.PerformanceRating > 0; - tblockStory.IsVisible = Rating?.StoryRating > 0; - } - - private void RatingBox_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) - { - tblockOverall.IsVisible = true; - tblockPerform.IsVisible = true; - tblockStory.IsVisible = true; - } - - private static string StarRating(int rating) => new string(FIVE_STARS, 0, rating); - public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) - { - var panel = sender as Panel; - var stackPanel = panel.Children.OfType().Single(); - - panel.Children.OfType().Single().IsVisible = true; - stackPanel.IsVisible = false; - - foreach (TextBlock child in stackPanel.Children) - child.Text = HOLLOW_STAR; - } - - public void Panel_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) - { - var panel = sender as Panel; - - panel.Children.OfType().Single().IsVisible = false; - panel.Children.OfType().Single().IsVisible = true; - } - - public void Star_PointerEntered(object sender, Avalonia.Input.PointerEventArgs e) - { - var thisTbox = sender as TextBlock; - var stackPanel = thisTbox.Parent as StackPanel; - - var star = SOLID_STAR; - - foreach (TextBlock child in stackPanel.Children) - { - child.Text = star; - if (child == thisTbox) star = HOLLOW_STAR; - } - } - - public void Star_Tapped(object sender, Avalonia.Input.TappedEventArgs e) - { - var overall = Rating.OverallRating; - var perform = Rating.PerformanceRating; - var story = Rating.StoryRating; - - var thisTbox = sender as TextBlock; - var stackPanel = thisTbox.Parent as StackPanel; - - int newRating = 0; - foreach (var tbox in stackPanel.Children) - { - newRating++; - if (tbox == thisTbox) break; - } - - var ratingName = ((Panel)stackPanel.Parent).Children.OfType().Single().Name; - - if (ratingName == tblockOverallRating.Name) - overall = newRating; - else if (ratingName == tblockPerformRating.Name) - perform = newRating; - else if (ratingName == tblockStoryRating.Name) - story = newRating; - - if (overall + perform + story == 0f) return; - - Rating = new Rating(overall, perform, story); - } - } -} diff --git a/Source/LibationAvalonia/ViewModels/GridEntry.cs b/Source/LibationAvalonia/ViewModels/GridEntry.cs index 71007456..bea4fadb 100644 --- a/Source/LibationAvalonia/ViewModels/GridEntry.cs +++ b/Source/LibationAvalonia/ViewModels/GridEntry.cs @@ -45,7 +45,7 @@ namespace LibationAvalonia.ViewModels public string Misc { get; protected set; } public string Description { get; protected set; } public string ProductRating { get; protected set; } - public string MyRatingString => Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); + public string MyRatingString => MyRating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); protected Rating _myRating; public Rating MyRating { diff --git a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs index a172e87b..c79f4cfd 100644 --- a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs +++ b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs @@ -65,7 +65,9 @@ namespace LibationAvalonia.ViewModels Title = Book.Title; Series = Book.SeriesNames(); Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min"; - _myRating = Book.UserDefinedItem.Rating; + //Ratings are changed using Update(), which is a problem for Avalonia data bindings because + //the reference doesn't change. Clone the rating so that it updates within Avalonia properly. + _myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating); PurchaseDate = libraryBook.DateAdded.ToString("d"); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); diff --git a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs index 67a46db7..c0ca2965 100644 --- a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs +++ b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs @@ -68,7 +68,9 @@ namespace LibationAvalonia.ViewModels Title = Book.Title; Series = Book.SeriesNames(); - _myRating = Book.UserDefinedItem.Rating; + //Ratings are changed using Update(), which is a problem for Avalonia data bindings because + //the reference doesn't change. Clone the rating so that it updates within Avalonia properly. + _myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating); ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames(); Narrators = Book.NarratorNames(); diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index 7175106d..0a86d97f 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -140,7 +140,7 @@ - + @@ -160,16 +160,9 @@ - - - - - - - - - + + diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs index c4537d1f..52404903 100644 --- a/Source/LibationSearchEngine/SearchEngine.cs +++ b/Source/LibationSearchEngine/SearchEngine.cs @@ -90,8 +90,8 @@ namespace LibationSearchEngine ["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), - ["UserRating"] = lb => userRating(lb.Book), - ["MyRating"] = lb => userRating(lb.Book) + ["UserRating"] = lb => userOverallRating(lb.Book), + ["MyRating"] = lb => userOverallRating(lb.Book) } ); @@ -136,7 +136,7 @@ namespace LibationSearchEngine var narrators = lb.Book.Narrators.Select(a => a.Name).ToArray(); return authors.Intersect(narrators).Any(); } - private static string userRating(Book book) => book.UserDefinedItem.Rating.OverallRating.ToLuceneString(); + private static string userOverallRating(Book book) => book.UserDefinedItem.Rating.OverallRating.ToLuceneString(); private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated; private static bool liberatedError(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Error; @@ -300,7 +300,7 @@ namespace LibationSearchEngine // fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY. // ie: must remove old before adding new else will create unwanted duplicates. - var v1 = userRating(book); + var v1 = userOverallRating(book); d.RemoveField("UserRating"); d.AddNotAnalyzed("UserRating", v1); d.RemoveField("MyRating"); diff --git a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs index 7691b32e..6230b0eb 100644 --- a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs +++ b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs @@ -39,10 +39,10 @@ namespace LibationWinForms.GridView private void Star_MouseEnter(object sender, EventArgs e) { var thisTbox = sender as Label; - var stackPanel = thisTbox.Parent as Panel; + var panel = thisTbox.Parent as Panel; var star = SOLID_STAR; - foreach (Label child in stackPanel.Controls) + foreach (Label child in panel.Controls) { child.Text = star; if (child == thisTbox) star = HOLLOW_STAR; diff --git a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs index ea174443..331c6123 100644 --- a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs +++ b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs @@ -26,7 +26,7 @@ namespace LibationWinForms.GridView internal class MyRatingGridViewCell : DataGridViewTextBoxCell { - private Rating DefaultRating => new Rating(0, 0, 0); + private static Rating DefaultRating => new Rating(0, 0, 0); public override object DefaultNewRowValue => DefaultRating; public override Type EditType => typeof(MyRatingCellEditor); public override Type ValueType => typeof(Rating); @@ -45,6 +45,7 @@ namespace LibationWinForms.GridView if (value is Rating rating) { var starString = rating.ToStarString(); + ToolTipText = starString; base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, starString, starString, errorText, cellStyle, advancedBorderStyle, paintParts); } else From 05ac5c63e1751f4470a520a8f128a3e21d11687b Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 10:16:54 -0700 Subject: [PATCH 05/14] Formatting --- Source/ApplicationServices/LibraryCommands.cs | 8 ++-- Source/DataLayer/EfClasses/UserDefinedItem.cs | 2 +- Source/LibationSearchEngine/SearchEngine.cs | 42 +++++++++---------- .../LibationWinForms/GridView/ProductsGrid.cs | 2 - 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index 21123ec5..d67b5332 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -419,7 +419,7 @@ namespace ApplicationServices Rating rating = null) => new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus, rating); - public static int UpdateUserDefinedItem( + public static int UpdateUserDefinedItem( this IEnumerable books, string tags = null, LiberatedStatus? bookStatus = null, @@ -494,10 +494,10 @@ namespace ApplicationServices foreach (var book in books) { context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified; - context.Attach(book.UserDefinedItem.Rating).State = Microsoft.EntityFrameworkCore.EntityState.Modified; - } + context.Attach(book.UserDefinedItem.Rating).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + } - var qtyChanges = context.SaveChanges(); + var qtyChanges = context.SaveChanges(); if (qtyChanges > 0) BookUserDefinedItemCommitted?.Invoke(null, books); diff --git a/Source/DataLayer/EfClasses/UserDefinedItem.cs b/Source/DataLayer/EfClasses/UserDefinedItem.cs index e97387ae..91bf236b 100644 --- a/Source/DataLayer/EfClasses/UserDefinedItem.cs +++ b/Source/DataLayer/EfClasses/UserDefinedItem.cs @@ -97,7 +97,7 @@ namespace DataLayer /// The user's individual book rating public Rating Rating { get; private set; } = new Rating(0, 0, 0); - public void UpdateRating(float overallRating, float performanceRating, float storyRating) + public void UpdateRating(float overallRating, float performanceRating, float storyRating) => Rating.Update(overallRating, performanceRating, storyRating); #endregion diff --git a/Source/LibationSearchEngine/SearchEngine.cs b/Source/LibationSearchEngine/SearchEngine.cs index 52404903..260bf14c 100644 --- a/Source/LibationSearchEngine/SearchEngine.cs +++ b/Source/LibationSearchEngine/SearchEngine.cs @@ -89,9 +89,9 @@ namespace LibationSearchEngine ["Hours"] = lb => (lb.Book.LengthInMinutes / 60).ToLuceneString(), ["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), - ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), - ["UserRating"] = lb => userOverallRating(lb.Book), - ["MyRating"] = lb => userOverallRating(lb.Book) + ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), + ["UserRating"] = lb => userOverallRating(lb.Book), + ["MyRating"] = lb => userOverallRating(lb.Book) } ); @@ -137,7 +137,7 @@ namespace LibationSearchEngine return authors.Intersect(narrators).Any(); } private static string userOverallRating(Book book) => book.UserDefinedItem.Rating.OverallRating.ToLuceneString(); - private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated; + private static bool isLiberated(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Liberated; private static bool liberatedError(Book book) => book.UserDefinedItem.BookStatus == LiberatedStatus.Error; // use these common fields in the "all" default search field @@ -289,25 +289,25 @@ namespace LibationSearchEngine d.AddBool("LiberatedError", v2); }); - public void UpdateUserRatings(Book book) - => updateDocument( - book.AudibleProductId, - d => - { - // - // TODO: better synonym handling. This is too easy to mess up - // + public void UpdateUserRatings(Book book) + => updateDocument( + book.AudibleProductId, + d => + { + // + // TODO: better synonym handling. This is too easy to mess up + // - // fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY. - // ie: must remove old before adding new else will create unwanted duplicates. - var v1 = userOverallRating(book); - d.RemoveField("UserRating"); - d.AddNotAnalyzed("UserRating", v1); - d.RemoveField("MyRating"); - d.AddNotAnalyzed("MyRating", v1); - }); + // fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY. + // ie: must remove old before adding new else will create unwanted duplicates. + var v1 = userOverallRating(book); + d.RemoveField("UserRating"); + d.AddNotAnalyzed("UserRating", v1); + d.RemoveField("MyRating"); + d.AddNotAnalyzed("MyRating", v1); + }); - private static void updateDocument(string productId, Action action) + private static void updateDocument(string productId, Action action) { var productTerm = new Term(_ID_, productId); diff --git a/Source/LibationWinForms/GridView/ProductsGrid.cs b/Source/LibationWinForms/GridView/ProductsGrid.cs index 90093f27..33a4d88d 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.cs @@ -51,8 +51,6 @@ namespace LibationWinForms.GridView propertyInfo.SetValue(gridEntryDataGridView, true, null); } - - #region Button controls private void DataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) { From b4838d364ed9c282ecd9789554dcd854e3376586 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 10:33:18 -0700 Subject: [PATCH 06/14] Only show hollow stars in editing mode --- .../Controls/MyRatingCellEditor.axaml | 2 +- .../Controls/MyRatingCellEditor.axaml.cs | 12 +++++++----- .../Controls/MyRatingGridColumn.axaml.cs | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml index 27b2592d..f15bea8e 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml @@ -15,7 +15,7 @@ - + diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs index 89a5ec91..f0c584ab 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs @@ -13,7 +13,7 @@ namespace LibationAvalonia.Controls public static readonly StyledProperty RatingProperty = AvaloniaProperty.Register(nameof(Rating)); - public bool AllRatingsVisible { get; set; } + public bool IsEditingMode { get; set; } public Rating Rating { get { return GetValue(RatingProperty); } @@ -30,19 +30,21 @@ namespace LibationAvalonia.Controls { if (change.Property.Name == nameof(Rating) && Rating is not null) { + var blankValue = IsEditingMode ? HOLLOW_STAR : string.Empty; + int rating = 0; foreach (TextBlock star in panelOverall.Children) - star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : blankValue; rating = 0; foreach (TextBlock star in panelPerform.Children) - star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : blankValue; rating = 0; foreach (TextBlock star in panelStory.Children) - star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR; + star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue; - SetVisible(AllRatingsVisible); + SetVisible(IsEditingMode); } base.OnPropertyChanged(change); } diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs index c9e67099..736117f4 100644 --- a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs +++ b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs @@ -23,7 +23,7 @@ namespace LibationAvalonia.Controls Name = "CellMyRatingDisplay", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - AllRatingsVisible = false, + IsEditingMode = false, Margin = new Thickness(3), IsEnabled = false }; @@ -42,7 +42,7 @@ namespace LibationAvalonia.Controls Name = "CellMyRatingCellEditor", HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - AllRatingsVisible = true, + IsEditingMode = true, Margin = new Thickness(3) }; From b97d8e9403965cbd160c392c6cd35ca44d5dfd4d Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 11:12:04 -0700 Subject: [PATCH 07/14] Add ratings cell tool tips --- Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml | 2 +- Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs | 5 ++++- Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml index f15bea8e..67d7138f 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="LibationAvalonia.Controls.MyRatingCellEditor"> - + - - - - - + + + + + + - - - - - - - - - + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs index f0c584ab..3c7e889f 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs @@ -14,11 +14,8 @@ namespace LibationAvalonia.Controls AvaloniaProperty.Register(nameof(Rating)); public bool IsEditingMode { get; set; } - public Rating Rating - { - get { return GetValue(RatingProperty); } - set { SetValue(RatingProperty, value); } - } + public Rating Rating { get => GetValue(RatingProperty); set => SetValue(RatingProperty, value); } + public MyRatingCellEditor() { InitializeComponent(); @@ -44,16 +41,17 @@ namespace LibationAvalonia.Controls foreach (TextBlock star in panelStory.Children) star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue; - SetVisible(IsEditingMode); + SetVisible(); } base.OnPropertyChanged(change); } - private void SetVisible(bool allVisible) + private void SetVisible() { - tblockOverall.IsVisible = panelOverall.IsVisible = allVisible || Rating?.OverallRating > 0; - tblockPerform.IsVisible = panelPerform.IsVisible = allVisible || Rating?.PerformanceRating > 0; - tblockStory.IsVisible = panelStory.IsVisible = allVisible || Rating?.StoryRating > 0; + ratingsGrid.IsEnabled = IsEditingMode; + tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0; + tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0; + tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0; } public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml deleted file mode 100644 index 3c77bb14..00000000 --- a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs index eab179ea..9dfc6e3f 100644 --- a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs @@ -131,7 +131,7 @@ namespace LibationAvalonia.Dialogs var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions); var selectedFile = selectedFiles.SingleOrDefault(); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { @@ -291,7 +291,7 @@ namespace LibationAvalonia.Dialogs var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { diff --git a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs index 5d6f444e..f6014fe2 100644 --- a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs @@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs { Title = $"Save Sover Image", SuggestedStartLocation = new Avalonia.Platform.Storage.FileIO.BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)), - SuggestedFileName = $"{PictureFileName}.jpg", + SuggestedFileName = PictureFileName, DefaultExtension = "jpg", ShowOverwritePrompt = true, FileTypeChoices = new FilePickerFileType[] @@ -62,7 +62,7 @@ namespace LibationAvalonia.Dialogs var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { diff --git a/Source/LibationAvalonia/Views/MainWindow.Export.cs b/Source/LibationAvalonia/Views/MainWindow.Export.cs index f5d903be..4864fa3e 100644 --- a/Source/LibationAvalonia/Views/MainWindow.Export.cs +++ b/Source/LibationAvalonia/Views/MainWindow.Export.cs @@ -34,7 +34,7 @@ namespace LibationAvalonia.Views var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; var ext = System.IO.Path.GetExtension(uri.LocalPath); switch (ext) diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index 0a86d97f..28967546 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -160,9 +160,8 @@ + - - diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index 8c479f94..d6f7e74f 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -71,6 +71,7 @@ namespace LibationAvalonia.Views AvaloniaXamlLoader.Load(this); productsGrid = this.FindControl(nameof(productsGrid)); + DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded; } #region Cell Context Menu @@ -121,7 +122,7 @@ namespace LibationAvalonia.Views var selectedFiles = await this.GetParentWindow().StorageProvider.OpenFilePickerAsync(openFileDialogOptions); var selectedFile = selectedFiles.SingleOrDefault(); - if (selectedFile.TryGetUri(out var uri)) + if (selectedFile?.TryGetUri(out var uri) is true) FilePathCache.Insert(entry.AudibleProductId, uri.LocalPath); } catch (Exception ex) @@ -179,10 +180,6 @@ namespace LibationAvalonia.Views foreach (var column in productsGrid.Columns) { - //Wire up column context menu - if (column is DataGridTemplateColumnExt tc) - tc.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded; - var itemName = column.SortMemberPath; if (itemName == nameof(GridEntry.Remove)) From 1ac825919abdbe2399c7f4bda9d8611509d80e9f Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 22:39:16 -0700 Subject: [PATCH 12/14] Remove old migrations --- Source/AppScaffolding/LibationScaffolding.cs | 70 -------------- Source/ApplicationServices/LibraryCommands.cs | 94 ------------------- .../Controls/DataGridContextMenus.cs | 40 ++++---- Source/LibationAvalonia/Program.cs | 2 - .../Views/MainWindow.axaml.cs | 10 +- .../GridView/MyRatingGridViewColumn.cs | 5 +- .../LibationWinForms/GridView/ProductsGrid.cs | 2 +- .../WindowsConfigApp/Form1.Designer.cs | 39 -------- Source/LoadByOS/WindowsConfigApp/Form1.cs | 10 -- Source/LoadByOS/WindowsConfigApp/Program.cs | 1 - 10 files changed, 29 insertions(+), 244 deletions(-) delete mode 100644 Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs delete mode 100644 Source/LoadByOS/WindowsConfigApp/Form1.cs diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index 2ab51557..05d5a400 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -81,7 +81,6 @@ namespace AppScaffolding // Migrations.migrate_to_v6_6_9(config); - Migrations.migrate_from_7_10_1(config); } public static void PopulateMissingConfigValues(Configuration config) @@ -457,74 +456,5 @@ namespace AppScaffolding UNSAFE_MigrationHelper.Settings_AddUniqueToArray("Serilog.Enrich", "WithExceptionDetails"); } } - - public static void migrate_from_7_10_1(Configuration config) - { - var lastMigrationThrew = config.GetNonString($"{nameof(migrate_from_7_10_1)}_ThrewError"); - - if (lastMigrationThrew) return; - - try - { - - //https://github.com/rmcrackan/Libation/issues/270#issuecomment-1152863629 - //This migration helps fix databases contaminated with the 7.10.1 hack workaround - //and those with improperly identified or missing series. This does not solve cases - //where individual episodes are in the db with a valid series link, but said series' - //parents have not been imported into the database. For those cases, Libation will - //attempt fixup by retrieving parents from the catalog endpoint - - using var context = DbContexts.GetContext(); - - //This migration removes books and series with SERIES_ prefix that were created - //as a hack workaround in 7.10.1. Said workaround was removed in 7.10.2 - string removeHackSeries = "delete " + - "from series " + - "where AudibleSeriesId like 'SERIES%'"; - - string removeHackBooks = "delete " + - "from books " + - "where AudibleProductId like 'SERIES%'"; - - //Detect series parents that were added to the database as books with ContentType.Episode, - //and change them to ContentType.Parent - string updateContentType = - "UPDATE books " + - "SET contenttype = 4 " + - "WHERE audibleproductid IN (SELECT books.audibleproductid " + - "FROM books " + - "INNER JOIN series " + - "ON ( books.audibleproductid = " + - "series.audibleseriesid) " + - "WHERE books.contenttype = 2)"; - - //Then detect series parents that were added to the database as books with ContentType.Parent - //but are missing a series link, and add the link (don't know how this happened) - string addMissingSeriesLink = - "INSERT INTO seriesbook " + - "SELECT series.seriesid, " + - "books.bookid, " + - "'- 1' " + - "FROM books " + - "LEFT OUTER JOIN seriesbook " + - "ON books.bookid = seriesbook.bookid " + - "INNER JOIN series " + - "ON books.audibleproductid = series.audibleseriesid " + - "WHERE books.contenttype = 4 " + - "AND seriesbook.seriesid IS NULL"; - - context.Database.ExecuteSqlRaw(removeHackSeries); - context.Database.ExecuteSqlRaw(removeHackBooks); - context.Database.ExecuteSqlRaw(updateContentType); - context.Database.ExecuteSqlRaw(addMissingSeriesLink); - - LibraryCommands.SaveContext(context); - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "An error occurred while running database migrations in {0}", nameof(migrate_from_7_10_1)); - config.SetObject($"{nameof(migrate_from_7_10_1)}_ThrewError", true); - } - } } } diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index d67b5332..a051fa84 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -126,22 +126,6 @@ namespace ApplicationServices if (totalCount == 0) return default; - - Log.Logger.Information("Begin scan for orphaned episode parents"); - var newParents = await findAndAddMissingParents(accounts); - Log.Logger.Information($"Orphan episode scan complete. New parents count {newParents}"); - - if (newParents >= 0) - { - //If any episodes are still orphaned, their series have been - //removed from the catalog and we'll never be able to find them. - - //only do this if findAndAddMissingParents returned >= 0. If it - //returned < 0, an error happened and there's still a chance that - //a future successful run will find missing parents. - removedOrphanedEpisodes(); - } - Log.Logger.Information("Begin long-running import"); logTime($"pre {nameof(importIntoDbAsync)}"); var newCount = await importIntoDbAsync(importItems); @@ -235,84 +219,6 @@ namespace ApplicationServices return newCount; } - static void removedOrphanedEpisodes() - { - using var context = DbContexts.GetContext(); - try - { - var orphanedEpisodes = - context - .GetLibrary_Flat_NoTracking(includeParents: true) - .FindOrphanedEpisodes(); - - context.LibraryBooks.RemoveRange(orphanedEpisodes); - context.Books.RemoveRange(orphanedEpisodes.Select(lb => lb.Book)); - - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "An error occurred while trying to remove orphaned episodes from the database"); - } - } - - static async Task findAndAddMissingParents(Account[] accounts) - { - using var context = DbContexts.GetContext(); - - var library = context.GetLibrary_Flat_NoTracking(includeParents: true); - - try - { - var orphanedEpisodes = library.FindOrphanedEpisodes().ToList(); - - if (!orphanedEpisodes.Any()) - return -1; - - var orphanedSeries = - orphanedEpisodes - .SelectMany(lb => lb.Book.SeriesLink) - .DistinctBy(s => s.Series.AudibleSeriesId) - .ToList(); - - // The Catalog endpoint does not require authentication. - var api = new ApiUnauthenticated(accounts[0].Locale); - - var seriesParents = orphanedSeries.Select(o => o.Series.AudibleSeriesId).ToList(); - var items = await api.GetCatalogProductsAsync(seriesParents, CatalogOptions.ResponseGroupOptions.ALL_OPTIONS); - - List newParentsImportItems = new(); - foreach (var sp in orphanedSeries) - { - var seriesItem = items.First(i => i.Asin == sp.Series.AudibleSeriesId); - - if (seriesItem.Relationships is null) - continue; - - var episode = orphanedEpisodes.First(l => l.Book.AudibleProductId == sp.Book.AudibleProductId); - - seriesItem.PurchaseDate = new DateTimeOffset(episode.DateAdded); - seriesItem.Series = new AudibleApi.Common.Series[] - { - new AudibleApi.Common.Series{ Asin = seriesItem.Asin, Title = seriesItem.TitleWithSubtitle, Sequence = "-1"} - }; - - newParentsImportItems.Add(new ImportItem { DtoItem = seriesItem, AccountId = episode.Account, LocaleName = episode.Book.Locale }); - } - - var newCount = new LibraryBookImporter(context) - .Import(newParentsImportItems); - - await context.SaveChangesAsync(); - - return newCount; - } - catch (Exception ex) - { - Serilog.Log.Logger.Error(ex, "An error occurred while trying to scan for orphaned episode parents."); - return -1; - } - } - public static int SaveContext(LibationContext context) { try diff --git a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs index 37044c51..0afcd02c 100644 --- a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs +++ b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs @@ -6,25 +6,6 @@ using System.Reflection; namespace LibationAvalonia.Controls { - public class DataGridCellContextMenuStripNeededEventArgs - { - private static readonly MethodInfo GetCellValueMethod; - static DataGridCellContextMenuStripNeededEventArgs() - { - GetCellValueMethod = typeof(DataGridColumn).GetMethod("GetCellValue", BindingFlags.NonPublic | BindingFlags.Instance); - } - - private static string GetCellValue(DataGridColumn column, object item) - => GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? ""; - - public string CellClipboardContents => GetCellValue(Column, GridEntry); - public DataGridColumn Column { get; init; } - public GridEntry GridEntry { get; init; } - public ContextMenu ContextMenu { get; init; } - public AvaloniaList ContextMenuItems - => ContextMenu.Items as AvaloniaList; - } - internal static class DataGridContextMenus { public static event EventHandler CellContextMenuStripNeeded; @@ -40,7 +21,7 @@ namespace LibationAvalonia.Controls public static void AttachContextMenuToCell(this DataGridCell cell) { - if (cell.ContextMenu is null) + if (cell is not null && cell.ContextMenu is null) { cell.ContextRequested += Cell_ContextRequested; cell.ContextMenu = ContextMenu; @@ -68,4 +49,23 @@ namespace LibationAvalonia.Controls e.Handled = true; } } + + public class DataGridCellContextMenuStripNeededEventArgs + { + private static readonly MethodInfo GetCellValueMethod; + static DataGridCellContextMenuStripNeededEventArgs() + { + GetCellValueMethod = typeof(DataGridColumn).GetMethod("GetCellValue", BindingFlags.NonPublic | BindingFlags.Instance); + } + + private static string GetCellValue(DataGridColumn column, object item) + => GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? ""; + + public string CellClipboardContents => GetCellValue(Column, GridEntry); + public DataGridColumn Column { get; init; } + public GridEntry GridEntry { get; init; } + public ContextMenu ContextMenu { get; init; } + public AvaloniaList ContextMenuItems + => ContextMenu.Items as AvaloniaList; + } } diff --git a/Source/LibationAvalonia/Program.cs b/Source/LibationAvalonia/Program.cs index 2718b8b3..d820eb28 100644 --- a/Source/LibationAvalonia/Program.cs +++ b/Source/LibationAvalonia/Program.cs @@ -13,8 +13,6 @@ namespace LibationAvalonia { static class Program { - private static string EXE_DIR = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); - static void Main() { //***********************************************// diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs index d91bb4a8..6d4e5a86 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs @@ -20,7 +20,7 @@ namespace LibationAvalonia.Views { public event EventHandler Load; public event EventHandler> LibraryLoaded; - private MainWindowViewModel _viewModel; + private readonly MainWindowViewModel _viewModel; public MainWindow() { @@ -135,11 +135,9 @@ namespace LibationAvalonia.Views try { System.Net.Http.HttpClient cli = new(); - using (var fs = System.IO.File.OpenWrite(zipFile)) - { - using (var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl))) - await dlStream.CopyToAsync(fs); - } + using var fs = System.IO.File.OpenWrite(zipFile); + using var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl)); + await dlStream.CopyToAsync(fs); } catch (Exception ex) { diff --git a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs index 2c360ec1..56893822 100644 --- a/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs +++ b/Source/LibationWinForms/GridView/MyRatingGridViewColumn.cs @@ -43,7 +43,7 @@ namespace LibationWinForms.GridView protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { if (value is Rating rating) - { + { ToolTipText = "Click to change ratings"; var starString = rating.ToStarString(); @@ -53,6 +53,9 @@ namespace LibationWinForms.GridView base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, string.Empty, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); } + protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) + => value is Rating rating ? rating.ToStarString() : value?.ToString(); + public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter) => formattedValue; } diff --git a/Source/LibationWinForms/GridView/ProductsGrid.cs b/Source/LibationWinForms/GridView/ProductsGrid.cs index 0ac93377..78d0d260 100644 --- a/Source/LibationWinForms/GridView/ProductsGrid.cs +++ b/Source/LibationWinForms/GridView/ProductsGrid.cs @@ -120,7 +120,7 @@ namespace LibationWinForms.GridView try { var dgv = (DataGridView)sender; - var text = dgv[e.ColumnIndex, e.RowIndex].Value.ToString(); + var text = dgv[e.ColumnIndex, e.RowIndex].FormattedValue.ToString(); InteropFactory.Create().CopyTextToClipboard(text); } catch { } diff --git a/Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs b/Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs deleted file mode 100644 index 30118c1b..00000000 --- a/Source/LoadByOS/WindowsConfigApp/Form1.Designer.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace WindowsConfigApp -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(800, 450); - this.Text = "Form1"; - } - - #endregion - } -} \ No newline at end of file diff --git a/Source/LoadByOS/WindowsConfigApp/Form1.cs b/Source/LoadByOS/WindowsConfigApp/Form1.cs deleted file mode 100644 index d3265e4e..00000000 --- a/Source/LoadByOS/WindowsConfigApp/Form1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace WindowsConfigApp -{ - public partial class Form1 : Form - { - public Form1() - { - InitializeComponent(); - } - } -} \ No newline at end of file diff --git a/Source/LoadByOS/WindowsConfigApp/Program.cs b/Source/LoadByOS/WindowsConfigApp/Program.cs index 93f5d8c6..1786ce7b 100644 --- a/Source/LoadByOS/WindowsConfigApp/Program.cs +++ b/Source/LoadByOS/WindowsConfigApp/Program.cs @@ -7,7 +7,6 @@ namespace WindowsConfigApp public override Type InteropFunctionsType => typeof(WinInterop); public override Type[] ReferencedTypes => new Type[] { - typeof(Form1), typeof(Bitmap), typeof(Dinah.Core.WindowsDesktop.GitClient), typeof(Accessibility.IAccIdentity), From 7ef666dc91f14731bc9ed8e8f2dbc45e4acc1abe Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 23:31:24 -0700 Subject: [PATCH 13/14] Add TCOM tag for narrator --- Source/AaxDecrypter/AaxDecrypter.csproj | 2 +- Source/AaxDecrypter/AaxcDownloadConvertBase.cs | 3 +++ .../LibationAvalonia/Views/MainWindow.axaml.cs | 16 +++++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj index 7a885fb2..5724667b 100644 --- a/Source/AaxDecrypter/AaxDecrypter.csproj +++ b/Source/AaxDecrypter/AaxDecrypter.csproj @@ -13,7 +13,7 @@ - + diff --git a/Source/AaxDecrypter/AaxcDownloadConvertBase.cs b/Source/AaxDecrypter/AaxcDownloadConvertBase.cs index 10f2cc37..dc4eeb66 100644 --- a/Source/AaxDecrypter/AaxcDownloadConvertBase.cs +++ b/Source/AaxDecrypter/AaxcDownloadConvertBase.cs @@ -32,6 +32,9 @@ namespace AaxDecrypter AaxFile.AppleTags.Album = AaxFile.AppleTags.Album?.Replace(" (Unabridged)", ""); } + if (DownloadOptions.FixupFile) + AaxFile.AppleTags.AppleListBox.EditOrAddTag("TCOM", AaxFile.AppleTags.Narrator); + //Finishing configuring lame encoder. if (DownloadOptions.OutputFormat == OutputFormat.Mp3) MpegUtil.ConfigureLameOptions( diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs index 6d4e5a86..d8580470 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs @@ -77,7 +77,7 @@ namespace LibationAvalonia.Views try { - (string zipFile, UpgradeProperties upgradeProperties) = await Task.Run(() => downloadUpdate()); + (string zipFile, UpgradeProperties upgradeProperties) = await Task.Run(downloadUpdate); if (string.IsNullOrEmpty(zipFile) || !System.IO.File.Exists(zipFile)) return; @@ -152,8 +152,6 @@ namespace LibationAvalonia.Views var thisExe = Environment.ProcessPath; var thisDir = System.IO.Path.GetDirectoryName(thisExe); - var args = $"--input {zipFile.SurroundWithQuotes()} --output {thisDir.SurroundWithQuotes()} --executable {thisExe.SurroundWithQuotes()}"; - var zipExtractor = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ZipExtractor.exe"); System.IO.File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true); @@ -164,8 +162,16 @@ namespace LibationAvalonia.Views UseShellExecute = true, Verb = "runas", WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal, - Arguments = args, - CreateNoWindow = true + CreateNoWindow = true, + ArgumentList = + { + "--input", + zipFile, + "--output", + thisDir, + "--executable", + thisExe + } }; System.Diagnostics.Process.Start(psi); From 0ed506268320d8a14ec99d33103b573563871205 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 1 Jan 2023 11:23:22 -0700 Subject: [PATCH 14/14] Cancel rating edit on escape --- .../Controls/DataGridContextMenus.cs | 2 +- .../Controls/DataGridMyRatingColumn.cs | 2 +- .../Controls/DataGridTemplateColumnExt.cs | 2 +- .../GridView/MyRatingCellEditor.cs | 17 +++++++++++++++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs index 0afcd02c..4ec6d825 100644 --- a/Source/LibationAvalonia/Controls/DataGridContextMenus.cs +++ b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs @@ -19,7 +19,7 @@ namespace LibationAvalonia.Controls OwningColumnProperty = typeof(DataGridCell).GetProperty("OwningColumn", BindingFlags.Instance | BindingFlags.NonPublic); } - public static void AttachContextMenuToCell(this DataGridCell cell) + public static void AttachContextMenu(this DataGridCell cell) { if (cell is not null && cell.ContextMenu is null) { diff --git a/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs index d3731e4a..36df2d0c 100644 --- a/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs +++ b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs @@ -22,7 +22,7 @@ namespace LibationAvalonia.Controls }; ToolTip.SetTip(myRatingElement, "Click to change ratings"); - cell?.AttachContextMenuToCell(); + cell?.AttachContextMenu(); if (Binding != null) { diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs index 58f94ff3..bf5d84e3 100644 --- a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs @@ -8,7 +8,7 @@ namespace LibationAvalonia.Controls { protected override IControl GenerateElement(DataGridCell cell, object dataItem) { - cell?.AttachContextMenuToCell(); + cell?.AttachContextMenu(); return base.GenerateElement(cell, dataItem); } } diff --git a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs index 1a322cc4..c9f3ecfe 100644 --- a/Source/LibationWinForms/GridView/MyRatingCellEditor.cs +++ b/Source/LibationWinForms/GridView/MyRatingCellEditor.cs @@ -102,12 +102,25 @@ namespace LibationWinForms.GridView EditingControlDataGridView.NotifyCurrentCellDirty(true); } + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.KeyCode == Keys.Escape) + { + EditingControlDataGridView.RefreshEdit(); + EditingControlDataGridView.CancelEdit(); + EditingControlDataGridView.CurrentCell.DetachEditingControl(); + EditingControlDataGridView.CurrentCell = null; + + } + base.OnKeyDown(e); + } + #region IDataGridViewEditingControl public DataGridView EditingControlDataGridView { get; set; } public int EditingControlRowIndex { get; set; } public bool EditingControlValueChanged { get; set; } - public object EditingControlFormattedValue { get => Rating; set => Rating = (Rating)value; } + public object EditingControlFormattedValue { get => Rating; set { } } public Cursor EditingPanelCursor => Cursor; public bool RepositionEditingControlOnValueChange => false; @@ -118,7 +131,7 @@ namespace LibationWinForms.GridView BackColor = dataGridViewCellStyle.BackColor; } - public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) => false; + public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) => keyData == Keys.Escape; public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => EditingControlFormattedValue; public void PrepareEditingControlForEdit(bool selectAll) { }