Keep the project's numbering in the project database too

QETZ-DB-FIRST stage 2b-1. The numbering schemes of wires, symbols,
folios and cables, and the settings saved with them (the scheme in use
of each kind, freezing new labels, auto-break, the cable axis and
question), get three tables of the project database: numbering_scheme,
numbering_part (one row per part, in order) and numbering_setting.
QETProject writes them when it reads its file and after each change of
its numbering, from every setter; nothing reads them yet.

The save writes the numbering through writeNumberingXml(), the code it
had moved out of writeDefaultPropertiesXml(), so the same writer can
take the rows once the save moves to them (2b-2).
QET_CHECK_NUMBERING_ROWS=1 writes the numbering from the project and
from the rows at each save and says whether the two differ.
tst_elementautonumids::numberingRowsFollowEveryChange checks it after
each of 23 changes; with one setter not writing the rows, one save
differs and it fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-19 21:33:49 +13:00
parent 992058348b
commit d05cc654ad
5 changed files with 376 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 &);
+60
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,62 @@ 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.
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');
qet.renumberElementAutoNum(schemes[0].split(': formula=')[0]); save();
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 "/industrial.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"));