mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-10 14:14:18 +02:00
Merge pull request #1444 from ispyisail/fix/table-chain-deleted-folio
Fix a split table going blank and crashing after a folio is deleted
This commit is contained in:
@@ -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<ProjectDBModel *>(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
|
||||
|
||||
@@ -160,6 +160,73 @@ 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 <previous_table> 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("<previous_table uuid=\"", at + 1);
|
||||
QVERIFY(at > 0);
|
||||
}
|
||||
at += int(qstrlen("<previous_table uuid=\""));
|
||||
xml.replace(at, 38, "{00000000-0000-4000-8000-000000000000}");
|
||||
const QString in = m_dir.filePath(QStringLiteral("missing_previous.qet"));
|
||||
QFile f(in);
|
||||
QVERIFY(f.open(QIODevice::WriteOnly));
|
||||
f.write(xml);
|
||||
f.close();
|
||||
QVERIFY2(!resave(in).isEmpty(), "--resave failed: QElectroTech crashed closing the project");
|
||||
}
|
||||
|
||||
// Deleting the folio that holds a middle part of a split table, then
|
||||
// saving: every <previous_table> 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()
|
||||
{
|
||||
#ifndef QET_HAS_SCRIPTING
|
||||
QSKIP("needs --run: this QElectroTech is built without Qt Qml");
|
||||
#endif
|
||||
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<QString> tables;
|
||||
for (const auto &m : QRegularExpression(QStringLiteral("<graphics_table [^>]*uuid=\"([^\"]+)\"")).globalMatch(saved))
|
||||
tables.insert(m.captured(1));
|
||||
int references = 0;
|
||||
for (const auto &m : QRegularExpression(QStringLiteral("<previous_table uuid=\"([^\"]+)\"")).globalMatch(saved)) {
|
||||
++references;
|
||||
QVERIFY2(tables.contains(m.captured(1)),
|
||||
qPrintable(QStringLiteral("a table names %1, which is not in the file").arg(m.captured(1))));
|
||||
}
|
||||
QVERIFY(references > 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()
|
||||
|
||||
Reference in New Issue
Block a user