mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-29 05:44:14 +02:00
Never derive a uuid the file already carries
A symbol keeps its derived uuid once saved, even when it is moved. A symbol saved without a uuid that later turns up on the spot it left -- a hand edit, an older version, another tool writing the file -- derived the same uuid, and the project had two symbols with one identity. readDiagramsXml() now collects every symbol and wire uuid the file carries, on any folio, before a folio loads; derivedItemUuid() moves to the next counter value while a candidate is among them. The result still depends on the file alone. Renamed from derivedUuid(), which QETProject already has for the project's own uuid. tst_derivedsymboluuid: newcomerOnAMovedSymbolsSpotGetsAnotherUuid fails with the check switched off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1685,7 +1685,7 @@ bool Diagram::fromXml(QDomElement &document,
|
||||
//uuids anyway.
|
||||
if (consider_informations && m_project
|
||||
&& QUuid(element_xml.attribute(QStringLiteral("uuid"))).isNull()) {
|
||||
nvel_elmt->setUuid(m_project->derivedUuid(
|
||||
nvel_elmt->setUuid(m_project->derivedItemUuid(
|
||||
QStringLiteral("element"),
|
||||
QStringList{type_id,
|
||||
element_xml.attribute(QStringLiteral("x")),
|
||||
|
||||
+32
-5
@@ -276,7 +276,7 @@ QUuid QETProject::uuid() const
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::derivedUuid
|
||||
@brief QETProject::derivedItemUuid
|
||||
A uuid for an item of this project that was saved without one, the same
|
||||
on every load of the same file.
|
||||
@p key describes the item by what it is, never by its place in the file
|
||||
@@ -284,16 +284,31 @@ QUuid QETProject::uuid() const
|
||||
Items with the same @p kind and @p key anywhere in the project (a copied
|
||||
folio, two identical symbols stacked on one spot) are told apart by a
|
||||
counter, in load order among those items alone.
|
||||
|
||||
A derived uuid is never one the file already carries: an item saved with
|
||||
a derived uuid and then moved or re-connected keeps it, so a newcomer
|
||||
later taking its old place or ends would otherwise derive the same one.
|
||||
The file's saved uuids are collected before any folio loads
|
||||
(readDiagramsXml()), so the result still depends on the file alone.
|
||||
|
||||
uuids are unique within one project; copies of a project share them, as
|
||||
they share every saved uuid. Anything bringing items in from another
|
||||
project must renew them, as paste does.
|
||||
@return a UUID v5, which cannot collide with the v4 uuids given to new
|
||||
items
|
||||
*/
|
||||
QUuid QETProject::derivedUuid(const QString &kind, const QString &key)
|
||||
QUuid QETProject::derivedItemUuid(const QString &kind, const QString &key)
|
||||
{
|
||||
static const QUuid derived_ns(QStringLiteral("{7d1e9c3a-5b2f-4e8a-9c61-2f4b8d0e6a17}"));
|
||||
const QString full = kind + QLatin1Char('\n') + key;
|
||||
const int n = m_derived_uuid_keys[full]++;
|
||||
return QUuid::createUuidV5(derived_ns,
|
||||
n ? full + QLatin1Char('\n') + QString::number(n) : full);
|
||||
int &n = m_derived_uuid_keys[full];
|
||||
QUuid uuid;
|
||||
do {
|
||||
uuid = QUuid::createUuidV5(derived_ns,
|
||||
n ? full + QLatin1Char('\n') + QString::number(n) : full);
|
||||
++n;
|
||||
} while (m_saved_item_uuids.contains(uuid));
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1909,6 +1924,18 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
//Search the diagrams in the project
|
||||
QDomNodeList diagram_nodes = xml_project.elementsByTagName(QStringLiteral("diagram"));
|
||||
|
||||
//Every symbol and wire uuid the file already carries, on any folio,
|
||||
//before a folio derives one for an item saved without: see
|
||||
//derivedItemUuid().
|
||||
for (const QString &tag : {QStringLiteral("element"), QStringLiteral("conductor")}) {
|
||||
const QDomNodeList nodes = xml_project.elementsByTagName(tag);
|
||||
for (int i = 0; i < nodes.size(); ++i) {
|
||||
const QUuid saved(nodes.at(i).toElement().attribute(QStringLiteral("uuid")));
|
||||
if (!saved.isNull())
|
||||
m_saved_item_uuids.insert(saved);
|
||||
}
|
||||
}
|
||||
|
||||
if(dlgWaiting)
|
||||
dlgWaiting->setProgressBarRange(0, diagram_nodes.length()*3);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#endif
|
||||
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QFuture>
|
||||
|
||||
class Diagram;
|
||||
@@ -107,7 +108,7 @@ class QETProject : public QObject
|
||||
ProjectPropertiesHandler& projectPropertiesHandler();
|
||||
projectDataBase *dataBase();
|
||||
QUuid uuid() const;
|
||||
QUuid derivedUuid(const QString &kind, const QString &key);
|
||||
QUuid derivedItemUuid(const QString &kind, const QString &key);
|
||||
ProjectState state() const;
|
||||
QList<Diagram *> diagrams() const;
|
||||
int folioIndex(const Diagram *) const;
|
||||
@@ -367,6 +368,7 @@ class QETProject : public QObject
|
||||
KAutoSaveFile m_backup_file;
|
||||
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()
|
||||
projectDataBase m_data_base;
|
||||
QVector<TerminalStrip *> m_terminal_strip_vector;
|
||||
|
||||
|
||||
@@ -156,6 +156,28 @@ private slots:
|
||||
QCOMPARE(symbolUuids(resave(doc)), symbolUuids(doc));
|
||||
}
|
||||
|
||||
// A symbol keeps its derived uuid once saved, even when moved. A symbol
|
||||
// saved without a uuid that later turns up on the spot it left (a hand
|
||||
// edit, an older version, another tool) would derive the same uuid: it
|
||||
// must get another one instead.
|
||||
void newcomerOnAMovedSymbolsSpotGetsAnotherUuid()
|
||||
{
|
||||
QDomDocument doc = resave(fixture());
|
||||
QDomElement moved = symbols(diagrams(doc).first()).first();
|
||||
QVERIFY(!QUuid(moved.attribute(QStringLiteral("uuid"))).isNull());
|
||||
QDomElement newcomer = moved.cloneNode(true).toElement();
|
||||
newcomer.removeAttribute(QStringLiteral("uuid"));
|
||||
const QDomNodeList terminals = newcomer.elementsByTagName(QStringLiteral("terminal"));
|
||||
for (int i = 0; i < terminals.size(); ++i)
|
||||
terminals.at(i).toElement().setAttribute(QStringLiteral("id"), 90000 + i);
|
||||
moved.setAttribute(QStringLiteral("x"), moved.attribute(QStringLiteral("x")).toInt() + 500);
|
||||
moved.parentNode().appendChild(newcomer);
|
||||
|
||||
const QMultiHash<QString, QString> after = symbolUuids(resave(doc));
|
||||
QCOMPARE(after.size(), 10);
|
||||
QCOMPARE(QSet<QString>(after.begin(), after.end()).size(), 10);
|
||||
}
|
||||
|
||||
void stackedIdenticalSymbolsDiffer()
|
||||
{
|
||||
QDomDocument doc = fixture();
|
||||
|
||||
Reference in New Issue
Block a user