diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 494f9941b..56c8bda2d 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -1642,6 +1642,7 @@ void Element::initLink(QETProject *prj) } } } + restoreSavedLinkOrder(); tmp_uuids_link.clear(); } @@ -1669,9 +1670,36 @@ void Element::initLink(const QList &candidates) } } } + restoreSavedLinkOrder(); tmp_uuids_link.clear(); } +/** + @brief Element::restoreSavedLinkOrder + Put connected_elements back in the order tmp_uuids_link saved them. + Partners link in the order the folios' items are visited, and for + items at the same height that order changes from run to run, so a + master's contacts were saved in a different order each time. + Linked elements missing from the saved list keep their place after it. +*/ +void Element::restoreSavedLinkOrder() +{ + QList ordered; + for (const auto &link_info : std::as_const(tmp_uuids_link)) { + for (Element *elmt : std::as_const(connected_elements)) { + if (elmt->uuid() == link_info.uuid && !ordered.contains(elmt)) { + ordered << elmt; + break; + } + } + } + for (Element *elmt : std::as_const(connected_elements)) { + if (!ordered.contains(elmt)) + ordered << elmt; + } + connected_elements = ordered; +} + /** * @brief Element::linkTypeToString * \deprecated use instead ElementData::typeToString diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h index 6c2a4b352..02c3ea600 100644 --- a/sources/qetgraphicsitem/element.h +++ b/sources/qetgraphicsitem/element.h @@ -328,6 +328,7 @@ class Element : public QetGraphicsItem QList plcTablePositions() const { return m_plc_table_positions; } private: + void restoreSavedLinkOrder(); bool m_must_highlight = false; QSize dimensions; QPoint hotspot_coord; diff --git a/tests/qttest/tst_resaveunchanged.cpp b/tests/qttest/tst_resaveunchanged.cpp index bc333ea44..e80b4cb50 100644 --- a/tests/qttest/tst_resaveunchanged.cpp +++ b/tests/qttest/tst_resaveunchanged.cpp @@ -19,7 +19,8 @@ // was opened again (m_000.qet). // Runs the real binary's --resave twice on every example, on a project // whose title block holds a value that is a single space (#973), and on -// one that used to crash on opening (bugtracker #345). +// one that used to crash on opening (bugtracker #345); and that a coil's +// contacts keep the order the file saved them in. class tst_resaveunchanged : public QObject { Q_OBJECT @@ -118,6 +119,47 @@ private slots: "a machine manufacturer reference variable was left unresolved"); } + // A coil's contacts are saved in the order the file listed them. + // They used to come back in the order the folios were visited, so a + // list that disagreed with it changed on every save, and contacts on + // one folio swapped places from run to run. m_000.qet's coil b02216df + // (folio 13) lists its contacts on folios 7 and 12; the test lists + // them the other way round. + void savedLinkOrderKept() + { + QByteArray xml = read(QStringLiteral(QET_EXAMPLES_DIR "/m_000.qet")); + const QRegularExpression coil(QStringLiteral( + "]*uuid=\"\\{b02216df-0851-4732-893b-901fea80703e\\}\"")); + // byte offset of the coil's tag in @p file, or -1 + const auto coilAt = [&coil](const QByteArray &file) { + const QRegularExpressionMatch m = coil.match(QString::fromLatin1(file)); + return m.hasMatch() ? int(m.capturedStart()) : -1; + }; + const QByteArray a = ""; + const QByteArray b = ""; + const int start = coilAt(xml); + QVERIFY(start > 0); + const int ia = xml.indexOf(a, start), ib = xml.indexOf(b, start); + QVERIFY2(ia > 0 && ib > ia, "m_000.qet no longer lists the coil's contacts as expected"); + const QByteArray link_b = xml.mid(ib, xml.indexOf(b_end, ib) + b_end.size() - ib); + xml.replace(ib, link_b.size(), a); + xml.replace(ia, a.size(), link_b); + const QString in = m_dir.filePath(QStringLiteral("links.qet")); + QFile f(in); + QVERIFY(f.open(QIODevice::WriteOnly)); + f.write(xml); + f.close(); + + const QByteArray saved = read(resave(in)); + QVERIFY2(!saved.isEmpty(), "--resave failed"); + const int s = coilAt(saved); + QVERIFY(s > 0); + const int sa = saved.indexOf(a, s), sb = saved.indexOf(b, s); + QVERIFY2(sa > 0 && sb > 0, "a link was lost"); + QVERIFY2(sb < sa, "the coil's contacts were saved in another order than the file's"); + } + // A title-block value that is a single space is kept through two saves // (#973), and a value with accents comes back as it went in. void singleSpaceValueKept()