Merge pull request #1568 from ispyisail/refactor/autonum-through-db
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m54s

Keep the project's numbering schemes in the project database
This commit is contained in:
ispyisail
2026-10-21 14:39:34 +13:00
committed by GitHub
5 changed files with 379 additions and 55 deletions
+133
View File
@@ -2695,6 +2695,25 @@ bool projectDataBase::createDataBase()
qDebug() << " link_table query : " << query_.lastError();
}
//The numbering tables (QETZ-DB-FIRST stage 2b): the project's
//schemes, one row per part of each in its order, and the settings
//saved with them. Not filled from the folios: QETProject writes
//them when it reads its file and whenever its numbering changes.
for (const char *table : {
"CREATE TABLE numbering_scheme ("
"kind VARCHAR(20) NOT NULL, title TEXT NOT NULL, uuid VARCHAR(50), "
"PRIMARY KEY (kind, title))",
"CREATE TABLE numbering_part ("
"kind VARCHAR(20) NOT NULL, title TEXT NOT NULL, ord INTEGER NOT NULL, "
"type TEXT, value TEXT, increase TEXT, initialvalue TEXT, modulus TEXT, format TEXT, "
"PRIMARY KEY (kind, title, ord), "
"FOREIGN KEY (kind, title) REFERENCES numbering_scheme (kind, title))",
"CREATE TABLE numbering_setting (name VARCHAR(50) PRIMARY KEY NOT NULL, value TEXT)"}) {
if (!query_.exec(QLatin1String(table))) {
qDebug() << " numbering table query : " << query_.lastError();
}
}
//Create the terminal table.
//Terminal::uuid() is the terminal-position id baked into the catalog
//.elmt definition (e.g. "the top terminal") -- identical across every
@@ -4091,6 +4110,120 @@ QStringList projectDataBase::linkRowMismatches()
return mismatches;
}
/**
@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)
*/
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();
}
}
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();
}
}
/**
@brief projectDataBase::numbering
@return the numbering the numbering tables hold (setNumbering()); the
schemes in no particular order
*/
projectDataBase::Numbering projectDataBase::numbering() const
{
Numbering numbering;
QSqlQuery query(m_data_base);
query.exec(QStringLiteral("SELECT kind, title, uuid FROM numbering_scheme"));
QHash<std::pair<QString, QString>, int> index;
while (query.next()) {
NumberingScheme scheme;
scheme.kind = query.value(0).toString();
scheme.title = query.value(1).toString();
scheme.uuid = QUuid(query.value(2).toString());
index.insert({scheme.kind, scheme.title}, numbering.schemes.size());
numbering.schemes << scheme;
}
query.exec(QStringLiteral("SELECT kind, title, type, value, increase, initialvalue, modulus, "
"format FROM numbering_part ORDER BY kind, title, ord"));
while (query.next()) {
const int at = index.value({query.value(0).toString(), query.value(1).toString()}, -1);
if (at < 0) {
continue;
}
numbering.schemes[at].context.addValue(query.value(2).toString(), query.value(3).toString(),
query.value(4).toInt(), query.value(5).toInt(),
query.value(6).toInt(), query.value(7).toString());
}
query.exec(QStringLiteral("SELECT name, value FROM numbering_setting"));
while (query.next())
{
const QString name = query.value(0).toString();
const QString value = query.value(1).toString();
const bool flag = value == QLatin1String("true");
if (name == QLatin1String("conductor_current")) numbering.current_conductor = value;
else if (name == QLatin1String("element_current")) numbering.current_element = value;
else if (name == QLatin1String("cable_current")) numbering.current_cable = value;
else if (name == QLatin1String("freeze_new_conductors")) numbering.freeze_new_conductors = flag;
else if (name == QLatin1String("freeze_new_elements")) numbering.freeze_new_elements = flag;
else if (name == QLatin1String("auto_break_conductors")) numbering.auto_break_conductors = flag;
else if (name == QLatin1String("cable_x_axis_first")) numbering.cable_x_axis_first = flag;
else if (name == QLatin1String("cable_ask_numbering")) numbering.cable_ask_numbering = flag;
}
return numbering;
}
/**
@brief projectDataBase::savedLinks
The links @p element saves, read from its link rows, in their order
+23
View File
@@ -36,6 +36,7 @@
#include "../titleblockproperties.h"
#include "../conductorproperties.h"
#include "../autoNum/assignvariables.h"
#include "../autoNum/numerotationcontext.h"
class Element;
class QETProject;
@@ -156,6 +157,28 @@ class projectDataBase : public QObject
void conductorUuidChanged(Conductor *conductor, const QUuid &old_uuid);
QStringList conductorPropertiesMismatches() const;
QStringList linkRowMismatches();
/// A numbering scheme of the project (QETZ-DB-FIRST stage 2b)
struct NumberingScheme {
QString kind; ///< conductor, element, folio or cable
QString title;
QUuid uuid; ///< element schemes only
NumerotationContext context;
};
/// The project's numbering: its schemes of every kind and the
/// settings saved with them
struct Numbering {
QList<NumberingScheme> schemes;
QString current_conductor;
QString current_element;
QString current_cable;
bool freeze_new_conductors = false;
bool freeze_new_elements = false;
bool auto_break_conductors = false;
bool cable_x_axis_first = true;
bool cable_ask_numbering = true;
};
void setNumbering(const Numbering &numbering);
Numbering numbering() const;
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())
+156 -55
View File
@@ -140,6 +140,8 @@ m_project_properties_handler{this}
setCurrentCableAutoNum(cableData.second);
}
}
//m_auto_break_conductor above is read from the settings directly
writeNumberingRows();
}
ProjectPropertiesHandler &QETProject::projectPropertiesHandler()
@@ -1504,6 +1506,7 @@ QString QETProject::elementCurrentAutoNum () const
*/
void QETProject::setCurrrentElementAutonum(QString autoNum) {
m_current_element_autonum = std::move(autoNum);
writeNumberingRows();
}
/**
@@ -1549,6 +1552,7 @@ QString QETProject::cableCurrentAutoNum() const
void QETProject::setCurrentCableAutoNum(QString autoNum)
{
m_current_cable_autonum = std::move(autoNum);
writeNumberingRows();
}
/**
@@ -1581,6 +1585,7 @@ bool QETProject::cableXAxisFirst() const
void QETProject::setCableXAxisFirst(bool x_axis_first)
{
m_cable_axis_x_first = x_axis_first;
writeNumberingRows();
}
/**
@@ -1607,6 +1612,7 @@ bool QETProject::cableAskNumbering() const
void QETProject::setCableAskNumbering(bool ask)
{
m_cable_ask_numbering = ask;
writeNumberingRows();
}
/**
@@ -1660,6 +1666,7 @@ QString QETProject::conductorCurrentAutoNum () const
*/
void QETProject::setCurrentConductorAutoNum(QString autoNum) {
m_current_conductor_autonum = std::move(autoNum);
writeNumberingRows();
}
/**
@@ -1680,6 +1687,7 @@ QHash <QString, NumerotationContext> QETProject::folioAutoNum() const
*/
void QETProject::addConductorAutoNum(const QString& key, const NumerotationContext& context) {
m_conductor_autonum.insert(key, context);
writeNumberingRows();
emit autoNumContextUpdated();
}
@@ -1724,6 +1732,7 @@ void QETProject::addElementAutoNum(const QString &key,
}
m_element_autonum_id.insert(key, scheme_id);
m_element_autonum.insert(key, context);
writeNumberingRows();
emit elementAutoNumAdded(key);
emit autoNumContextUpdated();
}
@@ -1795,6 +1804,7 @@ bool QETProject::renameElementAutoNum(const QString &old_title, const QString &n
}
}
writeNumberingRows();
emit elementAutoNumRemoved(old_title);
emit elementAutoNumAdded(new_title);
emit autoNumContextUpdated();
@@ -2023,6 +2033,7 @@ QList<QETProject::SymbolNumbering> QETProject::symbolNumbering() const
*/
void QETProject::addFolioAutoNum(const QString& key, const NumerotationContext& context) {
m_folio_autonum.insert(key, context);
writeNumberingRows();
emit autoNumContextUpdated();
}
@@ -2049,6 +2060,7 @@ void QETProject::addCableAutoNum(const QString& key, const NumerotationContext&
|| !m_cable_autonum.contains(m_current_cable_autonum))) {
m_current_cable_autonum = key;
}
writeNumberingRows();
emit autoNumContextUpdated();
}
@@ -2059,6 +2071,7 @@ void QETProject::addCableAutoNum(const QString& key, const NumerotationContext&
*/
void QETProject::removeConductorAutoNum(const QString& key) {
m_conductor_autonum.remove(key);
writeNumberingRows();
}
/**
@@ -2070,6 +2083,7 @@ void QETProject::removeElementAutoNum(const QString& key)
{
m_element_autonum.remove(key);
m_element_autonum_id.remove(key);
writeNumberingRows();
emit elementAutoNumRemoved(key);
}
@@ -2080,6 +2094,7 @@ void QETProject::removeElementAutoNum(const QString& key)
*/
void QETProject::removeFolioAutoNum(const QString& key) {
m_folio_autonum.remove(key);
writeNumberingRows();
}
/**
@@ -2094,6 +2109,7 @@ void QETProject::removeCableAutoNum(const QString& key)
m_current_cable_autonum = m_cable_autonum.isEmpty()
? QString() : m_cable_autonum.keys().first();
}
writeNumberingRows();
emit autoNumContextUpdated();
}
@@ -2186,6 +2202,7 @@ bool QETProject::isFreezeNewConductors()
*/
void QETProject::setFreezeNewConductors(bool set) {
m_freeze_new_conductors = set;
writeNumberingRows();
}
/**
@@ -2230,6 +2247,7 @@ bool QETProject::isFreezeNewElements()
*/
void QETProject::setFreezeNewElements(bool set) {
m_freeze_new_elements = set;
writeNumberingRows();
}
/**
@@ -2363,6 +2381,7 @@ void QETProject::setAutoBreakConductor(bool abc)
{
if (abc != m_auto_break_conductor)
m_auto_break_conductor = abc;
writeNumberingRows();
}
/**
@@ -4044,6 +4063,7 @@ void QETProject::readDefaultPropertiesXml(QDomDocument &xml_project)
m_default_guides.append(g);
}
}
writeNumberingRows();
}
/**
@@ -4227,21 +4247,116 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element)
}
xml_element.appendChild(xrefs_elmt);
writeNumberingXml(numberingOfProject(), xml_element);
//QET_CHECK_NUMBERING_ROWS=1: say whether the project database's
//numbering rows write what the project writes (QETZ-DB-FIRST stage
//2b-1). 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");
for (const auto &g : m_default_guides) {
QDomElement guide_elmt = xml_document.createElement("guide");
guide_elmt.setAttribute("orientation", static_cast<int>(g.orientation));
guide_elmt.setAttribute("position", g.position);
guide_elmt.setAttribute("color", g.color.name());
guides_elmt.appendChild(guide_elmt);
}
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, so the rows are always what the save
writes (QET_CHECK_NUMBERING_ROWS checks it)
*/
void QETProject::writeNumberingRows()
{
m_data_base.setNumbering(numberingOfProject());
}
/**
@brief QETProject::writeNumberingXml
Export @p numbering as the <conductors_autonums>, <folio_autonums>,
<element_autonums> and <cable_autonums> children of @p xml_element
*/
void QETProject::writeNumberingXml(const projectDataBase::Numbering &numbering,
QDomElement &xml_element)
{
QDomDocument xml_document = xml_element.ownerDocument();
//Sorted, as the xrefs are: the schemes come in no particular order
//(they were QHash, whose key order is randomised per process), so
//an unsorted write reorders these children on every save.
auto schemes = [&numbering](const QString &kind) {
QMap<QString, projectDataBase::NumberingScheme> sorted;
QStringList titles;
for (const auto &scheme : numbering.schemes) {
if (scheme.kind == kind) {
sorted.insert(scheme.title, scheme);
titles << scheme.title;
}
}
titles.sort();
QList<projectDataBase::NumberingScheme> list;
for (const QString &title : std::as_const(titles))
list << sorted.value(title);
return list;
};
auto formula = [](const projectDataBase::NumberingScheme &scheme) {
return autonum::numerotationContextToFormula(scheme.context);
};
//Export Conductor Autonums
QDomElement conductor_autonums = xml_document.createElement("conductors_autonums");
conductor_autonums.setAttribute("current_autonum", m_current_conductor_autonum);
conductor_autonums.setAttribute("freeze_new_conductors", m_freeze_new_conductors ? "true" : "false");
conductor_autonums.setAttribute("auto_break_conductors", m_auto_break_conductor ? "true" : "false");
//Sorted for the same reason as the xrefs above: these three
//collections are QHash, whose key order is randomised per process,
//so an unsorted write reorders these children on every save.
QStringList conductor_autonum_keys = conductorAutoNum().keys();
conductor_autonum_keys.sort();
for (const QString &key : std::as_const(conductor_autonum_keys)) {
QDomElement conductor_autonum = conductorAutoNum(key).toXml(xml_document, "conductor_autonum");
if (key != "" && conductorAutoNumFormula(key) != "") {
conductor_autonum.setAttribute("title", key);
conductor_autonum.setAttribute("formula", conductorAutoNumFormula(key));
conductor_autonums.setAttribute("current_autonum", numbering.current_conductor);
conductor_autonums.setAttribute("freeze_new_conductors", numbering.freeze_new_conductors ? "true" : "false");
conductor_autonums.setAttribute("auto_break_conductors", numbering.auto_break_conductors ? "true" : "false");
for (auto scheme : schemes(QStringLiteral("conductor"))) {
QDomElement conductor_autonum = scheme.context.toXml(xml_document, "conductor_autonum");
if (scheme.title != "" && formula(scheme) != "") {
conductor_autonum.setAttribute("title", scheme.title);
conductor_autonum.setAttribute("formula", formula(scheme));
conductor_autonums.appendChild(conductor_autonum);
}
}
@@ -4249,31 +4364,30 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element)
//Export Folio Autonums
QDomElement folio_autonums = xml_document.createElement("folio_autonums");
QStringList folio_autonum_keys = folioAutoNum().keys();
folio_autonum_keys.sort();
for (const QString &key : std::as_const(folio_autonum_keys)) {
QDomElement folio_autonum = folioAutoNum(key).toXml(xml_document, "folio_autonum");
folio_autonum.setAttribute("title", key);
for (auto scheme : schemes(QStringLiteral("folio"))) {
QDomElement folio_autonum = scheme.context.toXml(xml_document, "folio_autonum");
folio_autonum.setAttribute("title", scheme.title);
folio_autonums.appendChild(folio_autonum);
}
xml_element.appendChild(folio_autonums);
//Export Element Autonums
const QList<projectDataBase::NumberingScheme> element_schemes = schemes(QStringLiteral("element"));
QUuid current_element_id;
for (const auto &scheme : element_schemes)
if (scheme.title == numbering.current_element) current_element_id = scheme.uuid;
QDomElement element_autonums = xml_document.createElement("element_autonums");
element_autonums.setAttribute("current_autonum", m_current_element_autonum);
if (!elementAutoNumId(m_current_element_autonum).isNull()) {
element_autonums.setAttribute("current_autonum_id",
elementAutoNumId(m_current_element_autonum).toString());
element_autonums.setAttribute("current_autonum", numbering.current_element);
if (!current_element_id.isNull()) {
element_autonums.setAttribute("current_autonum_id", current_element_id.toString());
}
element_autonums.setAttribute("freeze_new_elements", m_freeze_new_elements ? "true" : "false");
QStringList element_autonum_keys = elementAutoNum().keys();
element_autonum_keys.sort();
for (const QString &key : std::as_const(element_autonum_keys)) {
QDomElement element_autonum = elementAutoNum(key).toXml(xml_document, "element_autonum");
if (key != "" && elementAutoNumFormula(key) != "") {
element_autonum.setAttribute("title", key);
element_autonum.setAttribute("id", elementAutoNumId(key).toString());
element_autonum.setAttribute("formula", elementAutoNumFormula(key));
element_autonums.setAttribute("freeze_new_elements", numbering.freeze_new_elements ? "true" : "false");
for (auto scheme : element_schemes) {
QDomElement element_autonum = scheme.context.toXml(xml_document, "element_autonum");
if (scheme.title != "" && formula(scheme) != "") {
element_autonum.setAttribute("title", scheme.title);
element_autonum.setAttribute("id", scheme.uuid.toString());
element_autonum.setAttribute("formula", formula(scheme));
element_autonums.appendChild(element_autonum);
}
}
@@ -4293,23 +4407,21 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element)
//drawn, an axis chosen before it, and the numbering question
//answered with no are answers only this element can carry.
QDomElement cable_autonums = xml_document.createElement("cable_autonums");
cable_autonums.setAttribute("current_autonum", m_current_cable_autonum);
cable_autonums.setAttribute("current_autonum", numbering.current_cable);
cable_autonums.setAttribute("axis_priority",
m_cable_axis_x_first ? "x" : "y");
numbering.cable_x_axis_first ? "x" : "y");
//Only the no is written down: a project which has not answered
//the numbering question yet asks again, so silence in the file
//means asking rather than holding back.
if (!m_cable_ask_numbering) {
if (!numbering.cable_ask_numbering) {
cable_autonums.setAttribute("ask_numbering_rule", "false");
}
int written_cable_rules = 0;
QStringList cable_autonum_keys = cableAutoNum().keys();
cable_autonum_keys.sort();
for (const QString &key : std::as_const(cable_autonum_keys)) {
QDomElement cable_autonum = cableAutoNum(key).toXml(xml_document, "cable_autonum");
if (key != "" && cableAutoNumFormula(key) != "") {
cable_autonum.setAttribute("title", key);
cable_autonum.setAttribute("formula", cableAutoNumFormula(key));
for (auto scheme : schemes(QStringLiteral("cable"))) {
QDomElement cable_autonum = scheme.context.toXml(xml_document, "cable_autonum");
if (scheme.title != "" && formula(scheme) != "") {
cable_autonum.setAttribute("title", scheme.title);
cable_autonum.setAttribute("formula", formula(scheme));
cable_autonums.appendChild(cable_autonum);
++written_cable_rules;
}
@@ -4318,23 +4430,12 @@ void QETProject::writeDefaultPropertiesXml(QDomElement &xml_element)
//chose an axis other than the default and has not answered the
//numbering question with no -- then this element would say
//nothing the reader does not assume anyway.
if (!m_current_cable_autonum.isEmpty()
|| !m_cable_ask_numbering
|| !m_cable_axis_x_first
if (!numbering.current_cable.isEmpty()
|| !numbering.cable_ask_numbering
|| !numbering.cable_x_axis_first
|| written_cable_rules > 0) {
xml_element.appendChild(cable_autonums);
}
// Export default guides
QDomElement guides_elmt = xml_document.createElement("guides");
for (const auto &g : m_default_guides) {
QDomElement guide_elmt = xml_document.createElement("guide");
guide_elmt.setAttribute("orientation", static_cast<int>(g.orientation));
guide_elmt.setAttribute("position", g.position);
guide_elmt.setAttribute("color", g.color.name());
guides_elmt.appendChild(guide_elmt);
}
xml_element.appendChild(guides_elmt);
}
/**
+4
View File
@@ -457,6 +457,10 @@ 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 &);
void writeWireHopsXml(QDomElement &);
void writeSymbolTextsXml(QDomElement &);
+63
View File
@@ -42,6 +42,7 @@ 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()
{
@@ -61,6 +62,9 @@ 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"));
@@ -725,6 +729,65 @@ 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.
void numberingRowsFollowEveryChange()
{
const QString saved = m_dir.filePath(QStringLiteral("numbering-rows.qet"));
const QString script = QStringLiteral(R"JS(
var saves = 0;
function save() { if (qet.save(%1)) saves++; }
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();
});
['conductor', 'element', 'folio'].forEach(function (k) {
qet.removeAutoNum(k, 'Rows renamed ' + k); save();
qet.undo(); save();
});
qet.useElementAutoNum('Rows renamed element'); save();
qet.useConductorAutoNum(0, 'Rows renamed conductor'); save();
var schemes = qet.autoNums('element');
var renumbered = qet.renumberElementAutoNum(schemes[0].split(': formula=')[0]) > 0;
save();
if (renumbered) qet.undo();
save();
qet.log('PROBE ' + JSON.stringify({saves: saves}));
)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));
f.write(script.toUtf8());
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);
// 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"));
}
void conductorNumberings()
{
const QString saved = m_dir.filePath(QStringLiteral("conductors.qet"));