Insert an element the same way whether it is added live or on load

The element and element_info tables had two independent insert paths --
addElement() for an element added to a live diagram, and
populateElementTable()/populateElementInfoTable() for a full rebuild --
which bound the same row differently. The incremental path wrote
kindInformations()["type"] into element.sub_type; the bulk path wrote
elementData().masterTypeToString(). So the table held different values
depending on whether the project had been reloaded since the element was
placed, and element_nomenclature_view exposes that column as
element_sub_type, which ElementQueryWidget filters on for the Coil,
Protection, Commutator and PLC nomenclature options.

That divergence is the same shape as the type-filter one fixed in the
previous commit, and it is the reason this stack kept finding bugs that
were invisible while editing and only appeared after a reload. Rather
than correct a second instance of it, both paths now go through
bindElementValues() and bindElementInfoValues(), following the
bindDiagramInfoValues() helper this class already had. Live and reloaded
now agree by construction instead of by coincidence.

The bulk path's values are the ones kept, because they are what every
already saved project contains: nothing a reload produces changes, and
the previous commit's 19-project BOM regression stays valid. It is the
live path that moves, onto the values a reload would have given it
anyway.

Measured, placing one element into a new project and then saving and
reopening it:

  live      element table: slave/ x1
  reloaded  element table: slave/ x1

and for the same element, what the two paths would have stored:

  bulk (now shared): ""      incremental (before this commit): "simple"

Re-ran the BOM regression over the same 19 projects after this change:
content identical to the pre-change baseline on all 19, and identical
line-for-line on 18, the exception being the three byte-identical
photovoltaique rows already described in the previous commit.

Note for anyone reading masterTypeToString(): the const no-argument
overload returns an empty string for anything that is not a Master, so
the "coil" fallback in the static overload is only reached for real
master elements. Non-master elements get an empty sub_type, not a
spurious "coil".
This commit is contained in:
ispyisail
2026-08-02 16:10:48 +12:00
parent b855d760a8
commit 030e6ebf00
2 changed files with 52 additions and 29 deletions
+50 -29
View File
@@ -158,24 +158,12 @@ void projectDataBase::addElement(Element *element)
return;
}
m_insert_elements_query.bindValue(":uuid", element->uuid().toString());
m_insert_elements_query.bindValue(":diagram_uuid", element->diagram()->uuid().toString());
m_insert_elements_query.bindValue(":pos", element->diagram()->convertPosition(element->scenePos()).toString());
m_insert_elements_query.bindValue(":type", element->elementData().typeToString());
m_insert_elements_query.bindValue(":sub_type", element->kindInformations()["type"].toString());
bindElementValues(m_insert_elements_query, element, element->diagram());
if (!m_insert_elements_query.exec()) {
qDebug() << "projectDataBase::addElement insert element error : " << m_insert_elements_query.lastError();
}
m_insert_element_info_query.bindValue(":uuid", element->uuid().toString());
auto hash = elementInfoToString(element);
for (auto key : hash.keys())
{
QString value = hash.value(key);
QString bind = key.prepend(":");
m_insert_element_info_query.bindValue(bind, value);
}
bindElementInfoValues(m_insert_element_info_query, element);
if (!m_insert_element_info_query.exec()) {
qDebug() << "projectDataBase::addElement insert element info error : " << m_insert_element_info_query.lastError();
} else {
@@ -778,12 +766,7 @@ void projectDataBase::populateElementTable()
//Insert all values into the database
for (const auto &elmt : elmt_vector)
{
const auto elmt_data = elmt->elementData();
m_insert_elements_query.bindValue(":uuid", elmt->uuid().toString());
m_insert_elements_query.bindValue(":diagram_uuid", diagram->uuid().toString());
m_insert_elements_query.bindValue(":pos", diagram->convertPosition(elmt->scenePos()).toString());
m_insert_elements_query.bindValue(":type", elmt_data.typeToString());
m_insert_elements_query.bindValue(":sub_type", elmt_data.masterTypeToString());
bindElementValues(m_insert_elements_query, elmt, diagram);
if (!m_insert_elements_query.exec()) {
qDebug() << "projectDataBase::populateElementTable insert error : " << m_insert_elements_query.lastError();
}
@@ -808,15 +791,7 @@ void projectDataBase::populateElementInfoTable()
//Insert all values into the database
for (const auto &elmt : elmt_vector)
{
m_insert_element_info_query.bindValue(QStringLiteral(":uuid"), elmt->uuid().toString());
const auto hash = elementInfoToString(elmt);
for (const auto &key : hash.keys())
{
QString value = hash.value(key);
QString bind = QStringLiteral(":") + key;
m_insert_element_info_query.bindValue(bind, value);
}
bindElementInfoValues(m_insert_element_info_query, elmt);
if (!m_insert_element_info_query.exec()) {
qDebug() << "projectDataBase::populateElementInfoTable insert error : " << m_insert_element_info_query.lastError();
}
@@ -1003,6 +978,52 @@ QHash<QString, QString> projectDataBase::elementInfoToString(Element *elmt)
return hash;
}
/**
@brief projectDataBase::bindElementValues
Bind one element's row for the element table.
Shared by addElement() (a single element added to a live diagram) and
populateElementTable() (a full rebuild), because those two used to bind
the same row differently: the incremental path wrote
kindInformations()["type"] into sub_type while the bulk path wrote
elementData().masterTypeToString(). The element table therefore held
different values depending on whether the project had been reloaded
since the element was placed. One binder means live and reloaded agree
by construction rather than by coincidence.
The bulk path's values are the ones kept: they are what every already
saved project contains, so nothing a reload produces changes.
@param query : prepared insert query to bind into
@param element : element to bind
@param diagram : diagram holding @element
*/
void projectDataBase::bindElementValues(QSqlQuery &query, Element *element, Diagram *diagram)
{
const auto element_data = element->elementData();
query.bindValue(QStringLiteral(":uuid"), element->uuid().toString());
query.bindValue(QStringLiteral(":diagram_uuid"), diagram->uuid().toString());
query.bindValue(QStringLiteral(":pos"), diagram->convertPosition(element->scenePos()).toString());
query.bindValue(QStringLiteral(":type"), element_data.typeToString());
query.bindValue(QStringLiteral(":sub_type"), element_data.masterTypeToString());
}
/**
@brief projectDataBase::bindElementInfoValues
Bind one element's row for the element info table.
Shared by addElement() and populateElementInfoTable() for the same
reason as bindElementValues().
@param query : prepared insert query to bind into
@param element : element to bind
*/
void projectDataBase::bindElementInfoValues(QSqlQuery &query, Element *element)
{
query.bindValue(QStringLiteral(":uuid"), element->uuid().toString());
const auto hash = elementInfoToString(element);
for (const auto &key : hash.keys()) {
query.bindValue(QStringLiteral(":") + key, hash.value(key));
}
}
void projectDataBase::bindDiagramInfoValues(QSqlQuery &query, Diagram *diagram)
{
query.bindValue(":uuid", diagram->uuid());
+2
View File
@@ -92,6 +92,8 @@ class projectDataBase : public QObject
static QHash<QString, QString> elementInfoToString(
Element *elmt);
void bindDiagramInfoValues(QSqlQuery &query, Diagram *diagram);
static void bindElementValues(QSqlQuery &query, Element *element, Diagram *diagram);
static void bindElementInfoValues(QSqlQuery &query, Element *element);
private:
QPointer<QETProject> m_project;