Merge pull request #1578 from ispyisail/refactor/autonum-rows-only

Make the project database the only copy of the numbering schemes
This commit is contained in:
ispyisail
2026-10-22 12:40:23 +13:00
committed by GitHub
8 changed files with 477 additions and 301 deletions
+257 -55
View File
@@ -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<QString, NumerotationContext> projectDataBase::numberingSchemes(const QString &kind) const
{
QHash<QString, NumerotationContext> 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
+15
View File
@@ -179,6 +179,21 @@ class projectDataBase : public QObject
};
void setNumbering(const Numbering &numbering);
Numbering numbering() const;
QHash<QString, NumerotationContext> 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<std::pair<QUuid, int>> *links);
//The link rows are written (opening filled them): a symbol
//built links from them (Element::initLink())
+9 -10
View File
@@ -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
+158 -183
View File
@@ -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<QString, XRefProperties> hash)
*/
QHash <QString, NumerotationContext> QETProject::conductorAutoNum() const
{
return m_conductor_autonum;
return m_data_base.numberingSchemes(QStringLiteral("conductor"));
}
/**
@@ -1455,7 +1453,7 @@ QHash <QString, NumerotationContext> QETProject::conductorAutoNum() const
*/
QHash <QString, NumerotationContext> QETProject::elementAutoNum() const
{
return m_element_autonum;
return m_data_base.numberingSchemes(QStringLiteral("element"));
}
/**
@@ -1465,7 +1463,7 @@ QHash <QString, NumerotationContext> QETProject::elementAutoNum() const
*/
QHash <QString, NumerotationContext> QETProject::cableAutoNum() const
{
return m_cable_autonum;
return m_data_base.numberingSchemes(QStringLiteral("cable"));
}
/**
@@ -1475,8 +1473,8 @@ QHash <QString, NumerotationContext> 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 <QString, NumerotationContext> QETProject::folioAutoNum() const
{
return m_folio_autonum;
return m_data_base.numberingSchemes(QStringLiteral("folio"));
}
/**
@@ -1686,8 +1680,7 @@ QHash <QString, NumerotationContext> 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<QString, NumerotationContext> 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<QString, QStringList> titles_by_formula = elementAutoNumTitlesByFormula();
QHash<QUuid, QString> title_cache;
QHash<QString, QUuid> id_cache;
{
const auto items = folio->items();
for (QGraphicsItem *it : items) {
auto *el = qgraphicsitem_cast<Element *>(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<QString, QStringList> QETProject::elementAutoNumTitlesByFormula() const
{
QHash<QString, QStringList> titles_by_formula;
for (auto it = m_element_autonum.constBegin();
it != m_element_autonum.constEnd(); ++it) {
const QHash<QString, NumerotationContext> 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<QString, QStringList> QETProject::elementAutoNumTitlesByFormula() const
*/
std::optional<QUuid> QETProject::elementAutoNumIdToLink(
const DiagramContext &information,
const QHash<QString, QStringList> &titles_by_formula) const
const QHash<QString, QStringList> &titles_by_formula,
QHash<QUuid, QString> *title_cache,
QHash<QString, QUuid> *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<QUuid> 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> QETProject::symbolNumbering() const
for (Diagram *d : m_diagrams_list)
if (!d->isLoaded()) unbuilt_in_order << d->uuid();
const QHash<QString, QStringList> 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<QUuid, QString> title_cache;
QHash<QString, QUuid> 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> 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<QString, NumerotationContext> conductor_autonum = conductorAutoNum();
QHash<QString, NumerotationContext> folio_autonum = folioAutoNum();
QHash<QString, NumerotationContext> element_autonum = elementAutoNum();
QHash<QString, QUuid> element_autonum_id;
for (auto it = element_autonum.cbegin() ; it != element_autonum.cend() ; ++it) {
element_autonum_id.insert(it.key(), elementAutoNumId(it.key()));
}
QHash<QString, NumerotationContext> 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<QString, NumerotationContext> &schemes,
const QHash<QString, QUuid> &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<QString, NumerotationContext> &schemes,
const QHash<QString, QUuid> &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 <conductors_autonums>, <folio_autonums>,
+3 -26
View File
@@ -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 <QString, NumerotationContext> m_conductor_autonum;//Title and NumContext hash
QString m_current_conductor_autonum;
/// Folio auto numbering
QHash <QString, NumerotationContext> m_folio_autonum;
/// Element Auto Numbering
QHash <QString, NumerotationContext> m_element_autonum; //Title and NumContext hash
/// Title -> uuid of each element numbering scheme
QHash <QString, QUuid> 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 <QString, NumerotationContext> 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<QString, QStringList> elementAutoNumTitlesByFormula() const;
std::optional<QUuid> elementAutoNumIdToLink(
const DiagramContext &information,
const QHash<QString, QStringList> &titles_by_formula) const;
const QHash<QString, QStringList> &titles_by_formula,
QHash<QUuid, QString> *title_cache = nullptr,
QHash<QString, QUuid> *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<bool> m_backup_future;
+1 -1
View File
@@ -92,7 +92,7 @@ if(Python3_Interpreter_FOUND AND CMAKE_GENERATOR STREQUAL "Ninja")
--build ${CMAKE_BINARY_DIR} --binary $<TARGET_FILE:qelectrotech>
--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
+1 -1
View File
@@ -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)
+33 -25
View File
@@ -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"));