Make the font restoration counters safe against nested project loads

DialogWaiting pumps the event loop while the folios of a project are
built, so a second openAndAddProject() can run to completion nested
inside the first one (drop on another editor window, queued open) and
the plain reset/read counters would then report the wrong numbers.

Replace them with a RAII counting window (FontRestorationScope): the
constructor keeps the enclosing counts aside, the destructor restores
them. The nesting is strictly LIFO - the nested load completes inside
the pump of the outer one - so each load reports exactly its own
numbers, and the early-return paths of openAndAddProject() restore the
outer window automatically.

Suggested by ispyisail in the review of the reporting change.
This commit is contained in:
Dieter Mayer
2026-08-01 11:13:57 +02:00
parent 0fa2591c4f
commit 3bc2e8e712
3 changed files with 49 additions and 18 deletions
+6 -4
View File
@@ -1171,8 +1171,10 @@ bool QETDiagramEditor::openAndAddProject(
//Per-project window for the font counters reported below; the folios
//(and with them the stored font descriptions) are built between here
//and the end of addProject().
QETUtils::resetFontRestorationCounters();
//and the end of addProject(). RAII, because DialogWaiting pumps the
//event loop during the load: a nested openAndAddProject() gets its
//own window and this one resumes unharmed.
QETUtils::FontRestorationScope font_scope;
QETProject *project = new QETProject(filepath);
if (project -> state() != QETProject::Ok)
@@ -1203,8 +1205,8 @@ bool QETDiagramEditor::openAndAddProject(
//Report font descriptions which could not be read as-is (written by
//an incompatible Qt version or corrupted), so the user learns about
//it from somewhere else than the console. See issue #553.
const int salvaged_fonts = QETUtils::salvagedFontCount();
const int unreadable_fonts = QETUtils::unreadableFontCount();
const int salvaged_fonts = font_scope.salvaged();
const int unreadable_fonts = font_scope.unreadable();
if (salvaged_fonts || unreadable_fonts)
{
qInfo().nospace() << "Project font descriptions: "
+20 -11
View File
@@ -304,33 +304,42 @@ bool QETUtils::fontFromString(QFont &font, const QString &description)
}
/**
* @brief QETUtils::resetFontRestorationCounters
* Reset the counters incremented by fontFromString(), to be called before
* loading a project so the numbers reported afterwards are per-project.
* @brief QETUtils::FontRestorationScope::FontRestorationScope
* Open a fresh counting window: the enclosing window's counts are kept
* aside and restored by the destructor, so a project load nested inside
* another one (through the event loop) reports its own numbers only.
*/
void QETUtils::resetFontRestorationCounters()
QETUtils::FontRestorationScope::FontRestorationScope() :
m_outer_salvaged(salvaged_font_count),
m_outer_unreadable(unreadable_font_count)
{
salvaged_font_count = 0;
unreadable_font_count = 0;
}
QETUtils::FontRestorationScope::~FontRestorationScope()
{
salvaged_font_count = m_outer_salvaged;
unreadable_font_count = m_outer_unreadable;
}
/**
* @brief QETUtils::salvagedFontCount
* @brief QETUtils::FontRestorationScope::salvaged
* @return How many font descriptions fontFromString() restored from a
* foreign or corrupt format since the counters were last reset. Such
* descriptions are rewritten in the stable format on the next save.
* foreign or corrupt format since this window was opened. Such descriptions
* are rewritten in the stable format on the next save.
*/
int QETUtils::salvagedFontCount()
int QETUtils::FontRestorationScope::salvaged() const
{
return salvaged_font_count;
}
/**
* @brief QETUtils::unreadableFontCount
* @brief QETUtils::FontRestorationScope::unreadable
* @return How many font descriptions fontFromString() could not restore at
* all since the counters were last reset (the caller's default font applies).
* all since this window was opened (the caller's default font applies).
*/
int QETUtils::unreadableFontCount()
int QETUtils::FontRestorationScope::unreadable() const
{
return unreadable_font_count;
}
+23 -3
View File
@@ -34,9 +34,29 @@ namespace QETUtils
void pixelSizedFont (QFont &font);
QString fontToString (const QFont &font);
bool fontFromString (QFont &font, const QString &description);
void resetFontRestorationCounters ();
int salvagedFontCount ();
int unreadableFontCount ();
/**
RAII counting window for the font descriptions fontFromString()
salvages or fails to read: construction opens a fresh window, the
destructor restores the enclosing one. Windows nest strictly LIFO,
which covers project loads re-entered through the event loop
(DialogWaiting pumps it while the folios are built).
*/
class FontRestorationScope
{
public:
FontRestorationScope();
~FontRestorationScope();
FontRestorationScope(const FontRestorationScope &) = delete;
FontRestorationScope &operator=(const FontRestorationScope &) = delete;
int salvaged() const;
int unreadable() const;
private:
int m_outer_salvaged;
int m_outer_unreadable;
};
bool sortBeginIntString(const QString &str_a, const QString &str_b);