diff --git a/sources/container/qetcontainer.cpp b/sources/container/qetcontainer.cpp index 19a7615b6..79050a8cd 100644 --- a/sources/container/qetcontainer.cpp +++ b/sources/container/qetcontainer.cpp @@ -19,6 +19,7 @@ #include "qetcontainerdb.h" #include +#include #include #include #include @@ -242,6 +243,28 @@ bool QetContainer::ownUuids(const QDomElement &project) return true; } +/** + @brief QetContainer::embeddedDefinitions + @return the paths of the symbol definitions the project @p project + holds in its collection, as a symbol's type names them after embed:// +*/ +QSet QetContainer::embeddedDefinitions(const QDomElement &project) +{ + QSet paths; + std::function walk = + [&](const QDomElement &category, const QString &path) { + for (QDomElement child = category.firstChildElement() ; !child.isNull() ; + child = child.nextSiblingElement()) { + const QString name = path + child.attribute(QStringLiteral("name")); + if (child.tagName() == QLatin1String("category")) walk(child, name + QLatin1Char('/')); + else if (child.tagName() == QLatin1String("element")) paths.insert(name); + } + }; + for (const QDomElement &collection : childElements(project, QStringLiteral("collection"))) + walk(collection, QString()); + return paths; +} + /** @brief QetContainer::dropComputed Take out of the folio @p diagram what QElectroTech computes when it @@ -253,19 +276,39 @@ bool QetContainer::ownUuids(const QDomElement &project) list of its terminals. Checked on 342 projects: opened and saved, each comes back as it was, but the terminal lists of a file whose symbols share a uuid (F100), where wires find their ends by them. + Nothing is taken from a symbol whose definition is not among + @p defined (embeddedDefinitions()), nor from a wire ending on one: + QElectroTech cannot build that symbol, keeps it as read and saves it + back (F127), so nothing of it would be computed again. */ -void QetContainer::dropComputed(QDomElement diagram, bool terminal_lists) +void QetContainer::dropComputed(QDomElement diagram, bool terminal_lists, + const QSet &defined) { + QSet undefined; + for (const QDomElement &list : childElements(diagram, QStringLiteral("elements"))) + for (const QDomElement &element : childElements(list, QStringLiteral("element"))) { + const QString type = element.attribute(QStringLiteral("type")); + if (!type.startsWith(QLatin1String("embed://")) + || !defined.contains(type.mid(int(qstrlen("embed://"))))) + undefined.insert(element.attribute(QStringLiteral("uuid"))); + } for (QDomElement list : childElements(diagram, QStringLiteral("conductors"))) for (QDomElement wire : childElements(list, QStringLiteral("conductor"))) + { + if (undefined.contains(wire.attribute(QStringLiteral("element1"))) + || undefined.contains(wire.attribute(QStringLiteral("element2")))) + continue; for (const char *end : {"1", "2"}) for (const char *name : {"element%1_label", "element%1_name", "element%1_linked", "terminalname%1"}) wire.removeAttribute(QString::fromLatin1(name).arg(QLatin1String(end))); + } for (QDomElement list : childElements(diagram, QStringLiteral("elements"))) { for (QDomElement element : childElements(list, QStringLiteral("element"))) { + if (undefined.contains(element.attribute(QStringLiteral("uuid")))) + continue; if (terminal_lists) for (QDomElement terminals : childElements(element, QStringLiteral("terminals"))) removeElement(terminals); @@ -341,8 +384,9 @@ QList QetContainer::split(const QDomDocument &project, const QStr int folio = 0; //Nothing QElectroTech computes is kept (format 4) const bool own_uuids = ownUuids(root); + const QSet defined = embeddedDefinitions(root); for (QDomElement diagram : childElements(root, QStringLiteral("diagram"))) - dropComputed(diagram, own_uuids); + dropComputed(diagram, own_uuids, defined); //The parts of the folios kept as they were, and their pictures QMap pictures; //name -> png, once each diff --git a/sources/container/qetcontainer.h b/sources/container/qetcontainer.h index bdfd37c55..c9f936317 100644 --- a/sources/container/qetcontainer.h +++ b/sources/container/qetcontainer.h @@ -89,7 +89,9 @@ namespace QetContainer void inlinePicture(QDomElement image, const QByteArray &bytes); /// Take what QElectroTech computes out of a folio (format 4) - void dropComputed(QDomElement diagram, bool terminal_lists); + void dropComputed(QDomElement diagram, bool terminal_lists, const QSet &defined); + /// The symbol definitions a project holds, by path after embed:// + QSet embeddedDefinitions(const QDomElement &project); /// true if every folio, symbol and wire has a uuid of its own bool ownUuids(const QDomElement &project); /// Parse @p xml as a .qet is read (QETProject::openFile) diff --git a/tests/qttest/tst_qetcontainer.cpp b/tests/qttest/tst_qetcontainer.cpp index 92a5b2c64..08cddd408 100644 --- a/tests/qttest/tst_qetcontainer.cpp +++ b/tests/qttest/tst_qetcontainer.cpp @@ -77,9 +77,10 @@ class tst_qetcontainer : public QObject { QDomDocument copy = document.cloneNode(true).toDocument(); const bool own_uuids = QetContainer::ownUuids(copy.documentElement()); + const QSet defined = QetContainer::embeddedDefinitions(copy.documentElement()); for (QDomElement diagram = copy.documentElement().firstChildElement(QStringLiteral("diagram")); !diagram.isNull() ; diagram = diagram.nextSiblingElement(QStringLiteral("diagram"))) - QetContainer::dropComputed(diagram, own_uuids); + QetContainer::dropComputed(diagram, own_uuids, defined); return copy; }