mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-19 20:44:16 +02:00
Merge pull request #1522 from ispyisail/fix/shared-symbol-uuid-renew
Fix symbols sharing a uuid: give each copy its own when a project opens
This commit is contained in:
@@ -2342,6 +2342,23 @@ bool Diagram::fromXml(QDomElement &document,
|
||||
<< "wire end(s) on a terminal that moved since the project was saved,"
|
||||
<< "matched to it by place";
|
||||
}
|
||||
//A copy of a symbol sharing its uuid with another (older versions'
|
||||
//copies, F100) gets its own, now that its wires are connected to
|
||||
//it: wires and links then name one symbol each
|
||||
//(QETProject::renewedSharedUuid(), only while the project opens)
|
||||
if (consider_informations && m_project) {
|
||||
const int folio_index = m_project->folioIndex(this);
|
||||
QHash<QUuid, int> ordinal;
|
||||
for (Element *element : std::as_const(added_elements)) {
|
||||
const QUuid shared = element->uuid();
|
||||
const QUuid renewed = m_project->renewedSharedUuid(folio_index, ordinal[shared]++,
|
||||
shared, uuid());
|
||||
if (!renewed.isNull()) {
|
||||
element->setUuid(renewed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (consider_informations && !m_wires_not_reconnected.isEmpty()) {
|
||||
qWarning().noquote() << "Diagram::fromXml():"
|
||||
<< m_wires_not_reconnected.size()
|
||||
|
||||
+58
-1
@@ -299,6 +299,27 @@ QByteArray QETProject::containerPicture(const QString &file) const
|
||||
return m_container_pictures.value(file);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::renewedSharedUuid
|
||||
While the project opens: the uuid of the @p ordinal -th symbol carrying
|
||||
@p uuid on the folio at @p folio_index (in the file's order), when
|
||||
other symbols of the project carry the same uuid and this copy is not
|
||||
the one keeping it (readDiagramsXml()). Derived from the uuid and the
|
||||
folio's uuid, so the same file gives the same uuid on every open.
|
||||
@return a null uuid when this symbol keeps its uuid
|
||||
*/
|
||||
QUuid QETProject::renewedSharedUuid(int folio_index, int ordinal, const QUuid &uuid,
|
||||
const QUuid &folio_uuid)
|
||||
{
|
||||
const auto keeper = m_shared_uuid_keepers.constFind(uuid);
|
||||
if (keeper == m_shared_uuid_keepers.constEnd()
|
||||
|| (keeper->first == folio_index && keeper->second == ordinal)) {
|
||||
return QUuid();
|
||||
}
|
||||
return derivedItemUuid(QStringLiteral("element-copy"),
|
||||
uuid.toString() + QLatin1Char('\n') + folio_uuid.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::derivedItemUuid
|
||||
A uuid for an item of this project that was saved without one, the same
|
||||
@@ -3664,6 +3685,41 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
}
|
||||
}
|
||||
|
||||
//Symbols sharing a uuid (copies made by older versions, F100): the
|
||||
//project database, links and wires name a symbol by its uuid, so
|
||||
//each copy but one gets its own (renewedSharedUuid()). The copy
|
||||
//that keeps it is the first one linked to another symbol (a
|
||||
//partner's link names the uuid), else the first. The folios with
|
||||
//a copy to renew are built now, also with lazy folios, so the
|
||||
//whole project has one uuid per symbol from the start.
|
||||
m_shared_uuid_keepers.clear();
|
||||
QSet<int> build_now;
|
||||
{
|
||||
QHash<QUuid, QList<std::tuple<int, int, bool>>> copies;
|
||||
for (int i = 0 ; i < diagram_nodes.length() ; ++i) {
|
||||
const QDomElement elements = diagram_nodes.at(i).toElement()
|
||||
.firstChildElement(QStringLiteral("elements"));
|
||||
QHash<QUuid, int> ordinal;
|
||||
for (QDomElement e = elements.firstChildElement(QStringLiteral("element"));
|
||||
!e.isNull() ; e = e.nextSiblingElement(QStringLiteral("element"))) {
|
||||
const QUuid uuid(e.attribute(QStringLiteral("uuid")));
|
||||
if (uuid.isNull()) continue;
|
||||
const bool linked = !e.firstChildElement(QStringLiteral("links_uuids"))
|
||||
.firstChildElement(QStringLiteral("link_uuid")).isNull();
|
||||
copies[uuid].append({i, ordinal[uuid]++, linked});
|
||||
}
|
||||
}
|
||||
for (auto it = copies.cbegin() ; it != copies.cend() ; ++it) {
|
||||
if (it.value().size() < 2) continue;
|
||||
auto keeper = it.value().first();
|
||||
for (const auto © : it.value())
|
||||
if (std::get<2>(copy)) { keeper = copy; break; }
|
||||
m_shared_uuid_keepers.insert(it.key(), {std::get<0>(keeper), std::get<1>(keeper)});
|
||||
for (const auto © : it.value())
|
||||
if (copy != keeper) build_now.insert(std::get<0>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
if(dlgWaiting)
|
||||
dlgWaiting->setProgressBarRange(0, diagram_nodes.length()*3);
|
||||
|
||||
@@ -3717,7 +3773,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
connect(diagram, &Diagram::usedTitleBlockTemplateChanged,
|
||||
this, &QETProject::usedTitleBlockTemplateChanged);
|
||||
|
||||
m_deferring_folios = m_lazy_open;
|
||||
m_deferring_folios = m_lazy_open && !build_now.contains(i);
|
||||
diagram->initFromXml(diagram_xml_element);
|
||||
m_deferring_folios = false;
|
||||
if (!diagram->isLoaded() && !line_starts.isEmpty())
|
||||
@@ -3730,6 +3786,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
}
|
||||
}
|
||||
|
||||
m_shared_uuid_keepers.clear();
|
||||
updateDiagramsFolioData();
|
||||
|
||||
//Initialise links between elements in this project
|
||||
|
||||
@@ -123,6 +123,8 @@ class QETProject : public QObject
|
||||
projectDataBase *dataBase();
|
||||
QUuid uuid() const;
|
||||
QUuid derivedItemUuid(const QString &kind, const QString &key);
|
||||
QUuid renewedSharedUuid(int folio_index, int ordinal, const QUuid &uuid,
|
||||
const QUuid &folio_uuid);
|
||||
QByteArray containerPicture(const QString &file) const;
|
||||
ProjectState state() const;
|
||||
QString openError() const;
|
||||
@@ -615,7 +617,11 @@ class QETProject : public QObject
|
||||
int m_next_backup_slot = 0;
|
||||
QUuid m_uuid = QUuid::createUuid();
|
||||
QHash<QString, int> m_derived_uuid_keys;
|
||||
QSet<QUuid> m_saved_item_uuids; //symbol and wire uuids the file carries, see derivedItemUuid()
|
||||
QSet<QUuid> m_saved_item_uuids;
|
||||
/// While opening: per uuid carried by several symbols, the copy
|
||||
/// keeping it (folio index, ordinal on that folio), see
|
||||
/// renewedSharedUuid()
|
||||
QHash<QUuid, std::pair<int, int>> m_shared_uuid_keepers; //symbol and wire uuids the file carries, see derivedItemUuid()
|
||||
projectDataBase m_data_base;
|
||||
QVector<TerminalStrip *> m_terminal_strip_vector;
|
||||
QVector<Cable *> m_cables;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <QtTest>
|
||||
#include <QSet>
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
@@ -150,13 +151,66 @@ private slots:
|
||||
QVERIFY(!twice.isEmpty());
|
||||
QCOMPARE(nets(twice), expected);
|
||||
|
||||
//No wire names a lamp by the uuid they share
|
||||
for (const QDomElement &c : childElements(firstDiagram(load(twice)),
|
||||
QStringLiteral("conductors"),
|
||||
QStringLiteral("conductor"))) {
|
||||
QVERIFY(c.attribute(QStringLiteral("element1")) != shared);
|
||||
QVERIFY(c.attribute(QStringLiteral("element2")) != shared);
|
||||
//Each lamp has a uuid of its own after a save: one keeps the
|
||||
//shared uuid, the others get one derived from it
|
||||
QSet<QString> uuids;
|
||||
for (const QDomElement &e : lamps(load(twice)))
|
||||
uuids.insert(e.attribute(QStringLiteral("uuid")));
|
||||
QCOMPARE(uuids.size(), 3);
|
||||
QVERIFY(uuids.contains(shared));
|
||||
}
|
||||
|
||||
// A linked contact and an unlinked symbol carrying the same uuid (a copy
|
||||
// made by an older version): the linked one keeps the uuid, the other
|
||||
// gets its own, and every link and wire stays where it was.
|
||||
void linkedCopyKeepsUuid()
|
||||
{
|
||||
const QString source = QStringLiteral(QET_EXAMPLES_DIR "/affuteuse_250h.qet");
|
||||
QDomDocument doc = load(source);
|
||||
QList<QDomElement> all;
|
||||
const QDomNodeList folios = doc.documentElement().elementsByTagName(QStringLiteral("diagram"));
|
||||
for (int i = 0; i < folios.size(); ++i)
|
||||
all << childElements(folios.at(i).toElement(), QStringLiteral("elements"),
|
||||
QStringLiteral("element"));
|
||||
auto linked = [](const QDomElement &e) {
|
||||
return !e.firstChildElement(QStringLiteral("links_uuids"))
|
||||
.firstChildElement(QStringLiteral("link_uuid")).isNull();
|
||||
};
|
||||
QDomElement keeper, copy;
|
||||
for (const QDomElement &e : std::as_const(all)) {
|
||||
if (keeper.isNull() && linked(e)) keeper = e;
|
||||
else if (copy.isNull() && !linked(e)) copy = e;
|
||||
}
|
||||
QVERIFY(!keeper.isNull() && !copy.isNull());
|
||||
const QString shared = keeper.attribute(QStringLiteral("uuid"));
|
||||
copy.setAttribute(QStringLiteral("uuid"), shared);
|
||||
const int wires = doc.elementsByTagName(QStringLiteral("conductor")).size();
|
||||
|
||||
const QString saved = resave(write(doc));
|
||||
QVERIFY(!saved.isEmpty());
|
||||
const QDomDocument out = load(saved);
|
||||
QHash<QString, QDomElement> by_uuid;
|
||||
QList<std::pair<QString, QString>> links;
|
||||
const QDomNodeList saved_folios = out.documentElement().elementsByTagName(QStringLiteral("diagram"));
|
||||
for (int i = 0; i < saved_folios.size(); ++i)
|
||||
for (const QDomElement &e : childElements(saved_folios.at(i).toElement(),
|
||||
QStringLiteral("elements"),
|
||||
QStringLiteral("element"))) {
|
||||
const QString u = e.attribute(QStringLiteral("uuid"));
|
||||
QVERIFY2(!by_uuid.contains(u), qPrintable(QStringLiteral("uuid still shared: ") + u));
|
||||
by_uuid.insert(u, e);
|
||||
for (QDomElement l = e.firstChildElement(QStringLiteral("links_uuids"))
|
||||
.firstChildElement(QStringLiteral("link_uuid"));
|
||||
!l.isNull(); l = l.nextSiblingElement(QStringLiteral("link_uuid")))
|
||||
links.append({u, l.attribute(QStringLiteral("uuid"))});
|
||||
}
|
||||
QVERIFY(by_uuid.contains(shared));
|
||||
QVERIFY(linked(by_uuid.value(shared)));
|
||||
for (const auto &link : std::as_const(links)) {
|
||||
QVERIFY2(by_uuid.contains(link.second), "a link names a symbol not in the project");
|
||||
QVERIFY2(links.contains(std::make_pair(link.second, link.first)), "a link only one side has");
|
||||
}
|
||||
QCOMPARE(out.elementsByTagName(QStringLiteral("conductor")).size(), wires);
|
||||
}
|
||||
|
||||
void savedByUuidReopensRight()
|
||||
|
||||
Reference in New Issue
Block a user