Save a new title, author or revision without building the folio (stage D5)

A folio not built whose own data changed was built to save, with the
folios its links reach. When what changed is only title block fields
nothing on a folio is computed from -- its title, author, date,
revision index, version, file name, template; a formula reads the
folio's label, plant, location, extra fields and grid -- its items as
read are what building it would write: it is saved from them with its
own data as it is now (Diagram::deferredXmlWithHeader()), .qet and
.qetz alike, with the information of its symbols changed through the
project database (or built, when one of those needs it). Any other
change still builds it.

136-folio .qetz, revision index and author set on every folio by a
script: 0.8 s, saved in 6.8 s, no folio built; with every folio built,
the same file. tst_lazyfolios: a new revision on every folio of a .qet
and of a .qetz saved as when built, building only the folios holding a
table (fails, 47 built, when every change counts); a folio whose label
changed is built (fails when none counts). ctest 96/96 eager and lazy;
342 corpus projects save the same in all four arms and export the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-12 17:54:37 +13:00
parent 244de05421
commit b151f52428
4 changed files with 154 additions and 2 deletions
+51
View File
@@ -830,6 +830,57 @@ QList<Element *> Diagram::buildSymbols(const QSet<QUuid> &uuids)
return built;
}
namespace {
//The title block fields nothing on a folio is computed from: a formula
//reads the folio's label, plant, location, extra fields and grid
//(autonum::FormulaContext), none of these
const QStringList ShownOnlyFields = {
QStringLiteral("title"), QStringLiteral("author"), QStringLiteral("date"),
QStringLiteral("indexrev"), QStringLiteral("version"), QStringLiteral("filename"),
QStringLiteral("titleblocktemplate"), QStringLiteral("titleblocktemplateCollection")};
QString headerWithoutShownOnly(const QString &header)
{
QDomDocument document;
document.setContent(header);
QDomElement root = document.documentElement();
for (const QString &field : ShownOnlyFields) root.removeAttribute(field);
return document.toString();
}
}
/**
@brief Diagram::headerChangeShowsOnly
@return true if what changed in this folio's own data since it was read
(headerChanged()) is only title block fields nothing on the folio is
computed from (its title, author, date, revision, file name, template):
its items, as read, are what building it would write
*/
bool Diagram::headerChangeShowsOnly()
{
return headerWithoutShownOnly(headerXml()) == headerWithoutShownOnly(m_opened_header);
}
/**
@brief Diagram::deferredXmlWithHeader
@return this folio, not built, as it saves: its own data as it is now
(writeHeader()) and its items as read (deferredXml()), in @p document --
when its items are what building it would write (headerChangeShowsOnly())
*/
QDomElement Diagram::deferredXmlWithHeader(QDomDocument &document)
{
QDomElement folio = document.createElement(QStringLiteral("diagram"));
writeHeader(document, folio);
QSet<QString> header_children;
for (QDomElement child = folio.firstChildElement() ; !child.isNull() ; child = child.nextSiblingElement())
header_children.insert(child.tagName());
const QDomElement items = deferredXml();
for (QDomElement child = items.firstChildElement() ; !child.isNull() ; child = child.nextSiblingElement())
if (!header_children.contains(child.tagName()))
folio.appendChild(document.importNode(child, true));
return folio;
}
/**
@brief Diagram::deferredXml
@return the XML of this folio's items while they are not built: kept
+2
View File
@@ -240,6 +240,8 @@ class Diagram : public QGraphicsScene
/// headerChanged() (QETProject::toXml())
void rememberHeader() {m_opened_header = headerXml();}
bool headerChanged() {return headerXml() != m_opened_header;}
bool headerChangeShowsOnly();
QDomElement deferredXmlWithHeader(QDomDocument &document);
void ensureLoaded();
bool buildDeferred();
//The last argument is only for a copy fragment: when it is
+28 -2
View File
@@ -2374,9 +2374,17 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
changed << diagram;
}
buildFolios(changed);
for (Diagram *diagram : std::as_const(m_diagrams_list))
if (diagram->headerChanged())
//-- unless it changed only in what nothing is computed from (its
//title, date, revision...): written from its items as read
//(Diagram::deferredXmlWithHeader())
for (Diagram *diagram : std::as_const(m_diagrams_list)) {
if (!diagram->headerChanged()) continue;
bool edits_need_build = false;
if (!diagram->isLoaded())
m_data_base.unbuiltEditsOnFolio(diagram->uuid(), &edits_need_build);
if (diagram->isLoaded() || !diagram->headerChangeShowsOnly() || edits_need_build)
buildFolioToShow(diagram);
}
//A table filled from the database saves the size its rows
//give it, which any edit can change
if (m_edited_since_open)
@@ -2490,6 +2498,24 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
<< "["
<< diagram
<< "]";
if (keep && !diagram->isLoaded() && diagram->headerChanged()) {
QDomElement xml_diagram = diagram->deferredXmlWithHeader(xml_doc);
//Its symbols whose information changed while it was not built
const QHash<QUuid, DiagramContext> edits = m_data_base.unbuiltEditsOnFolio(diagram->uuid());
for (const QDomElement &list : QET::findInDomElement(xml_diagram, QStringLiteral("elements")))
for (QDomElement element = list.firstChildElement(QStringLiteral("element")) ; !element.isNull() ;
element = element.nextSiblingElement(QStringLiteral("element"))) {
const auto edit = edits.constFind(QUuid(element.attribute(QStringLiteral("uuid"))));
if (edit == edits.constEnd()) continue;
QDomElement information = xml_doc.createElement(QStringLiteral("elementInformations"));
edit->toXml(information, QStringLiteral("elementInformation"));
const QDomElement old_information = element.firstChildElement(QStringLiteral("elementInformations"));
element.replaceChild(information, old_information); //it has one (unbuiltEditsOnFolio())
}
xml_diagram.setAttribute("order", order_num ++);
project_root.appendChild(xml_diagram);
continue;
}
if (keep && !diagram->isLoaded() && kept_parts) {
auto placeholder = xml_doc.createElement(QStringLiteral("diagram"));
placeholder.setAttribute(QStringLiteral("qetz-kept-part"), diagram->deferredPart());