Write embedded title block templates in a stable order

Fifth site of the hash-ordering defect fixed in #844.
TitleBlockTemplatesProjectCollection::templates() returns
titleblock_templates_xml_.keys(), a QHash, and QETProject::toXml() iterated
it directly. A project embedding more than one template therefore wrote the
<titleblocktemplate> children in a different order on every save.

examples/affuteuse_250h.qet embeds three -- A4_1, DIN_A4 and DIN_A4_copy --
and two saves of it produced "DIN_A4 A4_1 DIN_A4_copy" and
"DIN_A4_copy A4_1 DIN_A4". It was the last of the two projects #844 could not
make reproducible.

Worth recording because the first reading of that diff was wrong: seeing
name="DIN_A4" on one side and name="DIN_A4_copy" on the other looked like the
save path renaming a template, which would have been far more serious -- a
diagram referring to it by name would have been left dangling. The file
simply contains both, and they had swapped places.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-13 00:06:31 +12:00
parent f9d063bd38
commit cb0d8c8f63
+8 -1
View File
@@ -1043,7 +1043,14 @@ QDomDocument QETProject::toXml()
// titleblock templates, if any
if (m_titleblocks_collection.templates().count()) {
QDomElement titleblocktemplates_elmt = xml_doc.createElement("titleblocktemplates");
foreach (QString template_name, m_titleblocks_collection.templates()) {
//Sorted, because templates() returns QHash::keys() and Qt
//randomises hash order per process. Writing them unsorted put the
//<titleblocktemplate> children in a different order on every save,
//which is what made a project holding more than one template save
//irreproducibly.
QStringList template_names = m_titleblocks_collection.templates();
template_names.sort();
for (const QString &template_name : std::as_const(template_names)) {
QDomElement e = m_titleblocks_collection.getTemplateXmlDescription(template_name);
titleblocktemplates_elmt.appendChild(xml_doc.importNode(e, true));
}