mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-15 01:54:14 +02:00
Export the wiring list without building every folio (stage D5)
The wiring list export read the project as QETProject::toXml() writes it, which builds every folio. It now reads a document made without building: a built folio written as saving writes it (QETProject::folioXml(), which keeps its symbols' links to partners not built), a folio not built copied from its XML, and what QElectroTech computes for a wire's ends -- its symbols' labels, their last partner's label, the terminals' names -- filled in from the symbols built and from the project database. A symbol still waiting for a partner not built takes its partners from the database, saved order. 136-folio .qetz, wiring list from the command line: 30.1 s with every folio built, 4.5 s lazily, same file. tst_lazyfolios: the wiring list of a .qet and of a .qetz as when built, building no folio. New corpus gate (it fails on all 6 projects tried with terminal names broken): --export-cables and --export-wires lazily from the .qet and the .qetz = eager on 342 projects; one (forum f3386) differed until waiting symbols took their partners from the database. ctest 96/96 eager and lazy (one earlier run had modal_quit_regression and tst_resaveunchanged fail once each, both passing on rerun in both modes); 342 corpus projects save the same in all four arms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1289,6 +1289,34 @@ QList<projectDataBase::FolioWire> projectDataBase::wiresOnFolios(const QList<QUu
|
||||
return wires;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::elementLabel
|
||||
@return the label the symbol @p element shows, read from the element
|
||||
info table as it is (see elementTypesOnFolios())
|
||||
*/
|
||||
QString projectDataBase::elementLabel(const QUuid &element) const
|
||||
{
|
||||
QSqlQuery query(m_data_base);
|
||||
query.prepare(QStringLiteral("SELECT label FROM element_info WHERE element_uuid = :uuid"));
|
||||
query.bindValue(QStringLiteral(":uuid"), element.toString());
|
||||
return query.exec() && query.next() ? query.value(0).toString() : QString();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::terminalName
|
||||
@return the name of the terminal @p terminal of the symbol @p element,
|
||||
read from the terminal table as it is (see elementTypesOnFolios()): a
|
||||
terminal a wire ends on has a row
|
||||
*/
|
||||
QString projectDataBase::terminalName(const QUuid &terminal, const QUuid &element) const
|
||||
{
|
||||
QSqlQuery query(m_data_base);
|
||||
query.prepare(QStringLiteral("SELECT name FROM terminal WHERE uuid = :uuid AND element_uuid = :element"));
|
||||
query.bindValue(QStringLiteral(":uuid"), terminal.toString());
|
||||
query.bindValue(QStringLiteral(":element"), element.toString());
|
||||
return query.exec() && query.next() ? query.value(0).toString() : QString();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::linkedSymbols
|
||||
@return the symbols @p element is linked to, read from the link table
|
||||
|
||||
@@ -195,6 +195,8 @@ class projectDataBase : public QObject
|
||||
/// symbols at its ends (ElementData::typeToString())
|
||||
struct FolioWire { QString text; QString kind1; QString kind2; };
|
||||
QList<FolioWire> wiresOnFolios(const QList<QUuid> &folios) const;
|
||||
QString elementLabel(const QUuid &element) const;
|
||||
QString terminalName(const QUuid &terminal, const QUuid &element) const;
|
||||
static QVariant sequenceValue(const autonum::sequentialNumbers &sequence);
|
||||
static autonum::sequentialNumbers sequenceFromValue(const QVariant &value);
|
||||
|
||||
|
||||
@@ -229,6 +229,8 @@ class Diagram : public QGraphicsScene
|
||||
/// Symbols built as partners (buildSymbols()) changed since:
|
||||
/// the folio must be built to be saved
|
||||
bool partialChanged() const {return m_partial_changed;}
|
||||
/// The symbols built as partners (buildSymbols()), by uuid
|
||||
QHash<QUuid, Element *> partialElements() const {return m_partial_elements;}
|
||||
QString headerXml();
|
||||
/// The folio's text in the file it was read from, while it is
|
||||
/// not built (QETProject::toXml())
|
||||
|
||||
@@ -2978,6 +2978,20 @@ bool QETProject::usesElement(const ElementsLocation &location) const
|
||||
return(unbuiltFolioElements().contains(location));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::folioXml
|
||||
@return the built folio @p folio written as saving writes it: its
|
||||
symbols keep the links to partners on folios not built yet
|
||||
(QET_LAZY_FOLIOS), which Diagram::toXml() alone leaves out
|
||||
*/
|
||||
QDomDocument QETProject::folioXml(Diagram *folio)
|
||||
{
|
||||
m_waiting_link_targets = unloadedFolioCount() ? symbolsOnUnbuiltFolios() : QSet<QUuid>();
|
||||
const QDomDocument xml = folio->toXml();
|
||||
m_waiting_link_targets.clear();
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::buildFoliosHoldingTables
|
||||
Build the folios not built yet (QET_LAZY_FOLIOS) that hold a drawn
|
||||
|
||||
@@ -140,6 +140,7 @@ class QETProject : public QObject
|
||||
/// 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;}
|
||||
QDomDocument folioXml(Diagram *folio);
|
||||
QSet<Diagram *> tableChainFolios(Diagram *folio) const;
|
||||
void loadFolios() const;
|
||||
void buildFolios(const QList<Diagram *> &folios) const;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "wiringlistexport.h"
|
||||
#include "qetproject.h"
|
||||
#include "diagram.h"
|
||||
#include "dataBase/projectdatabase.h"
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
@@ -48,6 +51,89 @@ QDomElement WiringListExport::climbToDiagram(QDomNode node) const
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
/**
|
||||
The project as the export reads it: its symbol collection and its folios
|
||||
in order, each with its "order". A folio not built (QET_LAZY_FOLIOS) is
|
||||
not built for it: its XML is copied, and what QElectroTech computes for
|
||||
its wires' ends -- the labels of the symbols they end on and of their
|
||||
partners, the terminals' names -- is filled in from the symbols built
|
||||
(on built folios or alone, as partners) and from the project database.
|
||||
*/
|
||||
QDomDocument WiringListExport::projectDocument() const
|
||||
{
|
||||
QDomDocument document;
|
||||
QDomElement root = document.createElement(QStringLiteral("project"));
|
||||
document.appendChild(root);
|
||||
if (XmlElementCollection *collection = m_project->embeddedElementCollection())
|
||||
root.appendChild(document.importNode(collection->root(), true));
|
||||
|
||||
//A folio whose partners built alone were linked or unlinked since
|
||||
//is not what its XML says: built, as saving builds it
|
||||
for (Diagram *diagram : m_project->folios())
|
||||
if (!diagram->isLoaded() && diagram->partialChanged())
|
||||
m_project->buildFolios({diagram});
|
||||
|
||||
QHash<QUuid, Element *> built;
|
||||
for (Diagram *diagram : m_project->folios()) {
|
||||
if (diagram->isLoaded()) {
|
||||
for (Element *element : diagram->elements()) built.insert(element->uuid(), element);
|
||||
} else {
|
||||
const QHash<QUuid, Element *> partial = diagram->partialElements();
|
||||
for (auto it = partial.cbegin() ; it != partial.cend() ; ++it) built.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
projectDataBase *database = m_project->dataBase();
|
||||
auto label = [&built, database](const QUuid &uuid) {
|
||||
Element *element = built.value(uuid);
|
||||
return element ? element->actualLabel() : database->elementLabel(uuid);
|
||||
};
|
||||
//Conductor::toXml(): the label of the last of the symbol's partners.
|
||||
//A symbol still waiting for a partner not built has its links as
|
||||
//saved, in the database
|
||||
auto linked = [&built, database, &label](const QUuid &uuid) -> std::optional<QString> {
|
||||
Element *element = built.value(uuid);
|
||||
if (element && element->pendingLinks().isEmpty()) {
|
||||
if (element->linkedElements().isEmpty()) return std::nullopt;
|
||||
return element->linkedElements().last()->actualLabel();
|
||||
}
|
||||
const QList<QUuid> links = database->linkedSymbols(uuid);
|
||||
if (links.isEmpty()) return std::nullopt;
|
||||
return label(links.last());
|
||||
};
|
||||
|
||||
const QList<Diagram *> folios = m_project->folios();
|
||||
for (int i = 0 ; i < folios.size() ; ++i) {
|
||||
Diagram *diagram = folios.at(i);
|
||||
QDomElement folio;
|
||||
const bool is_built = diagram->isLoaded();
|
||||
folio = document.importNode(is_built ? m_project->folioXml(diagram).documentElement()
|
||||
: diagram->deferredXml(), true).toElement();
|
||||
//A built folio's wires describe their ends but a partner not
|
||||
//built yet; a folio not built has none of it in its part (.qetz)
|
||||
//or as read, before any change (.qet)
|
||||
QDomNodeList wires = folio.elementsByTagName(QStringLiteral("conductor"));
|
||||
for (int w = 0 ; w < wires.size() ; ++w) {
|
||||
QDomElement wire = wires.at(w).toElement();
|
||||
for (const QString end : {QStringLiteral("1"), QStringLiteral("2")}) {
|
||||
const QUuid element(wire.attribute(QStringLiteral("element") + end));
|
||||
if (element.isNull()) continue; //an end saved the older way
|
||||
if (const auto partner = linked(element))
|
||||
wire.setAttribute(QStringLiteral("element") + end + QStringLiteral("_linked"), *partner);
|
||||
else
|
||||
wire.removeAttribute(QStringLiteral("element") + end + QStringLiteral("_linked"));
|
||||
if (is_built) continue;
|
||||
wire.setAttribute(QStringLiteral("element") + end + QStringLiteral("_label"), label(element));
|
||||
wire.setAttribute(QStringLiteral("terminalname") + end,
|
||||
database->terminalName(QUuid(wire.attribute(QStringLiteral("terminal") + end)),
|
||||
element));
|
||||
}
|
||||
}
|
||||
folio.setAttribute(QStringLiteral("order"), i + 1);
|
||||
root.appendChild(folio);
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
QMap<QString, ElementInfo> WiringListExport::collectElementsInfo(const QDomElement &root) const
|
||||
{
|
||||
QMap<QString, ElementInfo> infoMap;
|
||||
@@ -191,7 +277,7 @@ QString WiringListExport::toCsvString() const
|
||||
{
|
||||
if (!m_project) return QString();
|
||||
|
||||
QDomDocument doc = m_project->toXml();
|
||||
QDomDocument doc = projectDocument();
|
||||
if (doc.isNull()) return QString();
|
||||
|
||||
QSet<QString> conductorDefinitionTypes;
|
||||
|
||||
@@ -60,6 +60,7 @@ private:
|
||||
QString normalizeUuid(const QString &u) const;
|
||||
QString findDiagramFolio(const QDomElement &diagramElem) const;
|
||||
QDomElement climbToDiagram(QDomNode node) const;
|
||||
QDomDocument projectDocument() const;
|
||||
|
||||
QMap<QString, ElementInfo> collectElementsInfo(const QDomElement &root) const;
|
||||
QList<ConductorData> collectConductors(const QDomElement &root) const;
|
||||
|
||||
@@ -385,8 +385,16 @@ int main(int argc, char **argv)
|
||||
QETProject exported(path);
|
||||
check(ConductorNumExport(&exported).wiresNum() == ConductorNumExport(&eager).wiresNum(),
|
||||
"wire numbers of a .qet exported as when built");
|
||||
const QString wiring = WiringListExport(&exported).toCsvString(), usual_wiring = WiringListExport(&eager).toCsvString();
|
||||
if (wiring != usual_wiring) {
|
||||
const QStringList a = wiring.split('\n'), b = usual_wiring.split('\n');
|
||||
for (const QString &line : b) if (!a.contains(line)) std::printf(" wiring when built: %s\n", qPrintable(line));
|
||||
for (const QString &line : a) if (!b.contains(line)) std::printf(" wiring lazily: %s\n", qPrintable(line));
|
||||
std::printf(" %d lines lazily, %d when built\n", int(a.size()), int(b.size()));
|
||||
}
|
||||
check(wiring == usual_wiring, "wiring list of a .qet exported as when built");
|
||||
check(exported.unloadedFolioCount() == folios.size() - strip_folios.size(),
|
||||
"exporting a .qet's wire numbers builds no folio");
|
||||
"exporting a .qet's wire numbers and wiring list builds no folio");
|
||||
}
|
||||
//A symbol placed on a folio, numbered by a scheme others follow
|
||||
QString location, title;
|
||||
@@ -707,13 +715,6 @@ int main(int argc, char **argv)
|
||||
++continued;
|
||||
}
|
||||
check(continued > 0, "a folio whose table continues another");
|
||||
{
|
||||
//The wiring list export writes the whole project out
|
||||
//(toXml()), building every folio: as when built
|
||||
QETProject exported(zipped);
|
||||
check(WiringListExport(&exported).toCsvString() == WiringListExport(&eager).toCsvString(),
|
||||
"wiring list exported as when built");
|
||||
}
|
||||
|
||||
//Numbering, the searches for symbols and the unused symbols
|
||||
//are answered from the database: no folio file is read
|
||||
@@ -799,7 +800,7 @@ int main(int argc, char **argv)
|
||||
check(listed.unloadedFolioCount() > 0, "listing the tables does not build every folio");
|
||||
}
|
||||
|
||||
//The wire numbers export and the terminal
|
||||
//The wire numbers and wiring list exports, and the terminal
|
||||
//numbering dialog: as when built, building only the folios
|
||||
//holding a terminal (D5)
|
||||
{
|
||||
@@ -807,7 +808,14 @@ int main(int argc, char **argv)
|
||||
const int unbuilt = exported.unloadedFolioCount();
|
||||
check(ConductorNumExport(&exported).wiresNum() == ConductorNumExport(&eager).wiresNum(),
|
||||
"wire numbers exported as when built");
|
||||
check(exported.unloadedFolioCount() == unbuilt, "exporting wire numbers builds no folio");
|
||||
const QString wiring = WiringListExport(&exported).toCsvString(), usual_wiring = WiringListExport(&eager).toCsvString();
|
||||
if (wiring != usual_wiring) {
|
||||
const QStringList a = wiring.split('\n'), b = usual_wiring.split('\n');
|
||||
for (const QString &line : b) if (!a.contains(line)) std::printf(" wiring when built: %s\n", qPrintable(line));
|
||||
for (const QString &line : a) if (!b.contains(line)) std::printf(" wiring lazily: %s\n", qPrintable(line));
|
||||
}
|
||||
check(wiring == usual_wiring, "wiring list exported as when built");
|
||||
check(exported.unloadedFolioCount() == unbuilt, "exporting wire numbers and the wiring list builds no folio");
|
||||
{ TerminalNumberingDialog dialog(nullptr, &exported); }
|
||||
int with_terminals = 0;
|
||||
for (Diagram *folio : folios)
|
||||
|
||||
Reference in New Issue
Block a user