Merge pull request #1552 from ispyisail/fix/keep-unloadable-items
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m43s

Fix symbols and wires lost when their definition cannot be found
This commit is contained in:
ispyisail
2026-10-19 20:58:13 +13:00
committed by GitHub
13 changed files with 898 additions and 62 deletions
+46 -2
View File
@@ -19,6 +19,7 @@
#include "qetcontainerdb.h"
#include <QCryptographicHash>
#include <functional>
#include <QHash>
#include <QMap>
#include <QSet>
@@ -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<QString> QetContainer::embeddedDefinitions(const QDomElement &project)
{
QSet<QString> paths;
std::function<void(const QDomElement &, const QString &)> 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<QString> &defined)
{
QSet<QString> 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<QetZip::Entry> 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<QString> 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<QString, QByteArray> pictures; //name -> png, once each
+3 -1
View File
@@ -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<QString> &defined);
/// The symbol definitions a project holds, by path after embed://
QSet<QString> 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)
+16 -1
View File
@@ -4119,9 +4119,24 @@ bool projectDataBase::savedLinks(const Element *element, QList<std::pair<QUuid,
@brief projectDataBase::waitingSymbols
@return the symbols on folios not built yet (lazy folios) and not
built alone as partners either (Diagram::buildSymbols()): partners a
symbol keeps its rows to until they are built
symbol keeps its rows to until they are built; and the symbols a built
folio could not build and keeps as read (Diagram::keptSymbolUuids())
*/
QSet<QUuid> projectDataBase::waitingSymbols() const
{
QSet<QUuid> kept;
if (m_project)
for (Diagram *diagram : m_project->folios())
if (diagram->isLoaded()) kept.unite(diagram->keptSymbolUuids());
return unbuiltSymbols().unite(kept);
}
/**
@brief projectDataBase::unbuiltSymbols
@return the symbols on folios not built yet and not built alone
(waitingSymbols())
*/
QSet<QUuid> projectDataBase::unbuiltSymbols() const
{
if (!m_project || !m_project->unloadedFolioCount()) {
return QSet<QUuid>();
+1
View File
@@ -165,6 +165,7 @@ class projectDataBase : public QObject
QList<std::pair<QUuid, int>> linkRowsOf(const QUuid &element) const;
QSet<QUuid> waitingPartners(const QUuid &element, const QSet<QUuid> &waiting);
QSet<QUuid> waitingSymbols() const;
QSet<QUuid> unbuiltSymbols() const;
//Fill the three stores from a project's document before its
//folios are built, then, once
+197 -13
View File
@@ -944,6 +944,132 @@ QStringList Diagram::wiresNotReconnected() const
return m_wires_not_reconnected;
}
/**
@brief Diagram::symbolsNotLoaded
@return one line per symbol of the loaded file that could not be built,
its definition missing from the project and the collections: kept as
read and saved back (F127). Empty for a folio that built every symbol.
*/
QStringList Diagram::symbolsNotLoaded() const
{
return m_symbols_not_loaded;
}
/**
@brief Diagram::keptSymbolUuids
@return the uuids of the symbols this folio could not build and keeps
as read: a partner linked to one of them keeps its link
*/
QSet<QUuid> Diagram::keptSymbolUuids() const
{
QSet<QUuid> uuids;
for (const QDomElement &symbol : m_kept_symbols)
uuids.insert(QUuid(symbol.attribute(QStringLiteral("uuid"))));
return uuids;
}
/**
@brief Diagram::keepWire
Keep @p wire, which could not be joined to its terminals, to save it
back (F127, F128). An end found (@p found1, @p found2) is written from
that terminal at save; an end not found keeps the symbol and terminal
it names, as uuids: for a wire saved by legacy terminal ids, the
symbol among @p symbols (uuid and XML of each symbol read) holding that
id and the uuid derived for that terminal where it was saved
(Element::savedTerminalUuid()), so the wire joins it again once the
symbol's definition has it there. An end naming no terminal of the
file at all pointed nowhere when it was saved: written as the null
uuid, so it names no symbol and is read back as a wire whose ends
cannot be read, kept unchanged and joining nothing (never a legacy id,
which the next save gives to another terminal).
*/
void Diagram::keepWire(const QDomElement &wire, Terminal *found1, Terminal *found2,
const QList<QPair<QUuid, QDomElement>> &symbols)
{
KeptWire kept;
Terminal *found[2] = {found1, found2};
for (int i = 0 ; i < 2 ; ++i) {
const QString index = QString::number(i + 1);
if (found[i]) {
kept.end[i] = found[i];
kept.found[i] = true;
continue;
}
if (wire.hasAttribute(QStringLiteral("element") + index)) {
kept.element[i] = QUuid(wire.attribute(QStringLiteral("element") + index));
kept.terminal[i] = QUuid(wire.attribute(QStringLiteral("terminal") + index));
} else {
const QString id = wire.attribute(QStringLiteral("terminal") + index);
for (const auto &symbol : symbols) {
const QList<QDomElement> records = QET::findInDomElement(
symbol.second, QStringLiteral("terminals"), QStringLiteral("terminal"));
for (int r = 0 ; r < records.size() && kept.element[i].isNull() ; ++r)
if (records.at(r).attribute(QStringLiteral("id")) == id) {
kept.element[i] = symbol.first;
kept.terminal[i] = Element::savedTerminalUuid(records, r);
}
if (!kept.element[i].isNull()) break;
}
}
}
kept.xml = m_kept_document.importNode(wire, true).toElement();
if (QUuid(kept.xml.attribute(QStringLiteral("uuid"))).isNull() && m_project) {
QStringList ends;
for (int i = 0 ; i < 2 ; ++i)
ends << (kept.found[i]
? kept.end[i]->parentElement()->uuid().toString() + QLatin1Char('/')
+ kept.end[i]->stableUuid().toString()
: kept.element[i].toString() + QLatin1Char('/') + kept.terminal[i].toString());
ends.sort();
kept.xml.setAttribute(QStringLiteral("uuid"),
m_project->derivedItemUuid(QStringLiteral("conductor"),
ends.join(QLatin1Char('\n'))).toString());
}
m_kept_wires << kept;
}
/**
@brief Diagram::writeKept
Write what this folio could not load, as it was read, into @p elements
and @p conductors of @p document: the symbols, their terminals given ids
after those of @p table_adr_id so none is read twice, and the wires, an
end found written from its terminal as Conductor::toXml() does. A wire
whose found end was deleted since goes with it.
*/
void Diagram::writeKept(QDomDocument &document, QDomElement &elements,
QDomElement &conductors, const QHash<Terminal *, int> &table_adr_id) const
{
int next_id = 0;
for (int id : table_adr_id) next_id = qMax(next_id, id + 1);
for (const QDomElement &symbol : m_kept_symbols) {
QDomElement copy = document.importNode(symbol, true).toElement();
for (QDomElement record : QET::findInDomElement(copy, QStringLiteral("terminals"),
QStringLiteral("terminal")))
record.setAttribute(QStringLiteral("id"), next_id++);
elements.appendChild(copy);
}
for (const KeptWire &kept : m_kept_wires) {
if ((kept.found[0] && !kept.end[0]) || (kept.found[1] && !kept.end[1])) continue;
QDomElement copy = document.importNode(kept.xml, true).toElement();
for (int i = 0 ; i < 2 && !kept.as_read ; ++i) {
const QString index = QString::number(i + 1);
const QString element = QStringLiteral("element") + index;
const QString terminal = QStringLiteral("terminal") + index;
if (!kept.found[i]) {
copy.setAttribute(element, kept.element[i].toString());
copy.setAttribute(terminal, kept.terminal[i].toString());
} else if (kept.end[i]->uuid().isNull()) {
copy.removeAttribute(element);
copy.setAttribute(terminal, table_adr_id.value(kept.end[i]));
} else {
copy.setAttribute(element, kept.end[i]->parentElement()->uuid().toString());
copy.setAttribute(terminal, kept.end[i]->uuid().toString());
}
}
conductors.appendChild(copy);
}
}
/**
@brief Diagram::uuidUsedByOtherDiagram
A hand-edited or merged project file can contain two folios with the same
@@ -1268,7 +1394,10 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
}
document.appendChild(dom_root);
if (items().isEmpty())
//What the folio could not load is written back with a whole folio
const bool write_kept = whole_content && !is_copy_command
&& (!m_kept_symbols.isEmpty() || !m_kept_wires.isEmpty());
if (items().isEmpty() && !write_kept)
return(document);
QVector<Element *> list_elements;
@@ -1375,8 +1504,8 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
// table de correspondance entre les adresses des bornes et leurs ids
QHash<Terminal *, int> table_adr_id;
if (!list_elements.isEmpty()) {
auto dom_elements = document.createElement(QStringLiteral("elements"));
auto dom_elements = document.createElement(QStringLiteral("elements"));
if (!list_elements.isEmpty() || write_kept) {
for (auto elmt : list_elements) {
QDomElement dom_element = elmt->toXml(document, table_adr_id);
ItemGroups::write(dom_element, elmt);
@@ -1388,6 +1517,7 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
dom_root.appendChild(dom_elements);
}
auto dom_conductors = document.createElement(QStringLiteral("conductors"));
if (!list_conductors.isEmpty()) {
//Symbols copied in old versions can share one uuid. A wire
//saved by that uuid would reopen on the first of them (#1408).
@@ -1397,7 +1527,6 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
shared_uuids.insert(elmt->uuid());
seen_uuids.insert(elmt->uuid());
}
auto dom_conductors = document.createElement(QStringLiteral("conductors"));
for (auto cond : list_conductors) {
dom_conductors.appendChild(cond->toXml(document,
table_adr_id,
@@ -1405,6 +1534,11 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
}
dom_root.appendChild(dom_conductors);
}
if (write_kept) {
writeKept(document, dom_elements, dom_conductors, table_adr_id);
if (dom_conductors.hasChildNodes() && dom_conductors.parentNode().isNull())
dom_root.insertAfter(dom_conductors, dom_elements);
}
// A rect query, unlike items(), returns true stacking order (z, then
// insertion order) even with NoIndex.
@@ -1603,6 +1737,23 @@ void Diagram::folioSequentialsToXml(QHash<QString,
fromXml() does for each symbol it reads.
@return the symbol, or nullptr if it could not be made (said in the log)
*/
/**
@brief Diagram::derivedSymbolUuid
@return the uuid of the symbol @p element_xml, saved without one:
derived from what it is and where it sits on its folio, never from the
folio's index (see buildElement())
*/
QUuid Diagram::derivedSymbolUuid(const QDomElement &element_xml) const
{
return m_project->derivedItemUuid(
QStringLiteral("element"),
QStringList{element_xml.attribute(QStringLiteral("type")),
element_xml.attribute(QStringLiteral("x")),
element_xml.attribute(QStringLiteral("y")),
element_xml.attribute(QStringLiteral("orientation"))}
.join(QLatin1Char('\n')));
}
Element *Diagram::buildElement(QDomElement element_xml, QHash<int, Terminal *> &table_adr_id,
bool consider_informations)
{
@@ -1650,13 +1801,7 @@ Element *Diagram::buildElement(QDomElement element_xml, QHash<int, Terminal *> &
//uuids anyway.
if (consider_informations && m_project
&& QUuid(element_xml.attribute(QStringLiteral("uuid"))).isNull()) {
nvel_elmt->setUuid(m_project->derivedItemUuid(
QStringLiteral("element"),
QStringList{type_id,
element_xml.attribute(QStringLiteral("x")),
element_xml.attribute(QStringLiteral("y")),
element_xml.attribute(QStringLiteral("orientation"))}
.join(QLatin1Char('\n'))));
nvel_elmt->setUuid(derivedSymbolUuid(element_xml));
}
ItemGroups::setGroup(nvel_elmt, ItemGroups::read(element_xml));
return nvel_elmt;
@@ -2092,6 +2237,14 @@ bool Diagram::fromXml(QDomElement &document,
QHash<int, Terminal *> table_adr_id;
if (m_loading_deferred) {
table_adr_id = m_partial_table; //the terminals of symbols built already
}
//Each symbol read, by uuid: the ends of a wire kept (keepWire())
QList<QPair<QUuid, QDomElement>> read_symbols;
if (consider_informations) {
m_kept_document = QDomDocument();
m_kept_symbols.clear();
m_kept_wires.clear();
m_symbols_not_loaded.clear();
}
for (auto element_xml :
QET::findInDomElement(root, QStringLiteral("elements"), QStringLiteral("element")))
@@ -2102,11 +2255,30 @@ bool Diagram::fromXml(QDomElement &document,
Element *built = m_partial_elements.value(QUuid(element_xml.attribute(QStringLiteral("uuid"))));
if (built) {
added_elements << built;
read_symbols.append({built->uuid(), element_xml});
continue;
}
}
if (Element *nvel_elmt = buildElement(element_xml, table_adr_id, consider_informations))
if (Element *nvel_elmt = buildElement(element_xml, table_adr_id, consider_informations)) {
added_elements << nvel_elmt;
if (consider_informations) read_symbols.append({nvel_elmt->uuid(), element_xml});
} else if (consider_informations) {
//Its definition is missing: kept as read, saved back, so a
//save loses nothing (F127)
QDomElement kept = m_kept_document.importNode(element_xml, true).toElement();
if (QUuid(kept.attribute(QStringLiteral("uuid"))).isNull() && m_project)
kept.setAttribute(QStringLiteral("uuid"), derivedSymbolUuid(element_xml).toString());
m_kept_symbols << kept;
read_symbols.append({QUuid(kept.attribute(QStringLiteral("uuid"))), element_xml});
QString label;
for (const QDomElement &info : QET::findInDomElement(
element_xml, QStringLiteral("elementInformations"), QStringLiteral("elementInformation")))
if (info.attribute(QStringLiteral("name")) == QLatin1String("label")) label = info.text();
const QString type = element_xml.attribute(QStringLiteral("type"));
m_symbols_not_loaded << (label.isEmpty()
? type.section(QLatin1Char('/'), -1)
: QStringLiteral("%1 (%2)").arg(label, type.section(QLatin1Char('/'), -1)));
}
}
//Texts, images and shapes written before they carried a uuid (or
@@ -2262,7 +2434,17 @@ bool Diagram::fromXml(QDomElement &document,
QStringLiteral("conductors"),
QStringLiteral("conductor")))
{
if (!Conductor::valideXml(f)) continue;
if (!Conductor::valideXml(f)) {
//Its ends cannot be read: kept and written back unchanged
//(F128), it can join nothing
if (consider_informations) {
KeptWire kept;
kept.xml = m_kept_document.importNode(f, true).toElement();
kept.as_read = true;
m_kept_wires << kept;
}
continue;
}
//Check if terminal that conductor must be linked is know
@@ -2297,6 +2479,8 @@ bool Diagram::fromXml(QDomElement &document,
if (!num.isEmpty() && num != QLatin1String("_"))
wire += QStringLiteral(" (%1)").arg(num);
m_wires_not_reconnected << wire;
//Kept as read, saved back (F128)
keepWire(f, p1, p2, read_symbols);
}
if (p1 && p2 && p1 != p2)
+25
View File
@@ -39,6 +39,7 @@ class DiagramContent;
class DiagramPosition;
class DiagramTextItem;
class Element;
class Terminal;
class ElementsLocation;
class DiagramImageItem;
class DiagramEventInterface;
@@ -165,6 +166,28 @@ class Diagram : public QGraphicsScene
//Wires of the loaded file whose ends could not be found
QStringList m_wires_not_reconnected;
//Symbols of the loaded file that could not be built
QStringList m_symbols_not_loaded;
//What the folio could not load, written back as it was read
//(F127, F128): symbols whose definition is missing, and wires
//to a terminal not found
struct KeptWire {
QDomElement xml;
QPointer<Terminal> end[2]; ///< an end found, null if not
bool found[2] = {false, false};
QUuid element[2]; ///< an end not found: its symbol
QUuid terminal[2]; ///< and its terminal
bool as_read = false; ///< no end can be read: written unchanged
};
QDomDocument m_kept_document;
QList<QDomElement> m_kept_symbols;
QList<KeptWire> m_kept_wires;
QUuid derivedSymbolUuid(const QDomElement &element_xml) const;
void keepWire(const QDomElement &wire, Terminal *found1, Terminal *found2,
const QList<QPair<QUuid, QDomElement>> &symbols);
void writeKept(QDomDocument &document, QDomElement &elements,
QDomElement &conductors, const QHash<Terminal *, int> &table_adr_id) const;
// METHODS
protected:
@@ -189,6 +212,8 @@ class Diagram : public QGraphicsScene
void restoreText(Element* elmt);
QUuid uuid();
QStringList wiresNotReconnected() const;
QStringList symbolsNotLoaded() const;
QSet<QUuid> keptSymbolUuids() const;
void setEventInterface (DiagramEventInterface *event_interface);
void clearEventInterface();
+32 -10
View File
@@ -2262,27 +2262,49 @@ bool QETDiagramEditor::openAndAddProject(
);
}
//Report wires left out of the load because a terminal they join
//was not found: they would otherwise vanish on the next save
//without the user ever being told.
QStringList lost_wires;
//Report the elements and wires left out of the load: an element
//whose definition is missing, a wire whose terminal was not found.
//They are kept in the file as they were (F127, F128), but are not
//shown.
QStringList lost_elements, lost_wires;
for (Diagram *diagram : project->folios()) {
if (!diagram->isLoaded()) continue;
for (const QString &element : diagram->symbolsNotLoaded())
lost_elements << tr("Sheet %1: %2").arg(diagram->folioIndex() + 1).arg(element);
}
for (Diagram *diagram : project->foliosWithWiresNotReconnected()) {
for (const QString &wire : diagram->wiresNotReconnected()) {
lost_wires << tr("Sheet %1: %2").arg(diagram->folioIndex() + 1).arg(wire);
}
}
if (interactive && !lost_elements.isEmpty())
{
QMessageBox box(QMessageBox::Warning,
tr("Elements not loaded", "message box title"),
tr("%n elements could not be loaded: their definition is "
"missing from the project and from the collections.\n"
"\n"
"They are not shown, but they are kept in the file as they "
"are, with their conductors, and come back once their "
"definition is available again.",
"message box content",
lost_elements.size()),
QMessageBox::Ok,
this);
box.setDetailedText(lost_elements.join(QLatin1Char('\n')));
box.exec();
}
if (interactive && !lost_wires.isEmpty())
{
QMessageBox box(QMessageBox::Warning,
tr("Conductors not loaded", "message box title"),
tr("%n conductors could not be joined to their terminals and "
"were not loaded. The element's definition in the project "
"was probably replaced by another one with different "
"terminals.\n"
"were not loaded. The element's definition is missing, or "
"was replaced by another one with different terminals.\n"
"\n"
"If you save the project, these conductors will disappear "
"from the file. Close it without saving to keep the file as "
"it is.",
"They are not shown, but they are kept in the file as they "
"are, and join their terminals again once the definition "
"has them where they were.",
"message box content",
lost_wires.size()),
QMessageBox::Ok,
+37 -26
View File
@@ -975,6 +975,41 @@ bool Element::valideXml(QDomElement &e)
return(true);
}
/**
@brief Element::savedTerminalUuid
@return the uuid TerminalUuids derives for the terminal saved as
@p records [@p index] (a symbol's saved terminals, in file order) at the
place it was saved: its docking point less the stub Terminal::init()
adds, and its rank among the records at that place, as the project
counted it when it gave the terminals their uuids
*/
QUuid Element::savedTerminalUuid(const QList<QDomElement> &records, int index)
{
const auto dock_of = [](const QDomElement &r) {
return QPointF(r.attribute(QStringLiteral("x")).toDouble(),
r.attribute(QStringLiteral("y")).toDouble());
};
const QDomElement &record = records.at(index);
const int orientation = record.attribute(QStringLiteral("orientation")).toInt();
const QPointF dock = dock_of(record);
QPointF old_pos = dock;
switch (orientation) {
case Qet::North: old_pos -= QPointF(0, Terminal::terminalSize); break;
case Qet::East : old_pos -= QPointF(-Terminal::terminalSize, 0); break;
case Qet::West : old_pos -= QPointF(Terminal::terminalSize, 0); break;
case Qet::South: old_pos -= QPointF(0, -Terminal::terminalSize); break;
}
int rank = 0;
for (int j = 0; j < index; ++j) {
const QPointF other = dock_of(records.at(j));
if (records.at(j).attribute(QStringLiteral("orientation")).toInt() == orientation
&& qAbs(other.x() - dock.x()) < 1e-6
&& qAbs(other.y() - dock.y()) < 1e-6)
++rank;
}
return TerminalUuids::derived(old_pos.x(), old_pos.y(), orientation, rank);
}
/**
@brief Element::matchMovedTerminals
Pair the saved terminals that no live terminal matched exactly with the
@@ -1033,32 +1068,8 @@ void Element::matchMovedTerminals(const QList<QDomElement> &records,
//Pair a record with a live terminal: register its legacy id, and the
//uuid derived for the terminal at its old place
const auto pair_up = [&](int index, Terminal *t) {
const QDomElement &record = records.at(index);
const QPointF dock = dock_of(record);
//The old place of the terminal: its docking point less the
//stub that Terminal::init() added
QPointF old_pos = dock;
switch (orientation_of(record)) {
case Qet::North: old_pos -= QPointF(0, Terminal::terminalSize); break;
case Qet::East : old_pos -= QPointF(-Terminal::terminalSize, 0); break;
case Qet::West : old_pos -= QPointF(Terminal::terminalSize, 0); break;
case Qet::South: old_pos -= QPointF(0, -Terminal::terminalSize); break;
}
//The rank among the records at the same place, as the project
//counted it when it gave the terminals their uuids
int rank = 0;
for (int j = 0; j < index; ++j) {
const QPointF other = dock_of(records.at(j));
if (orientation_of(records.at(j)) == orientation_of(record)
&& qAbs(other.x() - dock.x()) < 1e-6
&& qAbs(other.y() - dock.y()) < 1e-6)
++rank;
}
id_adr.insert(record.attribute(QStringLiteral("id")).toInt(), t);
m_old_place_terminals.insert(TerminalUuids::derived(old_pos.x(), old_pos.y(),
orientation_of(record), rank), t);
id_adr.insert(records.at(index).attribute(QStringLiteral("id")).toInt(), t);
m_old_place_terminals.insert(savedTerminalUuid(records, index), t);
m_moved_terminals << t;
};
const auto same_place = [](const QPointF &a, const QPointF &b) {
+1
View File
@@ -183,6 +183,7 @@ class Element : public QetGraphicsItem
QPoint hotspot() const;
void editProperty() override;
static bool valideXml(QDomElement &);
static QUuid savedTerminalUuid(const QList<QDomElement> &records, int index);
virtual bool fromXml(
QDomElement &,
QHash<int,