mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-20 07:14:13 +02:00
Merge pull request #883 from bhangart/persist-diagram-uuid
Persist the folio uuid, derived deterministically for legacy folios
This commit is contained in:
@@ -691,6 +691,79 @@ QUuid Diagram::uuid()
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Diagram::uuidUsedByOtherDiagram
|
||||
A hand-edited or merged project file can contain two folios with the same
|
||||
uuid. The uuid is used as a key (e.g. in the project database), so the
|
||||
second one must get another one.
|
||||
@param uuid
|
||||
@return true if another diagram of the parent project already uses @p uuid
|
||||
*/
|
||||
bool Diagram::uuidUsedByOtherDiagram(const QUuid &uuid) const
|
||||
{
|
||||
if (!m_project) {
|
||||
return false;
|
||||
}
|
||||
const auto diagrams = m_project->diagrams();
|
||||
for (const Diagram *diagram : diagrams) {
|
||||
if (diagram != this && diagram->m_uuid == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Diagram::derivedUuid
|
||||
Name-based (version 5) uuid for a folio that has no usable uuid in the
|
||||
file it is loaded from : either the file predates the uuid attribute, or
|
||||
the uuid it carries is already taken by another folio of the project.
|
||||
|
||||
A random uuid would do as an identity, but it would make saving an
|
||||
unmodified legacy project non-reproducible : every load would invent a
|
||||
different one and write it out (see #754). The name is therefore built
|
||||
only from data read from the file itself -- the project title, the
|
||||
position of the folio in the file and its title -- so the same input file
|
||||
always yields the same uuid. It is computed once, when the folio is
|
||||
loaded, and saved from then on : renaming or moving the folio later does
|
||||
not change it.
|
||||
|
||||
@param root : the <diagram> element being loaded
|
||||
@param reason : distinguishes the two cases above, so that they can not
|
||||
produce the same name
|
||||
@return a uuid not used by any other diagram of the project
|
||||
*/
|
||||
QUuid Diagram::derivedUuid(const QDomElement &root, const QString &reason) const
|
||||
{
|
||||
//Fixed namespace for QElectroTech folio uuids, never change it :
|
||||
//doing so would change the uuid given to every legacy folio.
|
||||
static const QUuid folio_namespace(
|
||||
QStringLiteral("{d5951240-154d-44d6-8277-0092a31d1920}"));
|
||||
|
||||
const int index = m_project
|
||||
? m_project->diagrams().indexOf(const_cast<Diagram *>(this))
|
||||
: -1;
|
||||
const QString project_title = root.ownerDocument()
|
||||
.documentElement()
|
||||
.attribute(QStringLiteral("title"));
|
||||
|
||||
const QString base = QStringLiteral("qet-folio\n%1\n%2\n%3\n%4")
|
||||
.arg(reason,
|
||||
project_title,
|
||||
QString::number(index),
|
||||
root.attribute(QStringLiteral("title")));
|
||||
|
||||
//A clash is only possible with a hand-crafted file, but the uuid is a
|
||||
//key : salt the name until it is free. Still deterministic.
|
||||
QUuid uuid = QUuid::createUuidV5(folio_namespace, base);
|
||||
for (int salt = 1 ; uuidUsedByOtherDiagram(uuid) ; ++salt) {
|
||||
uuid = QUuid::createUuidV5(folio_namespace,
|
||||
base + QStringLiteral("\n")
|
||||
+ QString::number(salt));
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Diagram::setEventInterface
|
||||
Set event_interface has current interface.
|
||||
@@ -906,6 +979,11 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
|
||||
// schema properties
|
||||
// proprietes du schema
|
||||
if (whole_content) {
|
||||
//Persist the folio identity, so that a folio keeps the same uuid
|
||||
//across save/load. Without it every load invents a new one, and
|
||||
//nothing outside the running instance (version control, a lock,
|
||||
//a diff tool...) can tell which folio is which.
|
||||
dom_root.setAttribute(QStringLiteral("uuid"), m_uuid.toString());
|
||||
border_and_titleblock.titleBlockToXml(dom_root);
|
||||
border_and_titleblock.borderToXml(dom_root);
|
||||
|
||||
@@ -1406,6 +1484,21 @@ bool Diagram::fromXml(QDomElement &document,
|
||||
// Read attributes of this diagram
|
||||
if (consider_informations)
|
||||
{
|
||||
// Restore the persisted folio uuid. Done first, before any item is
|
||||
// loaded, so that everything created below sees the final uuid.
|
||||
// A folio without a usable one (file written before the uuid was
|
||||
// persisted, or uuid already taken by another folio) gets a
|
||||
// deterministic one instead, see derivedUuid().
|
||||
const QUuid persisted_uuid(root.attribute(QStringLiteral("uuid")));
|
||||
if (persisted_uuid.isNull()) {
|
||||
m_uuid = derivedUuid(root, QStringLiteral("legacy"));
|
||||
} else if (uuidUsedByOtherDiagram(persisted_uuid)) {
|
||||
m_uuid = derivedUuid(root, QStringLiteral("duplicate ")
|
||||
+ persisted_uuid.toString());
|
||||
} else {
|
||||
m_uuid = persisted_uuid;
|
||||
}
|
||||
|
||||
// Load border and titleblock
|
||||
border_and_titleblock.titleBlockFromXml(root);
|
||||
border_and_titleblock.borderFromXml(root);
|
||||
|
||||
@@ -136,6 +136,9 @@ class Diagram : public QGraphicsScene
|
||||
bool m_freeze_new_elements;
|
||||
bool m_freeze_new_conductors_;
|
||||
QUuid m_uuid = QUuid::createUuid();
|
||||
|
||||
bool uuidUsedByOtherDiagram(const QUuid &uuid) const;
|
||||
QUuid derivedUuid(const QDomElement &root, const QString &reason) const;
|
||||
|
||||
// METHODS
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user