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);