Write model header roles in a stable order

Fourth and last instance of the ordering defect, and the inner half of the
one fixed in the previous commit. ProjectDBModel::toXml() builds each
section's role list from m_header_data.value(key).keys(), and m_header_data
is a QHash<int, QHash<int, QVariant>> -- so both levels are randomised per
process. Sorting the sections left the roles inside each section still
arriving shuffled, which showed up as <data> children with the same
section="0" swapping places between two saves.

With this, save idempotence across the shipped examples goes from 6 of 23 to
22 of 24.

The two that remain fail for unrelated reasons, not for ordering:
schema_indus.qet stores no uuid attribute on its elements at all, so
fromXml() invents a fresh one on every load; and affuteuse_250h.qet loses a
title block logo's storage attribute and renames a title block template on
save. Both are separate defects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-12 23:31:26 +12:00
parent 1272b9db06
commit fcbea2dafd
@@ -17,6 +17,8 @@
*/
#include "projectdbmodel.h"
#include <algorithm>
#include "../../dataBase/projectdatabase.h"
#include "../../qetapp.h"
#include "../../qetinformation.h"
@@ -266,7 +268,13 @@ QDomElement ProjectDBModel::toXml(QDomDocument &document) const
//We save all data except the display role, because he was generated in the fly
auto list = m_header_data.value(key).keys();
list.removeAll(Qt::DisplayRole);
//Sorted: m_header_data's inner container is a QHash too, so its
//key order is randomised per process. modelHeaderDataToXml()
//writes the roles of a section in the order given here, so an
//unsorted list reordered the <data> children of that section on
//every save and kept the save irreproducible.
std::sort(list.begin(), list.end());
horizontal_.insert(key, list);
}