mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-14 17:44:13 +02:00
Save a .qetz without building partners: symbols save the links they wait for (stage D5a)
A built symbol whose partner is on a folio not built yet (QET_LAZY_FOLIOS) now saves that link too, in the order it was saved with (Element::toXml(); QETProject::waitingLinkTargets() keeps it to partners the project has, so a link to a symbol gone is dropped as it always was). With that, and with no partner's text in a .qetz's folio files (D3c), saving a .qetz no longer builds the folios of the partners built folios wait for; table chains still are (a table saves the table before it), and a .qet saved as read (QET_LAZY_SAVE_KEPT) still builds them, its folio files holding partners' texts. industrial.qetz: an untouched save builds no folio (47 of 47 stay not built; 19 before), after everyday edits on its busiest folio 29 stay not built (7 before). tst_lazyfolios compares the links an edited .qetz saved without building holds, symbol by symbol in their order, with those the same edits saved with every folio built -- it fails when waiting links are not saved (the drawing alone cannot tell: links are kept on both sides, and a symbol reread gets its partner's back, in another order). Corpus, 342 projects: a .qetz saved without building, read and saved as .qet = eager = master. ctest 96/96 with and without QET_LAZY_FOLIOS=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1250,17 +1250,41 @@ QDomElement Element::toXml(
|
||||
|
||||
//if this element is linked to other elements,
|
||||
//save the uuid of each other elements
|
||||
if (! isFree()) {
|
||||
//A partner on a folio not built yet (QET_LAZY_FOLIOS), which this
|
||||
//symbol will be linked to, is saved too, in the order the symbol was
|
||||
//saved with: saving needs no partner built (stage D5a)
|
||||
QList<std::pair<QUuid, int>> links;
|
||||
if (keepsSavedLinks() && diagram() && diagram()->project()) {
|
||||
const QSet<QUuid> waiting = diagram()->project()->waitingLinkTargets();
|
||||
QSet<Element *> written;
|
||||
for (const auto &link_info : std::as_const(tmp_uuids_link)) {
|
||||
Element *linked = nullptr;
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (elmt->uuid() == link_info.uuid && !written.contains(elmt)) { linked = elmt; break; }
|
||||
if (linked) {
|
||||
written.insert(linked);
|
||||
links.append({linked->uuid(), m_group_index_map.value(linked, -1)});
|
||||
} else if (waiting.contains(link_info.uuid)) {
|
||||
links.append({link_info.uuid, link_info.group_index});
|
||||
}
|
||||
}
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
if (!written.contains(elmt))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1)});
|
||||
} else {
|
||||
for (Element *elmt : std::as_const(connected_elements))
|
||||
links.append({elmt->uuid(), m_group_index_map.value(elmt, -1)});
|
||||
}
|
||||
if (!links.isEmpty()) {
|
||||
QDomElement links_uuids = document.createElement(QStringLiteral("links_uuids"));
|
||||
foreach (Element *elmt, connected_elements) {
|
||||
for (const auto &link : std::as_const(links)) {
|
||||
QDomElement link_uuid =
|
||||
document.createElement(QStringLiteral("link_uuid"));
|
||||
link_uuid.setAttribute(QStringLiteral("uuid"), elmt->uuid().toString());
|
||||
link_uuid.setAttribute(QStringLiteral("uuid"), link.first.toString());
|
||||
|
||||
// Save group index if assigned (for slave->master links)
|
||||
int gi = m_group_index_map.value(elmt, -1);
|
||||
if (gi >= 0) {
|
||||
link_uuid.setAttribute(QStringLiteral("group_index"), gi);
|
||||
if (link.second >= 0) {
|
||||
link_uuid.setAttribute(QStringLiteral("group_index"), link.second);
|
||||
}
|
||||
|
||||
links_uuids.appendChild(link_uuid);
|
||||
|
||||
+11
-5
@@ -2327,17 +2327,21 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
|
||||
QetGraphicsTableItem::xmlTagName()).isEmpty())
|
||||
buildFolioToShow(diagram);
|
||||
//A built folio is written from its items, which need their
|
||||
//partners: a symbol saves its links, a report the position of
|
||||
//its partner. Build the folios of every partner still waiting,
|
||||
//and of every table chain, until none is
|
||||
//partners: a table saves the table before it, and in a .qet a
|
||||
//report the position of its partner. Build the folios of every
|
||||
//table chain, and for a .qet of every partner still waiting,
|
||||
//until none is. A symbol saves the partners it waits for itself
|
||||
//(Element::toXml()), and a .qetz keeps no partner's text (D3c):
|
||||
//saving a .qetz builds no partner (stage D5a)
|
||||
for (int built = -1 ; built != unloadedFolioCount() ; )
|
||||
{
|
||||
built = unloadedFolioCount();
|
||||
QSet<QUuid> waiting;
|
||||
QSet<Diagram *> chained;
|
||||
for (Diagram *diagram : builtFolios()) {
|
||||
for (Element *element : diagram->elements())
|
||||
waiting.unite(element->pendingLinks());
|
||||
if (kept_folios)
|
||||
for (Element *element : diagram->elements())
|
||||
waiting.unite(element->pendingLinks());
|
||||
for (Diagram *other : tableChainFolios(diagram))
|
||||
if (!other->isLoaded()) chained.insert(other);
|
||||
}
|
||||
@@ -2351,6 +2355,7 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
|
||||
} else {
|
||||
loadFolios();
|
||||
}
|
||||
m_waiting_link_targets = unloadedFolioCount() ? symbolsOnUnbuiltFolios() : QSet<QUuid>();
|
||||
//QET_CHECK_ELEMENT_INFO_STORE=1: say whether the stores of symbol
|
||||
//information, folio title blocks and wire properties agree with every placed symbol, folio and
|
||||
//wire, at each save. A test and debugging aid; it changes nothing.
|
||||
@@ -2478,6 +2483,7 @@ QDomDocument QETProject::toXml(QHash<int, QByteArray> *kept_folios, QStringList
|
||||
// Write the elements collection.
|
||||
project_root.appendChild(m_elements_collection->root().cloneNode(true));
|
||||
|
||||
m_waiting_link_targets.clear();
|
||||
return(xml_doc);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,9 @@ class QETProject : public QObject
|
||||
void buildFoliosHolding(ElementData::Types kinds, bool free_only);
|
||||
void buildFoliosHoldingSymbols(const QSet<QUuid> &symbols);
|
||||
QSet<QUuid> symbolsOnUnbuiltFolios() const;
|
||||
/// While saving: the symbols on folios not built a built symbol
|
||||
/// may be saved linked to (Element::toXml())
|
||||
QSet<QUuid> waitingLinkTargets() const {return m_waiting_link_targets;}
|
||||
QSet<Diagram *> tableChainFolios(Diagram *folio) const;
|
||||
void loadFolios() const;
|
||||
void buildFolios(const QList<Diagram *> &folios) const;
|
||||
@@ -540,6 +543,7 @@ class QETProject : public QObject
|
||||
/// Saving a .qetz may copy the part of a folio not built
|
||||
/// (toXml(), stage D4)
|
||||
bool m_kept_parts_trusted = false;
|
||||
QSet<QUuid> m_waiting_link_targets;
|
||||
QHash<QString, QByteArray> m_container_files;
|
||||
QStringList m_folio_files;
|
||||
QList<std::pair<QUuid, QString>> m_folio_headers;
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "../../sources/qetgraphicsitem/element.h"
|
||||
#include "../../sources/autoNum/elementautonumschemecommand.h"
|
||||
#include "../../sources/elementprovider.h"
|
||||
#include "../../sources/container/qetzip.h"
|
||||
#include <QSqlDatabase>
|
||||
#include <QMap>
|
||||
#include "../../sources/TerminalStrip/terminalstrip.h"
|
||||
#include "../../sources/ui/elementpropertieswidget.h"
|
||||
#include "../../sources/conductorautonumerotation.h"
|
||||
@@ -193,6 +196,38 @@ static QStringList sortedLines(QString xml, const QString &path)
|
||||
return list;
|
||||
}
|
||||
|
||||
//The saved links of a .qetz, symbol by symbol in their order: what a
|
||||
//symbol saves of its partners, as its file holds it
|
||||
static QStringList savedLinks(const QString &qetz, const QString &path)
|
||||
{
|
||||
QFile file(qetz); file.open(QIODevice::ReadOnly);
|
||||
QList<QetZip::Entry> entries;
|
||||
QString error;
|
||||
check(QetZip::fromBytes(file.readAll(), &entries, &error), "a .qetz read");
|
||||
QTemporaryDir dir;
|
||||
const QString db_path = dir.filePath(QStringLiteral("project.sqlite"));
|
||||
for (const QetZip::Entry &entry : entries)
|
||||
if (entry.name == QLatin1String("project.sqlite")) {
|
||||
QFile db(db_path); db.open(QIODevice::WriteOnly); db.write(entry.data);
|
||||
}
|
||||
QMap<QString, QStringList> links; //symbol -> its partners in order
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), QStringLiteral("saved_links"));
|
||||
db.setDatabaseName(db_path);
|
||||
check(db.open(), "a .qetz's database opened");
|
||||
QSqlQuery query(db);
|
||||
check(query.exec(QStringLiteral("SELECT element_key, linked_uuid FROM doc_link ORDER BY element_key, ord")),
|
||||
"saved links read");
|
||||
while (query.next())
|
||||
links[query.value(0).toString()] << query.value(1).toString();
|
||||
}
|
||||
QSqlDatabase::removeDatabase(QStringLiteral("saved_links"));
|
||||
QStringList rows;
|
||||
for (auto it = links.cbegin() ; it != links.cend() ; ++it)
|
||||
rows << it.key() + QStringLiteral(": ") + it.value().join(QLatin1Char(','));
|
||||
return sortedLines(rows.join(QLatin1Char('\n')), path);
|
||||
}
|
||||
|
||||
//The rows of the project database's tables, in their order, read as
|
||||
//every caller reads them (newQuery(): brought up to date first)
|
||||
static QStringList tables(QETProject &project)
|
||||
@@ -680,6 +715,10 @@ int main(int argc, char **argv)
|
||||
qputenv("QET_LAZY_FOLIOS", "1");
|
||||
check(sortedLines(edited_back.toXml().toString(), path) == sortedLines(usual_back.toXml().toString(), path),
|
||||
"an edited .qetz saved without building holds what the edits made");
|
||||
//Each symbol's links as saved, partners on folios not built
|
||||
//included, in their order (D5a)
|
||||
check(savedLinks(edited_path, path) == savedLinks(usual_path, path),
|
||||
"an edited .qetz saved without building keeps every symbol's links");
|
||||
}
|
||||
std::printf("PASS: %d folios\n", int(folios.size()));
|
||||
} catch (const std::exception &error) {
|
||||
|
||||
Reference in New Issue
Block a user