diff --git a/sources/dataBase/projectdatabase.cpp b/sources/dataBase/projectdatabase.cpp index 5e463cbc3..2cf59498c 100644 --- a/sources/dataBase/projectdatabase.cpp +++ b/sources/dataBase/projectdatabase.cpp @@ -4113,68 +4113,28 @@ QStringList projectDataBase::linkRowMismatches() /** @brief projectDataBase::setNumbering - The numbering tables hold @p numbering from now on, and nothing else - (QETZ-DB-FIRST stage 2b-1: QETProject writes them after reading its - file and after each change of its numbering) + The numbering tables hold @p numbering from now on, and nothing else: + what QETProject reads from its file (QETZ-DB-FIRST stage 2b) */ void projectDataBase::setNumbering(const Numbering &numbering) { QSqlQuery query(m_data_base); - bool ok = true; - for (const char *table : {"numbering_part", "numbering_scheme", "numbering_setting"}) - ok = ok && query.exec(QStringLiteral("DELETE FROM %1").arg(QLatin1String(table))); - - QSqlQuery scheme(m_data_base); - scheme.prepare(QStringLiteral("INSERT INTO numbering_scheme (kind, title, uuid) " - "VALUES (:kind, :title, :uuid)")); - QSqlQuery part(m_data_base); - part.prepare(QStringLiteral("INSERT INTO numbering_part (kind, title, ord, type, value, " - "increase, initialvalue, modulus, format) VALUES (:kind, :title, " - ":ord, :type, :value, :increase, :initialvalue, :modulus, :format)")); - for (const NumberingScheme &item : numbering.schemes) - { - scheme.bindValue(QStringLiteral(":kind"), item.kind); - scheme.bindValue(QStringLiteral(":title"), item.title); - scheme.bindValue(QStringLiteral(":uuid"), item.uuid.isNull() ? QVariant() - : QVariant(item.uuid.toString())); - ok = ok && scheme.exec(); - for (int i = 0 ; i < item.context.size() ; ++i) - { - const QStringList fields = item.context.itemAt(i); - part.bindValue(QStringLiteral(":kind"), item.kind); - part.bindValue(QStringLiteral(":title"), item.title); - part.bindValue(QStringLiteral(":ord"), i); - int field = 0; - for (const char *name : {":type", ":value", ":increase", ":initialvalue", ":modulus", ":format"}) { - part.bindValue(QLatin1String(name), field < fields.size() ? QVariant(fields.at(field)) - : QVariant()); - ++field; - } - ok = ok && part.exec(); + for (const char *table : {"numbering_part", "numbering_scheme", "numbering_setting"}) { + if (!query.exec(QStringLiteral("DELETE FROM %1").arg(QLatin1String(table)))) { + qDebug() << "projectDataBase::setNumbering error : " << query.lastError(); } } - - QSqlQuery setting(m_data_base); - setting.prepare(QStringLiteral("INSERT INTO numbering_setting (name, value) VALUES (:name, :value)")); - auto set = [&setting, &ok](const QString &name, const QString &value) { - setting.bindValue(QStringLiteral(":name"), name); - setting.bindValue(QStringLiteral(":value"), value); - ok = ok && setting.exec(); - }; - auto flag = [](bool value) { return value ? QStringLiteral("true") : QStringLiteral("false"); }; - set(QStringLiteral("conductor_current"), numbering.current_conductor); - set(QStringLiteral("element_current"), numbering.current_element); - set(QStringLiteral("cable_current"), numbering.current_cable); - set(QStringLiteral("freeze_new_conductors"), flag(numbering.freeze_new_conductors)); - set(QStringLiteral("freeze_new_elements"), flag(numbering.freeze_new_elements)); - set(QStringLiteral("auto_break_conductors"), flag(numbering.auto_break_conductors)); - set(QStringLiteral("cable_x_axis_first"), flag(numbering.cable_x_axis_first)); - set(QStringLiteral("cable_ask_numbering"), flag(numbering.cable_ask_numbering)); - - if (!ok) { - qDebug() << "projectDataBase::setNumbering error : " << query.lastError() - << scheme.lastError() << part.lastError() << setting.lastError(); + for (const NumberingScheme &item : numbering.schemes) { + setNumberingScheme(item.kind, item.title, item.context, item.uuid); } + setNumberingSetting(QStringLiteral("conductor_current"), numbering.current_conductor); + setNumberingSetting(QStringLiteral("element_current"), numbering.current_element); + setNumberingSetting(QStringLiteral("cable_current"), numbering.current_cable); + setNumberingFlag(QStringLiteral("freeze_new_conductors"), numbering.freeze_new_conductors); + setNumberingFlag(QStringLiteral("freeze_new_elements"), numbering.freeze_new_elements); + setNumberingFlag(QStringLiteral("auto_break_conductors"), numbering.auto_break_conductors); + setNumberingFlag(QStringLiteral("cable_x_axis_first"), numbering.cable_x_axis_first); + setNumberingFlag(QStringLiteral("cable_ask_numbering"), numbering.cable_ask_numbering); } /** @@ -4225,6 +4185,248 @@ projectDataBase::Numbering projectDataBase::numbering() const return numbering; } +/** + @brief projectDataBase::numberingSchemes + @return the numbering schemes of @p kind (conductor, element, folio or + cable) by title +*/ +QHash projectDataBase::numberingSchemes(const QString &kind) const +{ + QHash schemes; + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT title FROM numbering_scheme WHERE kind = :kind")); + query.bindValue(QStringLiteral(":kind"), kind); + query.exec(); + while (query.next()) { + schemes.insert(query.value(0).toString(), NumerotationContext()); + } + query.prepare(QStringLiteral("SELECT title, type, value, increase, initialvalue, modulus, format " + "FROM numbering_part WHERE kind = :kind ORDER BY title, ord")); + query.bindValue(QStringLiteral(":kind"), kind); + query.exec(); + while (query.next()) { + const QString title = query.value(0).toString(); + if (!schemes.contains(title)) { + continue; + } + schemes[title].addValue(query.value(1).toString(), query.value(2).toString(), + query.value(3).toInt(), query.value(4).toInt(), + query.value(5).toInt(), query.value(6).toString()); + } + return schemes; +} + +/** + @brief projectDataBase::hasNumberingScheme + @return true if there is a numbering scheme of @p kind titled @p title +*/ +bool projectDataBase::hasNumberingScheme(const QString &kind, const QString &title) const +{ + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT 1 FROM numbering_scheme WHERE kind = :kind AND title = :title")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + return query.exec() && query.next(); +} + +/** + @brief projectDataBase::numberingScheme + @return the numbering scheme of @p kind titled @p title, empty if there + is none +*/ +NumerotationContext projectDataBase::numberingScheme(const QString &kind, const QString &title) const +{ + NumerotationContext context; + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT type, value, increase, initialvalue, modulus, format " + "FROM numbering_part WHERE kind = :kind AND title = :title ORDER BY ord")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + query.exec(); + while (query.next()) { + context.addValue(query.value(0).toString(), query.value(1).toString(), + query.value(2).toInt(), query.value(3).toInt(), + query.value(4).toInt(), query.value(5).toString()); + } + return context; +} + +/** + @brief projectDataBase::numberingSchemeUuid + @return the uuid of the numbering scheme of @p kind titled @p title, + null if there is no such scheme or it has none (only element schemes + have one) +*/ +QUuid projectDataBase::numberingSchemeUuid(const QString &kind, const QString &title) const +{ + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT uuid FROM numbering_scheme WHERE kind = :kind AND title = :title")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + if (query.exec() && query.next()) { + return QUuid(query.value(0).toString()); + } + return QUuid(); +} + +/** + @brief projectDataBase::numberingSchemeTitle + @return the title of the numbering scheme of @p kind whose uuid is + @p uuid, empty if there is none +*/ +QString projectDataBase::numberingSchemeTitle(const QString &kind, const QUuid &uuid) const +{ + if (uuid.isNull()) { + return QString(); + } + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT title FROM numbering_scheme WHERE kind = :kind AND uuid = :uuid")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":uuid"), uuid.toString()); + if (query.exec() && query.next()) { + return query.value(0).toString(); + } + return QString(); +} + +/** + @brief projectDataBase::setNumberingScheme + Add the numbering scheme of @p kind titled @p title, or replace it: + its parts are those of @p context, its uuid @p uuid +*/ +void projectDataBase::setNumberingScheme(const QString &kind, const QString &title, + const NumerotationContext &context, const QUuid &uuid) +{ + QSqlQuery query(m_data_base); + bool ok = true; + query.prepare(QStringLiteral("DELETE FROM numbering_part WHERE kind = :kind AND title = :title")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + ok = ok && query.exec(); + query.prepare(QStringLiteral("INSERT OR REPLACE INTO numbering_scheme (kind, title, uuid) " + "VALUES (:kind, :title, :uuid)")); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + query.bindValue(QStringLiteral(":uuid"), uuid.isNull() ? QVariant() : QVariant(uuid.toString())); + ok = ok && query.exec(); + + query.prepare(QStringLiteral("INSERT INTO numbering_part (kind, title, ord, type, value, " + "increase, initialvalue, modulus, format) VALUES (:kind, :title, " + ":ord, :type, :value, :increase, :initialvalue, :modulus, :format)")); + for (int i = 0 ; i < context.size() ; ++i) + { + const QStringList fields = context.itemAt(i); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + query.bindValue(QStringLiteral(":ord"), i); + int field = 0; + for (const char *name : {":type", ":value", ":increase", ":initialvalue", ":modulus", ":format"}) { + query.bindValue(QLatin1String(name), field < fields.size() ? QVariant(fields.at(field)) + : QVariant()); + ++field; + } + ok = ok && query.exec(); + } + if (!ok) { + qDebug() << "projectDataBase::setNumberingScheme error : " << query.lastError(); + } +} + +/** + @brief projectDataBase::removeNumberingScheme + Remove the numbering scheme of @p kind titled @p title +*/ +void projectDataBase::removeNumberingScheme(const QString &kind, const QString &title) +{ + QSqlQuery query(m_data_base); + for (const char *table : {"numbering_part", "numbering_scheme"}) + { + query.prepare(QStringLiteral("DELETE FROM %1 WHERE kind = :kind AND title = :title") + .arg(QLatin1String(table))); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":title"), title); + if (!query.exec()) { + qDebug() << "projectDataBase::removeNumberingScheme error : " << query.lastError(); + } + } +} + +/** + @brief projectDataBase::renameNumberingScheme + The numbering scheme of @p kind titled @p old_title is titled + @p new_title from now on, with the same parts and uuid. The caller + makes sure no scheme of @p kind is titled @p new_title. +*/ +void projectDataBase::renameNumberingScheme(const QString &kind, const QString &old_title, + const QString &new_title) +{ + QSqlQuery query(m_data_base); + for (const char *table : {"numbering_scheme", "numbering_part"}) + { + query.prepare(QStringLiteral("UPDATE %1 SET title = :new_title " + "WHERE kind = :kind AND title = :old_title") + .arg(QLatin1String(table))); + query.bindValue(QStringLiteral(":new_title"), new_title); + query.bindValue(QStringLiteral(":kind"), kind); + query.bindValue(QStringLiteral(":old_title"), old_title); + if (!query.exec()) { + qDebug() << "projectDataBase::renameNumberingScheme error : " << query.lastError(); + } + } +} + +/** + @brief projectDataBase::numberingSetting + @return the numbering setting @p name (setNumbering() lists them), + @p default_value if it was never set +*/ +QString projectDataBase::numberingSetting(const QString &name, const QString &default_value) const +{ + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("SELECT value FROM numbering_setting WHERE name = :name")); + query.bindValue(QStringLiteral(":name"), name); + if (query.exec() && query.next()) { + return query.value(0).toString(); + } + return default_value; +} + +/** + @brief projectDataBase::numberingFlag + @return numberingSetting() @p name as a flag, @p default_value if it + was never set +*/ +bool projectDataBase::numberingFlag(const QString &name, bool default_value) const +{ + return numberingSetting(name, default_value ? QStringLiteral("true") : QStringLiteral("false")) + == QLatin1String("true"); +} + +/** + @brief projectDataBase::setNumberingSetting + The numbering setting @p name is @p value from now on +*/ +void projectDataBase::setNumberingSetting(const QString &name, const QString &value) +{ + QSqlQuery query(m_data_base); + query.prepare(QStringLiteral("INSERT OR REPLACE INTO numbering_setting (name, value) " + "VALUES (:name, :value)")); + query.bindValue(QStringLiteral(":name"), name); + query.bindValue(QStringLiteral(":value"), value); + if (!query.exec()) { + qDebug() << "projectDataBase::setNumberingSetting error : " << query.lastError(); + } +} + +/** + @brief projectDataBase::setNumberingFlag + setNumberingSetting() for a flag +*/ +void projectDataBase::setNumberingFlag(const QString &name, bool value) +{ + setNumberingSetting(name, value ? QStringLiteral("true") : QStringLiteral("false")); +} + /** @brief projectDataBase::savedLinks The links @p element saves, read from its link rows, in their order diff --git a/sources/dataBase/projectdatabase.h b/sources/dataBase/projectdatabase.h index 8d75dc585..516800a1e 100644 --- a/sources/dataBase/projectdatabase.h +++ b/sources/dataBase/projectdatabase.h @@ -179,6 +179,21 @@ class projectDataBase : public QObject }; void setNumbering(const Numbering &numbering); Numbering numbering() const; + QHash numberingSchemes(const QString &kind) const; + bool hasNumberingScheme(const QString &kind, const QString &title) const; + NumerotationContext numberingScheme(const QString &kind, const QString &title) const; + QUuid numberingSchemeUuid(const QString &kind, const QString &title) const; + QString numberingSchemeTitle(const QString &kind, const QUuid &uuid) const; + void setNumberingScheme(const QString &kind, const QString &title, + const NumerotationContext &context, + const QUuid &uuid = QUuid()); + void removeNumberingScheme(const QString &kind, const QString &title); + void renameNumberingScheme(const QString &kind, const QString &old_title, + const QString &new_title); + QString numberingSetting(const QString &name, const QString &default_value = QString()) const; + bool numberingFlag(const QString &name, bool default_value) const; + void setNumberingSetting(const QString &name, const QString &value); + void setNumberingFlag(const QString &name, bool value); bool savedLinks(const Element *element, QList> *links); //The link rows are written (opening filled them): a symbol //built links from them (Element::initLink()) diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 3e0b541ac..8c4676e79 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -2580,21 +2580,20 @@ void Element::setUpFormula(bool code_letter, QUndoCommand *parent_undo) if (diagram()) { - QString formula = diagram() - ->project() - ->elementAutoNumCurrentFormula(); + QETProject *autonum_project = diagram()->project(); + QString element_currentAutoNum = autonum_project->elementCurrentAutoNum(); + //One query for the scheme's rows, read once and reused below -- + //elementAutoNumCurrentFormula()+elementAutoNum() each re-fetched + //the same rows separately (2b-3: every numbering read is now a + //database query, so a second fetch is a second round trip). + NumerotationContext nc = autonum_project->elementAutoNum(element_currentAutoNum); + QString formula = autonum::numerotationContextToFormula(nc); m_data.m_informations.addValue(QStringLiteral("formula"), formula); storeInformation(); - QString element_currentAutoNum = diagram() - ->project() - ->elementCurrentAutoNum(); - const QUuid scheme_id = diagram()->project()->elementAutoNumId(element_currentAutoNum); + const QUuid scheme_id = autonum_project->elementAutoNumId(element_currentAutoNum); setFormulaSchemeId(formula.isEmpty() ? QUuid() : scheme_id); - NumerotationContext nc = diagram() - ->project() - ->elementAutoNum(element_currentAutoNum); //The number given is the first whose label no other element of //the project carries: a counter set back, or an element which diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index 8b5ec0b61..c8dd66df0 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -93,7 +93,7 @@ m_project_properties_handler{this} QSettings settings; //Read auto break conductor default from global settings - m_auto_break_conductor = settings.value(QStringLiteral("diagrameditor/auto_break_conductor"), false).toBool(); + setAutoBreakConductor(settings.value(QStringLiteral("diagrameditor/auto_break_conductor"), false).toBool()); int size = settings.beginReadArray(QStringLiteral("diagrameditor/defaultguides")); for (int i = 0; i < size; ++i) { @@ -140,8 +140,6 @@ m_project_properties_handler{this} setCurrentCableAutoNum(cableData.second); } } - //m_auto_break_conductor above is read from the settings directly - writeNumberingRows(); } ProjectPropertiesHandler &QETProject::projectPropertiesHandler() @@ -1446,7 +1444,7 @@ void QETProject::setDefaultXRefProperties(QHash hash) */ QHash QETProject::conductorAutoNum() const { - return m_conductor_autonum; + return m_data_base.numberingSchemes(QStringLiteral("conductor")); } /** @@ -1455,7 +1453,7 @@ QHash QETProject::conductorAutoNum() const */ QHash QETProject::elementAutoNum() const { - return m_element_autonum; + return m_data_base.numberingSchemes(QStringLiteral("element")); } /** @@ -1465,7 +1463,7 @@ QHash QETProject::elementAutoNum() const */ QHash QETProject::cableAutoNum() const { - return m_cable_autonum; + return m_data_base.numberingSchemes(QStringLiteral("cable")); } /** @@ -1475,8 +1473,8 @@ QHash QETProject::cableAutoNum() const */ QString QETProject::elementAutoNumFormula (const QString& key) const { - if (m_element_autonum.contains(key)) { - return autonum::numerotationContextToFormula(m_element_autonum[key]); + if (m_data_base.hasNumberingScheme(QStringLiteral("element"), key)) { + return autonum::numerotationContextToFormula(m_data_base.numberingScheme(QStringLiteral("element"), key)); } return QString(); @@ -1488,7 +1486,7 @@ QString QETProject::elementAutoNumFormula (const QString& key) const */ QString QETProject::elementAutoNumCurrentFormula() const { - return elementAutoNumFormula(m_current_element_autonum); + return elementAutoNumFormula(elementCurrentAutoNum()); } /** @@ -1497,7 +1495,7 @@ QString QETProject::elementAutoNumCurrentFormula() const */ QString QETProject::elementCurrentAutoNum () const { - return m_current_element_autonum; + return m_data_base.numberingSetting(QStringLiteral("element_current")); } /** @@ -1505,8 +1503,7 @@ QString QETProject::elementCurrentAutoNum () const @param autoNum : set the current element autonum to autonum */ void QETProject::setCurrrentElementAutonum(QString autoNum) { - m_current_element_autonum = std::move(autoNum); - writeNumberingRows(); + m_data_base.setNumberingSetting(QStringLiteral("element_current"), autoNum); } /** @@ -1516,8 +1513,8 @@ void QETProject::setCurrrentElementAutonum(QString autoNum) { */ QString QETProject::cableAutoNumFormula(const QString& key) const { - if (m_cable_autonum.contains(key)) { - return autonum::numerotationContextToFormula(m_cable_autonum.value(key)); + if (m_data_base.hasNumberingScheme(QStringLiteral("cable"), key)) { + return autonum::numerotationContextToFormula(m_data_base.numberingScheme(QStringLiteral("cable"), key)); } return QString(); @@ -1532,8 +1529,9 @@ QString QETProject::cableAutoNumFormula(const QString& key) const */ bool QETProject::hasCableAutoNum() const { - if (m_current_cable_autonum.isEmpty()) return false; - return !cableAutoNum(m_current_cable_autonum).isEmpty(); + const QString current = cableCurrentAutoNum(); + if (current.isEmpty()) return false; + return !cableAutoNum(current).isEmpty(); } /** @@ -1542,7 +1540,7 @@ bool QETProject::hasCableAutoNum() const */ QString QETProject::cableCurrentAutoNum() const { - return m_current_cable_autonum; + return m_data_base.numberingSetting(QStringLiteral("cable_current")); } /** @@ -1551,8 +1549,7 @@ QString QETProject::cableCurrentAutoNum() const */ void QETProject::setCurrentCableAutoNum(QString autoNum) { - m_current_cable_autonum = std::move(autoNum); - writeNumberingRows(); + m_data_base.setNumberingSetting(QStringLiteral("cable_current"), autoNum); } /** @@ -1572,7 +1569,7 @@ QString QETProject::cableAutoNumRuleName() */ bool QETProject::cableXAxisFirst() const { - return m_cable_axis_x_first; + return m_data_base.numberingFlag(QStringLiteral("cable_x_axis_first"), true); } /** @@ -1584,8 +1581,7 @@ bool QETProject::cableXAxisFirst() const */ void QETProject::setCableXAxisFirst(bool x_axis_first) { - m_cable_axis_x_first = x_axis_first; - writeNumberingRows(); + m_data_base.setNumberingFlag(QStringLiteral("cable_x_axis_first"), x_axis_first); } /** @@ -1598,7 +1594,7 @@ void QETProject::setCableXAxisFirst(bool x_axis_first) */ bool QETProject::cableAskNumbering() const { - return m_cable_ask_numbering; + return m_data_base.numberingFlag(QStringLiteral("cable_ask_numbering"), true); } /** @@ -1611,8 +1607,7 @@ bool QETProject::cableAskNumbering() const */ void QETProject::setCableAskNumbering(bool ask) { - m_cable_ask_numbering = ask; - writeNumberingRows(); + m_data_base.setNumberingFlag(QStringLiteral("cable_ask_numbering"), ask); } /** @@ -1645,8 +1640,8 @@ void QETProject::renumberElementsBySchemeTitle(const QString &scheme_title) */ QString QETProject::conductorAutoNumFormula (const QString& key) const { - if (m_conductor_autonum.contains(key)) - return autonum::numerotationContextToFormula(m_conductor_autonum.value(key)); + if (m_data_base.hasNumberingScheme(QStringLiteral("conductor"), key)) + return autonum::numerotationContextToFormula(m_data_base.numberingScheme(QStringLiteral("conductor"), key)); else return QString(); } @@ -1657,7 +1652,7 @@ QString QETProject::conductorAutoNumFormula (const QString& key) const */ QString QETProject::conductorCurrentAutoNum () const { - return m_current_conductor_autonum; + return m_data_base.numberingSetting(QStringLiteral("conductor_current")); } /** @@ -1665,8 +1660,7 @@ QString QETProject::conductorCurrentAutoNum () const @param autoNum set the current conductor autonum to autonum */ void QETProject::setCurrentConductorAutoNum(QString autoNum) { - m_current_conductor_autonum = std::move(autoNum); - writeNumberingRows(); + m_data_base.setNumberingSetting(QStringLiteral("conductor_current"), autoNum); } /** @@ -1675,7 +1669,7 @@ void QETProject::setCurrentConductorAutoNum(QString autoNum) { */ QHash QETProject::folioAutoNum() const { - return m_folio_autonum; + return m_data_base.numberingSchemes(QStringLiteral("folio")); } /** @@ -1686,8 +1680,7 @@ QHash QETProject::folioAutoNum() const @param context */ void QETProject::addConductorAutoNum(const QString& key, const NumerotationContext& context) { - m_conductor_autonum.insert(key, context); - writeNumberingRows(); + m_data_base.setNumberingScheme(QStringLiteral("conductor"), key, context); emit autoNumContextUpdated(); } @@ -1725,14 +1718,12 @@ void QETProject::addElementAutoNum(const QString &key, } } if (scheme_id.isNull()) { - scheme_id = m_element_autonum_id.value(key); + scheme_id = elementAutoNumId(key); } if (scheme_id.isNull()) { scheme_id = QUuid::createUuid(); } - m_element_autonum_id.insert(key, scheme_id); - m_element_autonum.insert(key, context); - writeNumberingRows(); + m_data_base.setNumberingScheme(QStringLiteral("element"), key, context, scheme_id); emit elementAutoNumAdded(key); emit autoNumContextUpdated(); } @@ -1744,7 +1735,7 @@ void QETProject::addElementAutoNum(const QString &key, */ QUuid QETProject::elementAutoNumId(const QString &title) const { - return m_element_autonum_id.value(title); + return m_data_base.numberingSchemeUuid(QStringLiteral("element"), title); } /** @@ -1754,16 +1745,7 @@ QUuid QETProject::elementAutoNumId(const QString &title) const */ QString QETProject::elementAutoNumTitle(const QUuid &id) const { - if (id.isNull()) { - return QString(); - } - for (auto it = m_element_autonum_id.constBegin(); - it != m_element_autonum_id.constEnd(); ++it) { - if (it.value() == id) { - return it.key(); - } - } - return QString(); + return m_data_base.numberingSchemeTitle(QStringLiteral("element"), id); } /** @@ -1779,18 +1761,17 @@ QString QETProject::elementAutoNumTitle(const QUuid &id) const bool QETProject::renameElementAutoNum(const QString &old_title, const QString &new_title) { if (old_title == new_title) { - return m_element_autonum.contains(old_title); + return m_data_base.hasNumberingScheme(QStringLiteral("element"), old_title); } - if (!m_element_autonum.contains(old_title) - || m_element_autonum.contains(new_title) + if (!m_data_base.hasNumberingScheme(QStringLiteral("element"), old_title) + || m_data_base.hasNumberingScheme(QStringLiteral("element"), new_title) || new_title.isEmpty()) { return false; } - m_element_autonum.insert(new_title, m_element_autonum.take(old_title)); - m_element_autonum_id.insert(new_title, m_element_autonum_id.take(old_title)); - if (m_current_element_autonum == old_title) { - m_current_element_autonum = new_title; + m_data_base.renameNumberingScheme(QStringLiteral("element"), old_title, new_title); + if (elementCurrentAutoNum() == old_title) { + m_data_base.setNumberingSetting(QStringLiteral("element_current"), new_title); } for (Diagram *d : std::as_const(m_diagrams_list)) { @@ -1804,7 +1785,6 @@ bool QETProject::renameElementAutoNum(const QString &old_title, const QString &n } } - writeNumberingRows(); emit elementAutoNumRemoved(old_title); emit elementAutoNumAdded(new_title); emit autoNumContextUpdated(); @@ -1835,8 +1815,8 @@ QString QETProject::elementAutoNumNameClash(const QString &name, const QString &ignored_title) const { const QString wanted = normalizedAutoNumName(name); - for (auto it = m_element_autonum.constBegin(); - it != m_element_autonum.constEnd(); ++it) { + const QHash schemes = m_data_base.numberingSchemes(QStringLiteral("element")); + for (auto it = schemes.constBegin(); it != schemes.constEnd(); ++it) { if (it.key() == ignored_title) { continue; } @@ -1906,13 +1886,16 @@ void QETProject::linkElementsToElementAutoNums() void QETProject::linkElementsToElementAutoNums(Diagram *folio) { const QHash titles_by_formula = elementAutoNumTitlesByFormula(); + QHash title_cache; + QHash id_cache; { const auto items = folio->items(); for (QGraphicsItem *it : items) { auto *el = qgraphicsitem_cast(it); if (!el) continue; if (const auto id = elementAutoNumIdToLink(el->elementInformations(), - titles_by_formula)) { + titles_by_formula, + &title_cache, &id_cache)) { el->setFormulaSchemeId(*id); } } @@ -1926,8 +1909,8 @@ void QETProject::linkElementsToElementAutoNums(Diagram *folio) QHash QETProject::elementAutoNumTitlesByFormula() const { QHash titles_by_formula; - for (auto it = m_element_autonum.constBegin(); - it != m_element_autonum.constEnd(); ++it) { + const QHash schemes = m_data_base.numberingSchemes(QStringLiteral("element")); + for (auto it = schemes.constBegin(); it != schemes.constEnd(); ++it) { titles_by_formula[autonum::numerotationContextToFormula(it.value())] << it.key(); } return titles_by_formula; @@ -1942,7 +1925,9 @@ QHash QETProject::elementAutoNumTitlesByFormula() const */ std::optional QETProject::elementAutoNumIdToLink( const DiagramContext &information, - const QHash &titles_by_formula) const + const QHash &titles_by_formula, + QHash *title_cache, + QHash *id_cache) const { const QString formula = information.value(QETInformation::ELMT_FORMULA).toString(); const bool has_id = information.contains(QETInformation::ELMT_FORMULA_ID); @@ -1952,14 +1937,36 @@ std::optional QETProject::elementAutoNumIdToLink( if (has_id) return QUuid(); return std::nullopt; } - if (!elementAutoNumTitle(id).isEmpty()) { + //Every symbol following the same scheme repeats the same id/title + //lookup; a project database query per symbol is the ASan-visible + //cost (F134-adjacent, 2b-3), so a caller walking many symbols may + //pass caches that live only for that one walk -- never persisted. + QString title; + if (title_cache && title_cache->contains(id)) { + title = title_cache->value(id); + } else { + title = elementAutoNumTitle(id); + if (title_cache) title_cache->insert(id, title); + } + if (!title.isEmpty()) { return std::nullopt; } if (!has_id && !m_legacy_element_autonums) { return std::nullopt; //A formula typed by hand } const QStringList matches = titles_by_formula.value(formula); - return matches.size() == 1 ? elementAutoNumId(matches.first()) : QUuid(); + if (matches.size() != 1) { + return QUuid(); + } + const QString &match = matches.first(); + if (id_cache) { + auto it = id_cache->find(match); + if (it == id_cache->end()) { + it = id_cache->insert(match, elementAutoNumId(match)); + } + return it.value(); + } + return elementAutoNumId(match); } /** @@ -2006,13 +2013,18 @@ QList QETProject::symbolNumbering() const for (Diagram *d : m_diagrams_list) if (!d->isLoaded()) unbuilt_in_order << d->uuid(); const QHash titles_by_formula = elementAutoNumTitlesByFormula(); + //Every symbol on an unbuilt folio following the same scheme repeats + //the same title/id lookup; cache both directions for this one walk + //(never persisted -- a scheme rename between calls must see it). + QHash title_cache; + QHash id_cache; for (const projectDataBase::FolioSymbol &row : m_data_base.symbolsOnFolios(unbuilt_in_order)) { const DiagramContext info = m_data_base.elementInformation(row.uuid); SymbolNumbering symbol; symbol.label = info.value(QETInformation::ELMT_LABEL).toString(); symbol.formula = info.value(QETInformation::ELMT_FORMULA).toString(); - const auto linked = elementAutoNumIdToLink(info, titles_by_formula); + const auto linked = elementAutoNumIdToLink(info, titles_by_formula, &title_cache, &id_cache); symbol.scheme = linked ? *linked : QUuid(info.value(QETInformation::ELMT_FORMULA_ID).toString()); symbol.sequence = row.sequence; @@ -2032,8 +2044,7 @@ QList QETProject::symbolNumbering() const @param context */ void QETProject::addFolioAutoNum(const QString& key, const NumerotationContext& context) { - m_folio_autonum.insert(key, context); - writeNumberingRows(); + m_data_base.setNumberingScheme(QStringLiteral("folio"), key, context); emit autoNumContextUpdated(); } @@ -2048,19 +2059,19 @@ void QETProject::addFolioAutoNum(const QString& key, const NumerotationContext& void QETProject::addCableAutoNum(const QString& key, const NumerotationContext& context) { if (!key.isEmpty()) { - const QStringList others = m_cable_autonum.keys(); + const QStringList others = cableAutoNum().keys(); for (const QString &other : others) { - if (other != key) m_cable_autonum.remove(other); + if (other != key) m_data_base.removeNumberingScheme(QStringLiteral("cable"), other); } } - m_cable_autonum.insert(key, context); + m_data_base.setNumberingScheme(QStringLiteral("cable"), key, context); //The rule in use must always be one which exists: after a save //under another name the old entry is gone, so follow the new one. - if (!key.isEmpty() && (m_current_cable_autonum.isEmpty() - || !m_cable_autonum.contains(m_current_cable_autonum))) { - m_current_cable_autonum = key; + const QString current = cableCurrentAutoNum(); + if (!key.isEmpty() && (current.isEmpty() + || !m_data_base.hasNumberingScheme(QStringLiteral("cable"), current))) { + m_data_base.setNumberingSetting(QStringLiteral("cable_current"), key); } - writeNumberingRows(); emit autoNumContextUpdated(); } @@ -2070,8 +2081,7 @@ void QETProject::addCableAutoNum(const QString& key, const NumerotationContext& @param key */ void QETProject::removeConductorAutoNum(const QString& key) { - m_conductor_autonum.remove(key); - writeNumberingRows(); + m_data_base.removeNumberingScheme(QStringLiteral("conductor"), key); } /** @@ -2081,9 +2091,7 @@ void QETProject::removeConductorAutoNum(const QString& key) { */ void QETProject::removeElementAutoNum(const QString& key) { - m_element_autonum.remove(key); - m_element_autonum_id.remove(key); - writeNumberingRows(); + m_data_base.removeNumberingScheme(QStringLiteral("element"), key); emit elementAutoNumRemoved(key); } @@ -2093,8 +2101,7 @@ void QETProject::removeElementAutoNum(const QString& key) @param key */ void QETProject::removeFolioAutoNum(const QString& key) { - m_folio_autonum.remove(key); - writeNumberingRows(); + m_data_base.removeNumberingScheme(QStringLiteral("folio"), key); } /** @@ -2104,12 +2111,12 @@ void QETProject::removeFolioAutoNum(const QString& key) { */ void QETProject::removeCableAutoNum(const QString& key) { - m_cable_autonum.remove(key); - if (m_current_cable_autonum == key) { - m_current_cable_autonum = m_cable_autonum.isEmpty() - ? QString() : m_cable_autonum.keys().first(); + m_data_base.removeNumberingScheme(QStringLiteral("cable"), key); + if (cableCurrentAutoNum() == key) { + const QStringList left = cableAutoNum().keys(); + m_data_base.setNumberingSetting(QStringLiteral("cable_current"), + left.isEmpty() ? QString() : left.first()); } - writeNumberingRows(); emit autoNumContextUpdated(); } @@ -2121,8 +2128,7 @@ void QETProject::removeCableAutoNum(const QString& key) */ NumerotationContext QETProject::conductorAutoNum (const QString &key) const { - if (m_conductor_autonum.contains(key)) return m_conductor_autonum[key]; - else return NumerotationContext(); + return m_data_base.numberingScheme(QStringLiteral("conductor"), key); } /** @@ -2132,8 +2138,7 @@ NumerotationContext QETProject::conductorAutoNum (const QString &key) const @param key */ NumerotationContext QETProject::elementAutoNum (const QString &key) { - if (m_element_autonum.contains(key)) return m_element_autonum[key]; - else return NumerotationContext(); + return m_data_base.numberingScheme(QStringLiteral("element"), key); } /** @@ -2144,8 +2149,7 @@ NumerotationContext QETProject::elementAutoNum (const QString &key) { */ NumerotationContext QETProject::folioAutoNum (const QString &key) const { - if (m_folio_autonum.contains(key)) return m_folio_autonum[key]; - else return NumerotationContext(); + return m_data_base.numberingScheme(QStringLiteral("folio"), key); } /** @@ -2156,8 +2160,7 @@ NumerotationContext QETProject::folioAutoNum (const QString &key) const */ NumerotationContext QETProject::cableAutoNum(const QString &key) const { - if (m_cable_autonum.contains(key)) return m_cable_autonum.value(key); - else return NumerotationContext(); + return m_data_base.numberingScheme(QStringLiteral("cable"), key); } /** @@ -2193,7 +2196,7 @@ void QETProject::freezeNewConductorLabel(bool freeze, int from, int to) { */ bool QETProject::isFreezeNewConductors() { - return m_freeze_new_conductors; + return m_data_base.numberingFlag(QStringLiteral("freeze_new_conductors"), false); } /** @@ -2201,8 +2204,7 @@ bool QETProject::isFreezeNewConductors() Set Project Wide freeze new conductors */ void QETProject::setFreezeNewConductors(bool set) { - m_freeze_new_conductors = set; - writeNumberingRows(); + m_data_base.setNumberingFlag(QStringLiteral("freeze_new_conductors"), set); } /** @@ -2238,7 +2240,7 @@ void QETProject::freezeNewElementLabel(bool freeze, int from, int to) { */ bool QETProject::isFreezeNewElements() { - return m_freeze_new_elements; + return m_data_base.numberingFlag(QStringLiteral("freeze_new_elements"), false); } /** @@ -2246,8 +2248,7 @@ bool QETProject::isFreezeNewElements() Set Project Wide freeze new elements */ void QETProject::setFreezeNewElements(bool set) { - m_freeze_new_elements = set; - writeNumberingRows(); + m_data_base.setNumberingFlag(QStringLiteral("freeze_new_elements"), set); } /** @@ -2368,7 +2369,7 @@ void QETProject::setWiringRules(const WiringRules::Settings &rules) */ bool QETProject::autoBreakConductor() const { - return m_auto_break_conductor; + return m_data_base.numberingFlag(QStringLiteral("auto_break_conductors"), false); } /** @@ -2379,9 +2380,7 @@ bool QETProject::autoBreakConductor() const */ void QETProject::setAutoBreakConductor(bool abc) { - if (abc != m_auto_break_conductor) - m_auto_break_conductor = abc; - writeNumberingRows(); + m_data_base.setNumberingFlag(QStringLiteral("auto_break_conductors"), abc); } /** @@ -3970,16 +3969,39 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) m_default_xref_properties.insert(elmt.attribute(QStringLiteral("type")), xrp); } } + //The numbering read here goes to the project database, its only + //home (QETZ-DB-FIRST stage 2b-3), in one go once it is all read + QHash conductor_autonum = conductorAutoNum(); + QHash folio_autonum = folioAutoNum(); + QHash element_autonum = elementAutoNum(); + QHash element_autonum_id; + for (auto it = element_autonum.cbegin() ; it != element_autonum.cend() ; ++it) { + element_autonum_id.insert(it.key(), elementAutoNumId(it.key())); + } + QHash cable_autonum = cableAutoNum(); + projectDataBase::Numbering numbering; + numbering.current_conductor = conductorCurrentAutoNum(); + numbering.current_element = elementCurrentAutoNum(); + numbering.current_cable = cableCurrentAutoNum(); + numbering.freeze_new_conductors = isFreezeNewConductors(); + numbering.freeze_new_elements = isFreezeNewElements(); + numbering.auto_break_conductors = autoBreakConductor(); + numbering.cable_x_axis_first = cableXAxisFirst(); + numbering.cable_ask_numbering = cableAskNumbering(); + auto element_title = [&element_autonum_id](const QUuid &id) { + return id.isNull() ? QString() : element_autonum_id.key(id); + }; + if (!conds_autonums.isNull()) { - m_current_conductor_autonum = conds_autonums.attribute(QStringLiteral("current_autonum")); - m_freeze_new_conductors = conds_autonums.attribute(QStringLiteral("freeze_new_conductors")) == QLatin1String("true"); - m_auto_break_conductor = conds_autonums.attribute(QStringLiteral("auto_break_conductors")) == QLatin1String("true"); + numbering.current_conductor = conds_autonums.attribute(QStringLiteral("current_autonum")); + numbering.freeze_new_conductors = conds_autonums.attribute(QStringLiteral("freeze_new_conductors")) == QLatin1String("true"); + numbering.auto_break_conductors = conds_autonums.attribute(QStringLiteral("auto_break_conductors")) == QLatin1String("true"); for (auto elmt : QET::findInDomElement(conds_autonums, QStringLiteral("conductor_autonum"))) { NumerotationContext nc; nc.fromXml(elmt); - m_conductor_autonum.insert(elmt.attribute("title"), nc); + conductor_autonum.insert(elmt.attribute("title"), nc); } } if (!folio_autonums.isNull()) @@ -3988,20 +4010,20 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) { NumerotationContext nc; nc.fromXml(elmt); - m_folio_autonum.insert(elmt.attribute(QStringLiteral("title")), nc); + folio_autonum.insert(elmt.attribute(QStringLiteral("title")), nc); } } if (!element_autonums.isNull()) { - m_current_element_autonum = element_autonums.attribute(QStringLiteral("current_autonum")); - m_freeze_new_elements = element_autonums.attribute(QStringLiteral("freeze_new_elements")) == QLatin1String("true"); + numbering.current_element = element_autonums.attribute(QStringLiteral("current_autonum")); + numbering.freeze_new_elements = element_autonums.attribute(QStringLiteral("freeze_new_elements")) == QLatin1String("true"); for (auto elmt : QET::findInDomElement(element_autonums, QStringLiteral("element_autonum"))) { NumerotationContext nc; nc.fromXml(elmt); const QString title = elmt.attribute(QStringLiteral("title")); QUuid id(elmt.attribute(QStringLiteral("id"))); - if (id.isNull() || !elementAutoNumTitle(id).isEmpty()) { + if (id.isNull() || !element_title(id).isEmpty()) { //Saved before schemes had an id: derive one, the //same on every load of the file. m_legacy_element_autonums = true; @@ -4010,30 +4032,30 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) id = derivedItemUuid(QStringLiteral("element_autonum"), m_uuid.toString() + QLatin1Char('\n') + title); } - m_element_autonum.insert(title, nc); - m_element_autonum_id.insert(title, id); + element_autonum.insert(title, nc); + element_autonum_id.insert(title, id); } //The id is authoritative, the title is kept for older versions - const QString current_title = elementAutoNumTitle( + const QString current_title = element_title( QUuid(element_autonums.attribute(QStringLiteral("current_autonum_id")))); if (!current_title.isEmpty()) { - m_current_element_autonum = current_title; + numbering.current_element = current_title; } } if (!cable_autonums.isNull()) { - m_current_cable_autonum = cable_autonums.attribute(QStringLiteral("current_autonum")); + numbering.current_cable = cable_autonums.attribute(QStringLiteral("current_autonum")); //Which axis the cables are numbered along. A file written //before this existed has no say in it and stays with the //axis the terminals have always started from. - m_cable_axis_x_first = cable_autonums.attribute( + numbering.cable_x_axis_first = cable_autonums.attribute( QStringLiteral("axis_priority"), QStringLiteral("x")) != QLatin1String("y"); //Whether the numbering question was already answered with //no in this project. A file which does not hold the answer //yet asks again rather than staying silent: it is his own //answer per project which is kept, not a default saying no. - m_cable_ask_numbering = cable_autonums.attribute( + numbering.cable_ask_numbering = cable_autonums.attribute( QStringLiteral("ask_numbering_rule"), QStringLiteral("true")) != QLatin1String("false"); for (auto elmt : QET::findInDomElement(cable_autonums, QStringLiteral("cable_autonum"))) @@ -4041,16 +4063,27 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) NumerotationContext nc; nc.fromXml(elmt); if (elmt.attribute(QStringLiteral("title")).isEmpty()) continue; - m_cable_autonum.insert(elmt.attribute(QStringLiteral("title")), nc); + cable_autonum.insert(elmt.attribute(QStringLiteral("title")), nc); } //A file written by hand, or written before this rule existed, //may name a rule which is not in the list: the numbering must //never be left pointing at something which is not there. - if (!m_cable_autonum.contains(m_current_cable_autonum)) { - m_current_cable_autonum = m_cable_autonum.isEmpty() - ? QString() : m_cable_autonum.keys().first(); + if (!cable_autonum.contains(numbering.current_cable)) { + numbering.current_cable = cable_autonum.isEmpty() + ? QString() : cable_autonum.keys().first(); } } + auto add = [&numbering](const QString &kind, const QHash &schemes, + const QHash &ids) { + for (auto it = schemes.cbegin() ; it != schemes.cend() ; ++it) + numbering.schemes << projectDataBase::NumberingScheme{kind, it.key(), ids.value(it.key()), it.value()}; + }; + add(QStringLiteral("conductor"), conductor_autonum, {}); + add(QStringLiteral("folio"), folio_autonum, {}); + add(QStringLiteral("element"), element_autonum, element_autonum_id); + add(QStringLiteral("cable"), cable_autonum, {}); + m_data_base.setNumbering(numbering); + // Read guides from XML (if missing, e.g. in old projects, list stays empty) m_default_guides.clear(); @@ -4063,7 +4096,6 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project) m_default_guides.append(g); } } - writeNumberingRows(); } /** @@ -4247,24 +4279,9 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element) } xml_element.appendChild(xrefs_elmt); - //The numbering is written from the project database's rows - //(QETZ-DB-FIRST stage 2b-2), which the project keeps in step - //(writeNumberingRows()) + //The numbering is written from the project database, its only + //home (QETZ-DB-FIRST stage 2b) writeNumberingXml(m_data_base.numbering(), xml_element); - //QET_CHECK_NUMBERING_ROWS=1: say whether the project database's - //numbering rows write what the project holds. A test and - //debugging aid; it changes nothing. - if (qEnvironmentVariableIntValue("QET_CHECK_NUMBERING_ROWS") == 1) { - QDomDocument from_project, from_rows; - QDomElement project_root = from_project.createElement(QStringLiteral("numbering")); - QDomElement rows_root = from_rows.createElement(QStringLiteral("numbering")); - from_project.appendChild(project_root); - from_rows.appendChild(rows_root); - writeNumberingXml(numberingOfProject(), project_root); - writeNumberingXml(m_data_base.numbering(), rows_root); - const bool same = from_project.toString() == from_rows.toString(); - qWarning().noquote() << "numbering rows:" << (same ? 0 : 1) << "differ"; - } // Export default guides QDomElement guides_elmt = xml_document.createElement("guides"); @@ -4278,48 +4295,6 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element) xml_element.appendChild(guides_elmt); } -/** - @brief QETProject::numberingOfProject - @return the project's numbering schemes and their settings, as the - project holds them, for the project database's numbering tables - (QETZ-DB-FIRST stage 2b) and for the save -*/ -projectDataBase::Numbering QETProject::numberingOfProject() const -{ - projectDataBase::Numbering numbering; - auto add = [&numbering](const QString &kind, const QHash &schemes, - const QHash &ids) { - for (auto it = schemes.cbegin() ; it != schemes.cend() ; ++it) - numbering.schemes << projectDataBase::NumberingScheme{kind, it.key(), ids.value(it.key()), it.value()}; - }; - add(QStringLiteral("conductor"), m_conductor_autonum, {}); - add(QStringLiteral("folio"), m_folio_autonum, {}); - add(QStringLiteral("element"), m_element_autonum, m_element_autonum_id); - add(QStringLiteral("cable"), m_cable_autonum, {}); - numbering.current_conductor = m_current_conductor_autonum; - numbering.current_element = m_current_element_autonum; - numbering.current_cable = m_current_cable_autonum; - numbering.freeze_new_conductors = m_freeze_new_conductors; - numbering.freeze_new_elements = m_freeze_new_elements; - numbering.auto_break_conductors = m_auto_break_conductor; - numbering.cable_x_axis_first = m_cable_axis_x_first; - numbering.cable_ask_numbering = m_cable_ask_numbering; - return numbering; -} - -/** - @brief QETProject::writeNumberingRows - Write the project's numbering into the project database's numbering - tables (QETZ-DB-FIRST stage 2b-1): after reading the file and after - each change of the numbering. The save writes the numbering from - them (2b-2); QET_CHECK_NUMBERING_ROWS says whether they hold what - the project does -*/ -void QETProject::writeNumberingRows() -{ - m_data_base.setNumbering(numberingOfProject()); -} - /** @brief QETProject::writeNumberingXml Export @p numbering as the , , diff --git a/sources/qetproject.h b/sources/qetproject.h index a7b9e7613..1675f2627 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -457,8 +457,6 @@ class QETProject : public QObject void writeProjectPropertiesXml(QDomElement &); void writeDefaultPropertiesXml(QDomElement &); - projectDataBase::Numbering numberingOfProject() const; - void writeNumberingRows(); static void writeNumberingXml(const projectDataBase::Numbering &numbering, QDomElement &xml_element); void writeUsageXml(QDomElement &); @@ -531,26 +529,6 @@ class QETProject : public QObject DiagramContext m_project_properties; /// undo stack for this project QUndoStack *m_undo_stack; - /// Conductor auto numerotation - QHash m_conductor_autonum;//Title and NumContext hash - QString m_current_conductor_autonum; - /// Folio auto numbering - QHash m_folio_autonum; - /// Element Auto Numbering - QHash m_element_autonum; //Title and NumContext hash - /// Title -> uuid of each element numbering scheme - QHash m_element_autonum_id; - QString m_current_element_autonum; - /// Cable auto numbering: exactly one rule, kept the same way - /// the others are so it stores and travels with the project - /// alike, but never a list to choose from. - QHash m_cable_autonum; - QString m_current_cable_autonum; - ///< which axis the cables are numbered along (see cableXAxisFirst) - bool m_cable_axis_x_first = true; - ///< whether the cable tool still asks about a numbering rule - ///< for this project (see cableAskNumbering) - bool m_cable_ask_numbering = true; /// True when the loaded file had element numbering schemes /// saved without an id (written before ids existed) bool m_legacy_element_autonums = false; @@ -559,7 +537,9 @@ class QETProject : public QObject QHash elementAutoNumTitlesByFormula() const; std::optional elementAutoNumIdToLink( const DiagramContext &information, - const QHash &titles_by_formula) const; + const QHash &titles_by_formula, + QHash *title_cache = nullptr, + QHash *id_cache = nullptr) const; bool m_deferring_folios = false; /// Opening with folios built only when needed: QET_LAZY_FOLIOS /// is set and the database can be filled from the document @@ -598,10 +578,7 @@ class QETProject : public QObject /// project, off for one saved without it), see uprightSymbolTexts() bool m_upright_symbol_texts = false; WiringRules::Settings m_wiring_rules; - bool m_auto_break_conductor = false; XmlElementCollection *m_elements_collection = nullptr; - bool m_freeze_new_elements = false; - bool m_freeze_new_conductors = false; QTimer m_save_backup_timer, m_autosave_timer; QFuture m_backup_future; diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index f80592668..d5753ce50 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -92,7 +92,7 @@ if(Python3_Interpreter_FOUND AND CMAKE_GENERATOR STREQUAL "Ninja") --build ${CMAKE_BINARY_DIR} --binary $ --source ${CMAKE_CURRENT_SOURCE_DIR}/lazy_folios_probe.cpp --fixture ${CMAKE_CURRENT_SOURCE_DIR}/../../examples/industrial.qet) - set_tests_properties(tst_lazyfolios PROPERTIES TIMEOUT 1800 RUN_SERIAL TRUE + set_tests_properties(tst_lazyfolios PROPERTIES TIMEOUT 3000 RUN_SERIAL TRUE ENVIRONMENT "QT_QPA_PLATFORM=offscreen") # Deleting a cable, undoing the delete twice and then editing anything # has both cable commands tearing down the same cable. Runs under the diff --git a/tests/qttest/run_lazy_folios_probe.py b/tests/qttest/run_lazy_folios_probe.py index af41a0fcc..41a2503bc 100644 --- a/tests/qttest/run_lazy_folios_probe.py +++ b/tests/qttest/run_lazy_folios_probe.py @@ -54,7 +54,7 @@ subprocess.run([ninja, '-C', str(build), '-f', probe_manifest.name, target], che output = build / 'lazy-folios' output.mkdir(exist_ok=True) report = output / 'results.txt' -result = subprocess.run([str(probe_binary), str(fixture), str(report), str(output)], timeout=1500) +result = subprocess.run([str(probe_binary), str(fixture), str(report), str(output)], timeout=2400) if report.exists(): print(report.read_text(encoding='utf-8', errors='replace')) sys.exit(result.returncode) diff --git a/tests/qttest/tst_elementautonumids.cpp b/tests/qttest/tst_elementautonumids.cpp index 565a25111..b6c7646ba 100644 --- a/tests/qttest/tst_elementautonumids.cpp +++ b/tests/qttest/tst_elementautonumids.cpp @@ -42,7 +42,6 @@ class tst_elementautonumids : public QObject int m_run = 0; QString m_preferences; // contents of the settings file of the next run - bool m_check_numbering = false; // QET_CHECK_NUMBERING_ROWS for the runs QProcessEnvironment environment() { @@ -62,9 +61,6 @@ class tst_elementautonumids : public QObject env.insert(QStringLiteral("QET_SETTINGS_DIR"), settings_dir); env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen")); env.insert(QStringLiteral("QET_ENABLE_SCRIPTING"), QStringLiteral("1")); - if (m_check_numbering) { - env.insert(QStringLiteral("QET_CHECK_NUMBERING_ROWS"), 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")); @@ -729,29 +725,45 @@ qet.log('PROBE ' + JSON.stringify(r)); // the folios which read the numbering with it (26 folios of // industrial.qet read "Wire"), a numbering which folios read cannot be // removed, an unused one can, and every step is one undo. - // The project database's numbering rows (QETZ-DB-FIRST stage 2b-1) - // follow every change of the numbering: each save below writes the - // numbering from the project and from the rows, and the two must be - // the same (QET_CHECK_NUMBERING_ROWS). A scheme of each kind added, - // renamed, removed, undone and redone, then made current; a - // renumbering and its undo. On a one-folio project: a --run script - // is stopped after 30 s, and a sanitizer build is slow. + // The project database is the only home of the numbering (QETZ-DB-FIRST + // stage 2b): every change of it is read back, and saved, from there. + // A scheme of each kind added, renamed, removed, undone and redone, + // then made current; a renumbering and its undo; the scheme list is + // checked after each step and the project saved. On a one-folio + // project: a --run script is stopped after 30 s, and a sanitizer + // build is slow. void numberingRowsFollowEveryChange() { const QString saved = m_dir.filePath(QStringLiteral("numbering-rows.qet")); const QString script = QStringLiteral(R"JS( -var saves = 0; +var saves = 0, wrong = []; function save() { if (qet.save(%1)) saves++; } +function has(k, title) { + return qet.autoNums(k).some(function (n) { return n.split(': formula=')[0] === title; }); +} +function formula(k, title) { + var found = qet.autoNums(k).filter(function (n) { return n.split(': formula=')[0] === title; }); + return found.length ? found[0].split(': formula=')[1].replace(/^'|'$/g, '') : null; +} +function expect(step, k, present, absent) { + if (present && !has(k, present)) wrong.push(step + ' ' + k + ': no ' + present); + if (present && !formula(k, present)) wrong.push(step + ' ' + k + ': ' + present + ' has no parts'); + if (absent && has(k, absent)) wrong.push(step + ' ' + k + ': still ' + absent); + var left = qet.query('SELECT COUNT(*) AS n FROM numbering_part p WHERE NOT EXISTS (SELECT 1 ' + + 'FROM numbering_scheme s WHERE s.kind = p.kind AND s.title = p.title)'); + if (!left.length || left[0].n !== 0) wrong.push(step + ' ' + k + ': parts of no scheme'); +} save(); ['conductor', 'element', 'folio'].forEach(function (k) { - qet.addAutoNum(k, 'Rows ' + k, ['string:R-', 'unit:7:2']); save(); - qet.renameAutoNum(k, 'Rows ' + k, 'Rows renamed ' + k); save(); - qet.undo(); save(); - qet.redo(); save(); + var first = 'Rows ' + k, renamed = 'Rows renamed ' + k; + qet.addAutoNum(k, first, ['string:R-', 'unit:7:2']); expect('add', k, first); save(); + qet.renameAutoNum(k, first, renamed); expect('rename', k, renamed, first); save(); + qet.undo(); expect('undo', k, first, renamed); save(); + qet.redo(); expect('redo', k, renamed, first); save(); }); ['conductor', 'element', 'folio'].forEach(function (k) { - qet.removeAutoNum(k, 'Rows renamed ' + k); save(); - qet.undo(); save(); + qet.removeAutoNum(k, 'Rows renamed ' + k); expect('remove', k, null, 'Rows renamed ' + k); save(); + qet.undo(); expect('undo remove', k, 'Rows renamed ' + k); save(); }); qet.useElementAutoNum('Rows renamed element'); save(); qet.useConductorAutoNum(0, 'Rows renamed conductor'); save(); @@ -760,10 +772,9 @@ var renumbered = qet.renumberElementAutoNum(schemes[0].split(': formula=')[0]) > save(); if (renumbered) qet.undo(); save(); -qet.log('PROBE ' + JSON.stringify({saves: saves})); +qet.log('PROBE ' + JSON.stringify({saves: saves, wrong: wrong})); )JS").arg(QStringLiteral("'") + saved + QStringLiteral("'")); - m_check_numbering = true; const QString path = m_dir.filePath(QStringLiteral("probe%1.js").arg(m_run)); QFile f(path); QVERIFY(f.open(QIODevice::WriteOnly)); @@ -771,22 +782,19 @@ qet.log('PROBE ' + JSON.stringify({saves: saves})); f.close(); QProcess proc; proc.setProcessEnvironment(environment()); - m_check_numbering = false; proc.start(QStringLiteral(QET_TEST_BINARY_PATH), {QStringLiteral("--run"), path, QStringLiteral(QET_EXAMPLES_DIR "/741.qet")}); QVERIFY(proc.waitForFinished(180000)); const QString out = QString::fromUtf8(proc.readAllStandardOutput() + proc.readAllStandardError()); - QVERIFY2(out.contains(QLatin1String("PROBE {\"saves\":23}")), qPrintable(out.right(2000))); - QCOMPARE(out.count(QLatin1String("numbering rows: 0 differ")), 23); - QCOMPARE(out.count(QLatin1String("numbering rows:")), 23); + QVERIFY2(out.contains(QLatin1String("PROBE {\"saves\":23,\"wrong\":[]}")), qPrintable(out.right(2000))); // the changes are in the file: the folio numbering's removal was // undone, the wires of the first folio follow the new numbering const QByteArray xml = read(saved); QVERIFY(xml.contains("title=\"Rows renamed folio\"")); QCOMPARE(diagramAttributes(xml, QStringLiteral("conductorAutonum")).value(0), QStringLiteral("Rows renamed conductor")); - // and the save, which writes the numbering from the rows (2b-2), + // and the save, which writes the numbering from the database, // has every scheme and the ones made current const Saved numbering = parse(xml); QCOMPARE(numbering.current, QStringLiteral("Rows renamed element"));