diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp index 75660104a..df090c36d 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp @@ -448,7 +448,7 @@ void QetGraphicsTableItem::setPreviousTable(QetGraphicsTableItem *table) m_previous_table->setNextTable(this); setModel(m_previous_table->m_model); } - else //Copie the model of old previous table + else if (old_previous_table->model()) //Copie the model of old previous table { setModel(new ProjectDBModel(*static_cast(old_previous_table->model()))); } @@ -596,11 +596,23 @@ QDomElement QetGraphicsTableItem::toXml(QDomDocument &dom_document) const //Add the header xml dom_table.appendChild(m_header_item->toXml(dom_document)); - //Add previous table, the model is save by the previous table - if (m_previous_table) + //Add previous table, the model is save by the previous table. + //A folio deleted with undo still possible keeps its tables in the + //chain, but it is not saved: name the nearest previous table that + //is, or save the model if none is. + const auto project_ = diagram() ? diagram()->project() : nullptr; + auto in_project = [project_](const QetGraphicsTableItem *table) { + return project_ && table->diagram() + && project_->diagrams().contains(table->diagram()); + }; + QetGraphicsTableItem *previous_ = m_previous_table; + while (previous_ && !in_project(previous_)) { + previous_ = previous_->previousTable(); + } + if (previous_) { auto dom_previous_table = dom_document.createElement("previous_table"); - dom_previous_table.setAttribute("uuid", m_previous_table->m_uuid.toString()); + dom_previous_table.setAttribute("uuid", previous_->m_uuid.toString()); dom_table.appendChild(dom_previous_table); } else if (m_model) //There is not a previous table, we need to save the model diff --git a/tests/qttest/tst_resaveunchanged.cpp b/tests/qttest/tst_resaveunchanged.cpp index e80b4cb50..360d540ba 100644 --- a/tests/qttest/tst_resaveunchanged.cpp +++ b/tests/qttest/tst_resaveunchanged.cpp @@ -160,6 +160,70 @@ private slots: QVERIFY2(sb < sa, "the coil's contacts were saved in another order than the file's"); } + // A table split over several folios whose part names a previous part + // that is not in the file: opening and closing it crashed (the part + // has no data of its own and handed its missing data on when it was + // destroyed). industrial.qet's third is changed. + void missingPreviousTableOpens() + { + QByteArray xml = read(QStringLiteral(QET_EXAMPLES_DIR "/industrial.qet")); + int at = -1; + for (int n = 0 ; n < 3 ; ++n) { + at = xml.indexOf(" 0); + } + at += int(qstrlen(" in the file names a table that is in + // it. It used to name the deleted part, so every part after it opened + // with no data. industrial.qet's folio 46 (index 45) holds such a part. + void deletedFolioKeepsTableChain() + { + const QString out = m_dir.filePath(QStringLiteral("deleted_folio.qet")); + const QString script = m_dir.filePath(QStringLiteral("deleted_folio.js")); + QFile js(script); + QVERIFY(js.open(QIODevice::WriteOnly)); + js.write(QStringLiteral("qet.log('REMOVED ' + qet.removeFolio(45));\n" + "qet.log('SAVED ' + qet.save('%1'));\n").arg(out).toUtf8()); + js.close(); + const QString home = m_dir.filePath(QStringLiteral("home%1").arg(m_run++)); + 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")); + QProcess proc; + proc.setProcessEnvironment(env); + proc.start(QStringLiteral(QET_TEST_BINARY_PATH), + {QStringLiteral("--run"), script, QStringLiteral(QET_EXAMPLES_DIR "/industrial.qet")}); + QVERIFY(proc.waitForFinished(180000)); + const QString log = QString::fromUtf8(proc.readAllStandardOutput() + proc.readAllStandardError()); + QVERIFY2(log.contains(QStringLiteral("REMOVED true")) && log.contains(QStringLiteral("SAVED true")), + qPrintable(log.right(400))); + + const QString saved = QString::fromUtf8(read(out)); + QSet tables; + for (const auto &m : QRegularExpression(QStringLiteral("]*uuid=\"([^\"]+)\"")).globalMatch(saved)) + tables.insert(m.captured(1)); + int references = 0; + for (const auto &m : QRegularExpression(QStringLiteral(" 0); + } + // 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()