diff --git a/src/BloomExe/Book/Book.cs b/src/BloomExe/Book/Book.cs index 75fd558bbeaf..50de4b7cea2e 100644 --- a/src/BloomExe/Book/Book.cs +++ b/src/BloomExe/Book/Book.cs @@ -232,6 +232,12 @@ public Book( /// public string PendingCreationSource { get; set; } + /// + /// Snapshot of the source book's title (in L1, usually empty) captured when the new book is created. + /// This lets us distinguish true user title edits from automatic recalculation. + /// + public string PendingCreationSourceTitle { get; set; } + /// /// If there is a pending "Created" history event (set during book creation), record it now /// using the book's current title. @@ -244,14 +250,27 @@ public void RecordPendingCreatedHistoryEvent(bool onlyIfTitleChanged = false) { if (PendingCreationSource == null) return; - if (onlyIfTitleChanged && Storage.Dom.Title == PendingCreationSource) - return; + if (onlyIfTitleChanged) + { + // Compare L1 titles to detect if the user has actually changed the title. + // Extract the current book's L1 title using its BookData language. + var sourceTitle = PendingCreationSourceTitle ?? string.Empty; + var currentL1Title = string.Empty; + if (BookInfo != null && BookData != null) + { + currentL1Title = + BookInfo.GetTitleForLanguage(BookData.Language1Tag) ?? string.Empty; + } + if (sourceTitle == currentL1Title) + return; + } BookHistory.AddEvent( this, BookHistoryEventType.Created, $"Created a new book \"{Storage.Dom.Title}\" from a source book \"{PendingCreationSource}\"" ); PendingCreationSource = null; + PendingCreationSourceTitle = null; } public void UpdateBookInfoFromDisk() diff --git a/src/BloomExe/Book/BookInfo.cs b/src/BloomExe/Book/BookInfo.cs index 8bd252a7931d..bfdf2a47ddda 100644 --- a/src/BloomExe/Book/BookInfo.cs +++ b/src/BloomExe/Book/BookInfo.cs @@ -253,6 +253,33 @@ public virtual string AllTitles set { MetaData.AllTitles = value; } } + /// + /// Extract the title for a specific language from AllTitles JSON. + /// Returns the title if found, otherwise returns an empty string. + /// + public string GetTitleForLanguage(string languageTag) + { + if (string.IsNullOrWhiteSpace(AllTitles) || string.IsNullOrWhiteSpace(languageTag)) + return string.Empty; + + try + { + var jsonString = AllTitles.Replace("\r", "\\r").Replace("\n", "\\n"); + dynamic titles = DynamicJson.Parse(jsonString); + var langs = (IEnumerable)titles.GetDynamicMemberNames(); + if (langs.Contains(languageTag)) + { + return ((string)titles[languageTag]).Trim(); + } + } + catch + { + // If parsing fails, return empty + } + + return string.Empty; + } + public string Isbn { get { return MetaData.Isbn; } diff --git a/src/BloomExe/CollectionTab/CollectionModel.cs b/src/BloomExe/CollectionTab/CollectionModel.cs index 5d7d471aac88..dd673f4b8fd4 100644 --- a/src/BloomExe/CollectionTab/CollectionModel.cs +++ b/src/BloomExe/CollectionTab/CollectionModel.cs @@ -1032,19 +1032,16 @@ private void CreateFromSourceBook(Book.Book sourceBook) if (newBook == null) return; //This can happen if there is a configuration dialog and the user clicks Cancel - // We want it to have the name it's eventually going to BEFORE we add it to the collection. - // Otherwise, there are race conditions between the code that is selecting it (and as a side - // effect, bringing it up to date, which may rename it and its folder, if it already has a - // title in the relevant language) and the code that wants to display a thumbnail of the new - // item in the list. - // (We can't fix this by reordering things, because there will also be problems if we attempt - // to select an item before it is present in the collection to select.) - // We know this is a new book object, so there's no point in using EnsureUpToDate. - // When we later select it, that code uses EnsureUpToDate and will not do it again. - // Set before BringBookUpToDate so that title-change events fired during that call - // are suppressed (no spurious Renamed entries). The Created event will be recorded - // when the user enters a title (or various events if no title is entered earlier). + // We want to eventually make a book-created entry in history for this book, + // which includes information about the book we made it from. We want to wait + // to make that record until the new author gives it a name in L1. Possible + // sources for the original name may be lost in the course of bringing it up to + // date, so we capture the original title now. Also, we capture the initial + // L1 title, so we can reliably tell whether the user has actually provided one. newBook.PendingCreationSource = Path.GetFileName(sourceBook.FolderPath); + var l1Lang = newBook?.BookData?.Language1Tag; + var sourceL1Title = sourceBook.BookInfo.GetTitleForLanguage(l1Lang); + newBook.PendingCreationSourceTitle = sourceL1Title; newBook.BringBookUpToDate(new NullProgress(), false); TheOneEditableCollection.AddBookInfo(newBook.BookInfo);