From 0c2027fd77ddf1fbd1ab83533c7676440b1c3b25 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Tue, 11 Aug 2026 13:02:03 +1200 Subject: [PATCH] Fix bugtracker #245: bare %name custom variables not detected in title blocks TitleBlockTemplate::listOfVariables() -- which scans a title block template's cells to auto-populate the "Custom" tab in Project Properties (a feature recently added by another contributor, see TitleBlockPropertiesWidget::addTemplateVariables()) -- only matched the braced "%{name}" placeholder form. The bare "%name" form (also a legitimate, fully-supported substitution syntax -- see TitleBlockTemplate::interpreteVariables(), which already replaces both forms) was never matched at all, not merely mishandled on edge cases: a cell containing "%name2" alone, "%name2 " with a trailing space, or "%name2 %name3" with two bare variables all produced zero detected variables, exactly matching the report (manually adding the variable in Project Properties works fine and renders correctly, since rendering goes through interpreteVariables()'s simple string replacement against already-known keys, not this regex). Fix: extend the regex to also match a bare "%name" as the longest run of identifier characters immediately after '%', via a second alternative/capture group. This naturally stops at whitespace, so "%name2 " and "%name2 %name3" are both now correctly detected -- no change to the existing braced-form handling, and the existing globalMatch() loop already correctly finds multiple matches per cell. Verified: clean rebuild, only the intended object file recompiled and linked successfully. Wrote a standalone test of the regex/extraction logic covering exactly the reported repro cases -- "%name2", "%name2 " (trailing space), "%name2 %name3" (two bare variables), "%{name2}" (braced form, unaffected), a braced+bare mix, plain text with no variables, and two built-in-style names -- all extracted correctly with no regressions to the previously-working braced form. Not verified: the actual Project Properties "Custom" tab UI auto-populating live, since exercising the full Xvfb GUI flow (title block template editor > add a bare-form custom variable to a cell > save > open Project Properties > select that template > confirm the Custom tab lists it) was out of scope for the time available given the extraction logic itself was already precisely verified in isolation. --- sources/titleblocktemplate.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sources/titleblocktemplate.cpp b/sources/titleblocktemplate.cpp index 4379605c1..327bbcf0d 100644 --- a/sources/titleblocktemplate.cpp +++ b/sources/titleblocktemplate.cpp @@ -1846,10 +1846,13 @@ QString TitleBlockTemplate::interpreteVariables( QStringList TitleBlockTemplate::listOfVariables() { QStringList list; - // Match every "%{name}" placeholder. The bare "%name" form can't be - // extracted reliably without the variable list, and templates use the - // braced form, so only that is collected here. - static const QRegularExpression rx(QStringLiteral("%\\{([^}]+)\\}")); + // Match both the braced "%{name}" form and the bare "%name" form + // (bugtracker #245): a bare name is taken as the longest run of + // identifier characters right after the '%', which correctly stops at + // whitespace -- so "%name2 " and "%name2 %name3" are both detected, + // matching what previously only worked for the braced form. + static const QRegularExpression rx( + QStringLiteral("%\\{([^}]+)\\}|%([A-Za-z0-9_-]+)")); // run through each individual cell for (int j = 0 ; j < rows_heights_.count() ; ++ j) { for (int i = 0 ; i < columns_width_.count() ; ++ i) { @@ -1860,7 +1863,9 @@ QStringList TitleBlockTemplate::listOfVariables() const QString cell_value = cells_[i][j] -> value.name(); auto it = rx.globalMatch(cell_value); while (it.hasNext()) { - const QString name = it.next().captured(1); + const QRegularExpressionMatch m = it.next(); + const QString name = m.captured(1).isEmpty() + ? m.captured(2) : m.captured(1); if (!name.isEmpty() && !list.contains(name)) list << name; }