From 166ee34f5279f1da395f53d0dbda9fa00f510549 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sun, 27 Sep 2026 21:46:30 +1300 Subject: [PATCH] Fix parts lists saved before June 2022 losing rows and tables on open A nomenclature table saved by an older version filters on the element type names the project database used then: element_type = 'Simple', 'Terminale', 'Master'. Commit 2e70d2e59 (June 2022) changed the database to "simple", "terminal", "master", and SQLite compares text case-sensitively, so such a table silently lost every row of that type on open. Its continuation tables were then empty, and removeUselessNextTable() deleted them: opening and saving the example industrial.qet removed seven of its ten parts-list tables (folios 44-50), and the remaining three listed 76 of 258 parts. ProjectDBModel::fromXml() now rewrites old names in element_type = '...' comparisons to the current ones (LegacyElementTypes::upgradeQuery()), which also lets the query editor tick the right boxes again. A query saved by a current version is unchanged, and so is any other text that happens to contain "Simple". Checked in the GUI on industrial.qet, open then save: master keeps tables on 3 of folios 41-50, this keeps all 10, with 258 rows (the last table 24 of 26) and the query saved as 'simple'. tst_legacyelementtypes fails when a name maps wrongly. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- cmake/qet_compilation_vars.cmake | 1 + sources/dataBase/legacyelementtypes.h | 69 +++++++++++++++++++ .../ViewItem/projectdbmodel.cpp | 5 +- tests/qttest/CMakeLists.txt | 7 ++ tests/qttest/tst_legacyelementtypes.cpp | 60 ++++++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 sources/dataBase/legacyelementtypes.h create mode 100644 tests/qttest/tst_legacyelementtypes.cpp diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index 60fddcf55..398cdce8c 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -325,6 +325,7 @@ set(QET_SRC_FILES ${QET_DIR}/sources/autoNum/ui/selectautonumw.cpp ${QET_DIR}/sources/autoNum/ui/selectautonumw.h + ${QET_DIR}/sources/dataBase/legacyelementtypes.h ${QET_DIR}/sources/dataBase/projectdatabase.cpp ${QET_DIR}/sources/dataBase/projectdatabase.h ${QET_DIR}/sources/dataBase/sqlreadonly.cpp diff --git a/sources/dataBase/legacyelementtypes.h b/sources/dataBase/legacyelementtypes.h new file mode 100644 index 000000000..51943996b --- /dev/null +++ b/sources/dataBase/legacyelementtypes.h @@ -0,0 +1,69 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef LEGACYELEMENTTYPES_H +#define LEGACYELEMENTTYPES_H + +#include +#include + +/** + Element type names in queries saved by versions before June 2022. + The project database then held Element::linkTypeToString() ("Simple", + "Terminale", ...); since it holds ElementData::typeToString() + ("simple", "terminal", ...). SQLite compares text case-sensitively, so + a nomenclature table saved with element_type = 'Simple' silently lost + every simple element, and its continuation tables were deleted as + empty. +*/ +namespace LegacyElementTypes +{ + /** + @return query with every element_type = '' comparison + rewritten to the current name. Anything else is left as it is, + so a query saved by a current version comes back unchanged. + */ + inline QString upgradeQuery(const QString &query) + { + static const QRegularExpression re(QStringLiteral( + "element_type\\s*=\\s*'(Simple|NextReport|PreviousReport|Master" + "|Slave|Terminale|Thumbnail)'")); + + QString upgraded = query; + auto it = re.globalMatch(query); + int shift = 0; + while (it.hasNext()) + { + const auto match = it.next(); + const QString old_name = match.captured(1); + QString new_name; + if (old_name == QLatin1String("Simple")) new_name = QStringLiteral("simple"); + else if (old_name == QLatin1String("NextReport")) new_name = QStringLiteral("next_report"); + else if (old_name == QLatin1String("PreviousReport")) new_name = QStringLiteral("previous_report"); + else if (old_name == QLatin1String("Master")) new_name = QStringLiteral("master"); + else if (old_name == QLatin1String("Slave")) new_name = QStringLiteral("slave"); + else if (old_name == QLatin1String("Terminale")) new_name = QStringLiteral("terminal"); + else new_name = QStringLiteral("thumbnail"); + + upgraded.replace(match.capturedStart(1) + shift, old_name.size(), new_name); + shift += new_name.size() - old_name.size(); + } + return upgraded; + } +} + +#endif // LEGACYELEMENTTYPES_H diff --git a/sources/qetgraphicsitem/ViewItem/projectdbmodel.cpp b/sources/qetgraphicsitem/ViewItem/projectdbmodel.cpp index ca07e5ba8..a201fcb02 100644 --- a/sources/qetgraphicsitem/ViewItem/projectdbmodel.cpp +++ b/sources/qetgraphicsitem/ViewItem/projectdbmodel.cpp @@ -19,6 +19,7 @@ #include +#include "../../dataBase/legacyelementtypes.h" #include "../../dataBase/projectdatabase.h" #include "../../qetapp.h" #include "../../qetinformation.h" @@ -294,7 +295,9 @@ void ProjectDBModel::fromXml(const QDomElement &element) return; setIdentifier(element.firstChildElement("identifier").text()); - setQuery(element.firstChildElement("query").text()); + //A query saved before June 2022 names element types the old way + setQuery(LegacyElementTypes::upgradeQuery( + element.firstChildElement("query").text())); //Index 0,0 auto index_00 = element.firstChildElement("index00"); diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index 66074282d..d2437661d 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -104,6 +104,13 @@ add_test(NAME tst_textgrid COMMAND tst_textgrid) target_include_directories(tst_textgrid PRIVATE ${QET_DIR}/sources) target_link_libraries(tst_textgrid PRIVATE Qt::Test) +# legacyelementtypes.h is header-only: the rewrite of element type names in +# nomenclature queries saved before June 2022. +add_executable(tst_legacyelementtypes tst_legacyelementtypes.cpp) +add_test(NAME tst_legacyelementtypes COMMAND tst_legacyelementtypes) +target_include_directories(tst_legacyelementtypes PRIVATE ${QET_DIR}/sources) +target_link_libraries(tst_legacyelementtypes PRIVATE Qt::Test) + add_executable( tst_qetpalette tst_qetpalette.cpp diff --git a/tests/qttest/tst_legacyelementtypes.cpp b/tests/qttest/tst_legacyelementtypes.cpp new file mode 100644 index 000000000..bc36725e1 --- /dev/null +++ b/tests/qttest/tst_legacyelementtypes.cpp @@ -0,0 +1,60 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "dataBase/legacyelementtypes.h" + +#include + +class TestLegacyElementTypes : public QObject +{ + Q_OBJECT + + private slots: + void upgradesOldNames_data() + { + QTest::addColumn("saved"); + QTest::addColumn("expected"); + + // The WHERE clause industrial.qet's parts list was saved with. + QTest::newRow("simple, with sub types") + << "WHERE ( element_type = 'Simple' OR element_sub_type = 'coil') ORDER BY label" + << "WHERE ( element_type = 'simple' OR element_sub_type = 'coil') ORDER BY label"; + QTest::newRow("terminal and master, lengths change") + << "element_type = 'Terminale' OR element_type = 'Master' OR element_type = 'Simple'" + << "element_type = 'terminal' OR element_type = 'master' OR element_type = 'simple'"; + QTest::newRow("reports and thumbnail") + << "element_type='NextReport' OR element_type = 'PreviousReport' OR element_type = 'Thumbnail'" + << "element_type='next_report' OR element_type = 'previous_report' OR element_type = 'thumbnail'"; + QTest::newRow("current names unchanged") + << "element_type = 'simple' OR element_type = 'terminal'" + << "element_type = 'simple' OR element_type = 'terminal'"; + QTest::newRow("the word elsewhere unchanged") + << "WHERE label = 'Simple' OR designation = 'Master'" + << "WHERE label = 'Simple' OR designation = 'Master'"; + QTest::newRow("empty") << "" << ""; + } + + void upgradesOldNames() + { + QFETCH(QString, saved); + QFETCH(QString, expected); + QCOMPARE(LegacyElementTypes::upgradeQuery(saved), expected); + } +}; + +QTEST_APPLESS_MAIN(TestLegacyElementTypes) +#include "tst_legacyelementtypes.moc"