From fcc11bff745919c448198946a61178655c6cd210 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 16 Oct 2026 12:57:17 +1300 Subject: [PATCH] Keep a right-aligned text where it was when lazy folios refill it A report symbol's right-aligned text (the function of its partner's wire) was saved at another x than with every folio built after deleting a coil on its folio: moved left by its own width. Cosmetic, nothing lost. setPlainText() keeps a right-aligned text's right edge, except while the project is being opened (ProjectParsingRunning) or the symbol is built. With lazy folios the text is emptied outside that state (the partner's folio is not built, so no wire is watched) and the edge is kept, then filled again while the late folios are built, which holds the project in the opening state: the edge was not kept, and x stayed where emptying moved it. With every folio built both happen during the opening. A text emptied with its alignment kept is now filled again the same way, whatever the project state; a text set while the project is opened and never emptied that way is untouched, so what a plain opening writes does not change. Evidence: forum f1537 (resaved with every folio built), deleting coil {794d8944} on folio 9 saved x=11.7969 lazily, x=60 eagerly; both 60 now. Resave of the 342 corpus projects, lazy and eager, identical to before. tst_reporttextlatefolio fails without the fix (x=28.6875 lazily). Co-Authored-By: Claude Opus 5.5 --- .../dynamicelementtextitem.cpp | 26 +- .../qetgraphicsitem/dynamicelementtextitem.h | 2 + tests/qttest/CMakeLists.txt | 15 + .../fixtures/report_text_late_folio.qet | 278 ++++++++++++++++++ tests/qttest/tst_reporttextlatefolio.cpp | 90 ++++++ 5 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 tests/qttest/fixtures/report_text_late_folio.qet create mode 100644 tests/qttest/tst_reporttextlatefolio.cpp diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.cpp b/sources/qetgraphicsitem/dynamicelementtextitem.cpp index c99eb4a37..495d9bb68 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.cpp +++ b/sources/qetgraphicsitem/dynamicelementtextitem.cpp @@ -1797,12 +1797,36 @@ void DynamicElementTextItem::setPlainText(const QString &text) bool update_alignment = true; + bool parsing_only = false; if (diagram() && (diagram()->project()->state() == QETProject::ProjectParsingRunning)) + { update_alignment = false; + parsing_only = true; + } if (m_parent_element.data()->state() == QET::GIBuildingFromXml || m_parent_element.data()->state() == QET::GILoadingFromXml) + { update_alignment = false; - + parsing_only = false; + } + + //A text emptied with its alignment kept (the project not being + //opened) is filled again the same way, even if the project is + //being opened by then: lazy folios build the folios left late with + //the project in that state, and the text would stay where emptying + //moved it (F119) + if (text.isEmpty()) + m_emptied_aligned = update_alignment; + else if (!toPlainText().isEmpty()) + m_emptied_aligned = false; + else if (parsing_only && m_emptied_aligned) + { + update_alignment = true; + m_emptied_aligned = false; + } + else + m_emptied_aligned = false; + if (update_alignment) { prepareAlignment(); } diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.h b/sources/qetgraphicsitem/dynamicelementtextitem.h index 5ac043a27..524dd91ad 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.h +++ b/sources/qetgraphicsitem/dynamicelementtextitem.h @@ -196,6 +196,8 @@ class DynamicElementTextItem : public DiagramTextItem CrossRefItem *m_Xref_item = nullptr; QGraphicsTextItem *m_slave_Xref_item = nullptr; qreal m_text_width = -1; + /// The text was emptied with its alignment kept (setPlainText()) + bool m_emptied_aligned = false; QPointF m_initial_position; bool m_keep_visual_rotation = true; bool m_rotation_point_center = false; diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index 32f68efc8..85951d4ca 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -1291,3 +1291,18 @@ target_compile_definitions(tst_qetcontainer PRIVATE "QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"" "QET_FIXTURES_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/fixtures\"" "QET_FORMAT_SPEC=\"${QET_DIR}/sources/container/QETZ-FORMAT.md\"") + +# A right-aligned report text emptied and set again while lazy folios are +# built is saved where it was (F119): the real binary's --run on +# fixtures/report_text_late_folio.qet, lazily and with every folio built. +if(QET_HAS_SCRIPTING) + add_executable( + tst_reporttextlatefolio + tst_reporttextlatefolio.cpp) + add_test(NAME tst_reporttextlatefolio COMMAND tst_reporttextlatefolio) + add_dependencies(tst_reporttextlatefolio qelectrotech) + target_link_libraries(tst_reporttextlatefolio PRIVATE Qt::Test) + target_compile_definitions(tst_reporttextlatefolio PRIVATE + "QET_TEST_BINARY_PATH=\"$\"" + "QET_FIXTURES_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/fixtures\"") +endif() diff --git a/tests/qttest/fixtures/report_text_late_folio.qet b/tests/qttest/fixtures/report_text_late_folio.qet new file mode 100644 index 000000000..b55af5aba --- /dev/null +++ b/tests/qttest/fixtures/report_text_late_folio.qet @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + T + label + + + Motor_X + function + + + + + + + + + + + + + + + + K1 + + + + T + + + T + + + T + description + + + T + label + + + T + comment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T + label + + + Motor_X + function + + + + + + + + + + + + + + + + + + + K1 + + + + T + + + T + + + T + description + + + T + label + + + T + comment + + + + + + + + + + + + + + + + + + + + + + + + + Следующая страница + الصفحة التالية + Nächste Folie + Επόμενη σελίδα + Going arrow + Foglio successivo + Folio suivant + Wyjście adresowe + Folio siguiente + Další list + Referentie volgend + + Author: The QElectroTech team +License: see http://qelectrotech.org/wiki/doc/elements_license + + + + + + + + + + + + + Предыдущая страница + الصفحة السابقة + Vorherige Folie + Προηγούμενη σελίδα + Coming arrow + Foglio precedente + Folio précédent + Wejście adresowe + folio anterior + Předchozí list + Referentie Vorig + + Author: The QElectroTech team +License: see http://qelectrotech.org/wiki/doc/elements_license + + + + + + + + + + + + + + + Coil + Bobina + Πηνίο + Bobine + Cívka + Bobina + Cewka + ملف + Spoel + Spule + Relais spoel (algemeen) + Обмотка + + + coil + + + + + tag + + + + Nome + + + comentário + + + Author: The QElectroTech team +License: see http://qelectrotech.org/wiki/doc/elements_license + + + A2 + + + A1 + + + + + Nome + description + + + tag + label + + + comentário + comment + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/qttest/tst_reporttextlatefolio.cpp b/tests/qttest/tst_reporttextlatefolio.cpp new file mode 100644 index 000000000..b73e91b8e --- /dev/null +++ b/tests/qttest/tst_reporttextlatefolio.cpp @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include + +#include +#include +#include +#include +#include + +// A report symbol on folio B shows the function of the wire its partner has +// on folio A, right-aligned. Deleting the coil on folio B empties that text +// while folio A, not built yet (lazy folios), is not known to the report, and +// builds it again when folio A is built. The text keeps its right edge when +// emptied outside the opening of the project, and was not moved back when set +// again while the late folios are built (the project is then in the state of +// being opened): it was saved at another x than with every folio built (F119). +// The real binary's --run on fixtures/report_text_late_folio.qet, lazily and +// with QET_EAGER_FOLIOS=1. +class tst_reporttextlatefolio : public QObject +{ + Q_OBJECT + + QTemporaryDir m_dir; + + QString savedX(bool eager) + { + const QString tag = eager ? QStringLiteral("eager") : QStringLiteral("lazy"); + const QString out = m_dir.filePath(tag + QStringLiteral(".qet")); + const QString script = m_dir.filePath(tag + QStringLiteral(".js")); + const QString home = m_dir.filePath(tag + QStringLiteral("-home")); + QDir().mkpath(home); + QFile f(script); + if (!f.open(QIODevice::WriteOnly)) + return QString(); + f.write("qet.deleteElement(1, '{794d8944-035d-4bcd-8ee6-c653d384fd4f}');\n" + "qet.save('" + out.toUtf8() + "');\n"); + f.close(); + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen")); + env.insert(QStringLiteral("QET_ENABLE_SCRIPTING"), QStringLiteral("1")); + env.insert(QStringLiteral("HOME"), home); + env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config")); + env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/data")); + env.insert(QStringLiteral("TMPDIR"), m_dir.path()); + if (eager) + env.insert(QStringLiteral("QET_EAGER_FOLIOS"), QStringLiteral("1")); + else + env.remove(QStringLiteral("QET_EAGER_FOLIOS")); + QProcess proc; + proc.setProcessEnvironment(env); + proc.start(QStringLiteral(QET_TEST_BINARY_PATH), + {QStringLiteral("--run"), script, + QStringLiteral(QET_FIXTURES_DIR "/report_text_late_folio.qet")}); + if (!proc.waitForFinished(120000)) + return QString(); + QFile saved(out); + if (!saved.open(QIODevice::ReadOnly)) + return QString(); + const QString xml = QString::fromUtf8(saved.readAll()); + const QRegularExpression re(QStringLiteral( + "uuid=\"\\{cbaf051e-0ce0-40f1-ada9-b8f637a79f92\\}\" x=\"([^\"]*)\"")); + const auto m = re.match(xml); + return m.hasMatch() ? m.captured(1) : QString(); + } + +private slots: + void initTestCase() + { + QVERIFY(m_dir.isValid()); + QVERIFY(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH))); + } + + void rightAlignedTextKeepsItsPlace_data() + { + QTest::addColumn("eager"); + QTest::newRow("lazy folios") << false; + QTest::newRow("every folio built") << true; + } + + void rightAlignedTextKeepsItsPlace() + { + QFETCH(bool, eager); + QCOMPARE(savedX(eager), QStringLiteral("60")); + } +}; + +QTEST_APPLESS_MAIN(tst_reporttextlatefolio) + +#include "tst_reporttextlatefolio.moc"