mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-08-22 08:34:12 +02:00
Merge pull request #628 from ispyisail/feature-wiring-db-tables
Add terminal and conductor tables to projectDataBase (discussion #503, slice 2)
This commit is contained in:
@@ -21,7 +21,9 @@
|
|||||||
#include "../diagramposition.h"
|
#include "../diagramposition.h"
|
||||||
#include "../elementprovider.h"
|
#include "../elementprovider.h"
|
||||||
#include "../qetapp.h"
|
#include "../qetapp.h"
|
||||||
|
#include "../qetgraphicsitem/conductor.h"
|
||||||
#include "../qetgraphicsitem/element.h"
|
#include "../qetgraphicsitem/element.h"
|
||||||
|
#include "../qetgraphicsitem/terminal.h"
|
||||||
#include "../qetinformation.h"
|
#include "../qetinformation.h"
|
||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
|
|
||||||
@@ -87,6 +89,7 @@ void projectDataBase::updateDB()
|
|||||||
populateDiagramInfoTable();
|
populateDiagramInfoTable();
|
||||||
populateElementTable();
|
populateElementTable();
|
||||||
populateElementInfoTable();
|
populateElementInfoTable();
|
||||||
|
populateConductorTable();
|
||||||
emit dataBaseUpdated();
|
emit dataBaseUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +248,132 @@ void projectDataBase::diagramOrderChanged()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::addConductor
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::addConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
if (!conductor || !conductor->diagram()) {
|
||||||
|
qDebug() << "projectDataBase::addConductor: null conductor or diagram";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Both endpoints must belong to an element: the terminal table is keyed
|
||||||
|
//on (terminal, element) and a terminal with no parent has no identity
|
||||||
|
//to key on. Terminals whose *definition* predates terminal uuids are
|
||||||
|
//fine -- Terminal::stableUuid() derives one from the terminal's local
|
||||||
|
//position, which is what the project format itself matches on.
|
||||||
|
if (!conductor->terminal1->parentElement()
|
||||||
|
|| !conductor->terminal2->parentElement()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertTerminal(conductor->terminal1);
|
||||||
|
insertTerminal(conductor->terminal2);
|
||||||
|
|
||||||
|
watchConductor(conductor);
|
||||||
|
bindConductorValues(m_insert_conductor_query, conductor, conductor->diagram());
|
||||||
|
if (!m_insert_conductor_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::addConductor insert error : " << m_insert_conductor_query.lastError();
|
||||||
|
} else {
|
||||||
|
emit dataBaseUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::removeConductor
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::removeConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
m_remove_conductor_query.bindValue(":uuid", conductor->uuid().toString());
|
||||||
|
if (!m_remove_conductor_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::removeConductor delete error : " << m_remove_conductor_query.lastError();
|
||||||
|
} else {
|
||||||
|
emit dataBaseUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::updateConductor
|
||||||
|
Refresh the mutable columns of an already-inserted conductor.
|
||||||
|
|
||||||
|
Only the text (the wire number) can change without the conductor being
|
||||||
|
removed and re-added: its endpoints are fixed for its lifetime. Without
|
||||||
|
this, renaming a wire left the database holding the old number and the
|
||||||
|
wiring list showed a stale value until the next full repopulate.
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::updateConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
if (!conductor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_update_conductor_query.bindValue(QStringLiteral(":uuid"), conductor->uuid().toString());
|
||||||
|
m_update_conductor_query.bindValue(QStringLiteral(":text"), conductor->properties().text);
|
||||||
|
if (!m_update_conductor_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::updateConductor update error : " << m_update_conductor_query.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Deliberately no dataBaseUpdated() here, unlike add/remove. The only
|
||||||
|
//column this touches is the wire text, which no view watched by
|
||||||
|
//ProjectDBModel displays -- the nomenclature shows elements, and its
|
||||||
|
//wire_count changes when a conductor appears or disappears, not when
|
||||||
|
//it is renamed. Emitting would make every ProjectDBModel re-run its
|
||||||
|
//query, and auto-numbering renames every conductor in the project in
|
||||||
|
//one pass.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::watchConductor
|
||||||
|
Keep this conductor's row in step with its properties.
|
||||||
|
|
||||||
|
Conductor::setProperties() has a dozen call sites (auto-numbering, the
|
||||||
|
properties dialog, element moves, deletion re-links...), so listening to
|
||||||
|
the signal it already emits is the only way to catch them all -- and the
|
||||||
|
only way to catch the ones added later. Qt::UniqueConnection makes a
|
||||||
|
repeated insert or a full repopulate harmless.
|
||||||
|
@param conductor
|
||||||
|
*/
|
||||||
|
void projectDataBase::watchConductor(Conductor *conductor)
|
||||||
|
{
|
||||||
|
connect(conductor, &Conductor::propertiesChange,
|
||||||
|
this, &projectDataBase::conductorPropertiesChanged,
|
||||||
|
Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::conductorPropertiesChanged
|
||||||
|
*/
|
||||||
|
void projectDataBase::conductorPropertiesChanged()
|
||||||
|
{
|
||||||
|
if (auto *conductor = qobject_cast<Conductor *>(sender())) {
|
||||||
|
updateConductor(conductor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::bindConductorValues
|
||||||
|
One binder for both insert paths, so a conductor added to a live diagram
|
||||||
|
and one read from a file can never drift apart -- the same reason
|
||||||
|
bindElementValues() exists for elements.
|
||||||
|
@param query
|
||||||
|
@param conductor
|
||||||
|
@param diagram : the diagram the conductor belongs to
|
||||||
|
*/
|
||||||
|
void projectDataBase::bindConductorValues(QSqlQuery &query, Conductor *conductor, Diagram *diagram)
|
||||||
|
{
|
||||||
|
query.bindValue(QStringLiteral(":uuid"), conductor->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":diagram_uuid"), diagram->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal1_uuid"), conductor->terminal1->stableUuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal1_element_uuid"), conductor->terminal1->parentElement()->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal2_uuid"), conductor->terminal2->stableUuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":terminal2_element_uuid"), conductor->terminal2->parentElement()->uuid().toString());
|
||||||
|
query.bindValue(QStringLiteral(":text"), conductor->properties().text);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief projectDataBase::createDataBase
|
@brief projectDataBase::createDataBase
|
||||||
Create the data base
|
Create the data base
|
||||||
@@ -323,6 +452,57 @@ bool projectDataBase::createDataBase()
|
|||||||
qDebug() << " element_info_table query : " << query_.lastError();
|
qDebug() << " element_info_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
|
||||||
|
//placed instance of that catalog element, not a per-instance id. A
|
||||||
|
//terminal instance is only uniquely identified by (uuid, element_uuid)
|
||||||
|
//together, so that pair is the primary key here, not uuid alone.
|
||||||
|
QString terminal_table("CREATE TABLE terminal"
|
||||||
|
"( "
|
||||||
|
"uuid VARCHAR(50) NOT NULL, "
|
||||||
|
"element_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"name VARCHAR(50),"
|
||||||
|
"PRIMARY KEY (uuid, element_uuid),"
|
||||||
|
"FOREIGN KEY (element_uuid) REFERENCES element (uuid)"
|
||||||
|
")");
|
||||||
|
if (!query_.exec(terminal_table)) {
|
||||||
|
qDebug() << "terminal_table query : "<< query_.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create the conductor table
|
||||||
|
QString conductor_table("CREATE TABLE conductor"
|
||||||
|
"( "
|
||||||
|
"uuid VARCHAR(50) PRIMARY KEY NOT NULL, "
|
||||||
|
"diagram_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"terminal1_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"terminal1_element_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"terminal2_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"terminal2_element_uuid VARCHAR(50) NOT NULL,"
|
||||||
|
"text VARCHAR(100),"
|
||||||
|
"FOREIGN KEY (diagram_uuid) REFERENCES diagram (uuid),"
|
||||||
|
"FOREIGN KEY (terminal1_uuid, terminal1_element_uuid) REFERENCES terminal (uuid, element_uuid),"
|
||||||
|
"FOREIGN KEY (terminal2_uuid, terminal2_element_uuid) REFERENCES terminal (uuid, element_uuid)"
|
||||||
|
")");
|
||||||
|
if (!query_.exec(conductor_table)) {
|
||||||
|
qDebug() << "conductor_table query : "<< query_.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//The element-facing columns are looked up per element row, not per
|
||||||
|
//conductor row: element_nomenclature_view carries a correlated
|
||||||
|
//subquery counting the wires touching each element. Without these
|
||||||
|
//indexes each element row full-scans the conductor table, which grows
|
||||||
|
//as elements x conductors.
|
||||||
|
for (const QString &index_ : {
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_terminal1_element ON conductor (terminal1_element_uuid)"),
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_terminal2_element ON conductor (terminal2_element_uuid)"),
|
||||||
|
QStringLiteral("CREATE INDEX idx_conductor_diagram ON conductor (diagram_uuid)") })
|
||||||
|
{
|
||||||
|
if (!query_.exec(index_)) {
|
||||||
|
qDebug() << "conductor index query : " << query_.lastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createElementNomenclatureView();
|
createElementNomenclatureView();
|
||||||
createSummaryView();
|
createSummaryView();
|
||||||
prepareQuery();
|
prepareQuery();
|
||||||
@@ -534,6 +714,58 @@ void projectDataBase::populateDiagramInfoTable()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::populateConductorTable
|
||||||
|
Populate the terminal and conductor tables. Terminals only matter here
|
||||||
|
in the context of a conductor referencing them, so their population is
|
||||||
|
folded into this method rather than tracked independently.
|
||||||
|
*/
|
||||||
|
void projectDataBase::populateConductorTable()
|
||||||
|
{
|
||||||
|
QSqlQuery query(m_data_base);
|
||||||
|
query.exec(QStringLiteral("DELETE FROM conductor"));
|
||||||
|
query.exec(QStringLiteral("DELETE FROM terminal"));
|
||||||
|
|
||||||
|
for (auto *diagram : m_project->diagrams())
|
||||||
|
{
|
||||||
|
const auto conductor_list = diagram->conductors();
|
||||||
|
for (auto *conductor : conductor_list)
|
||||||
|
{
|
||||||
|
//See addConductor(): only a terminal with no parent element is
|
||||||
|
//skipped. A missing terminal uuid is handled by stableUuid().
|
||||||
|
if (!conductor->terminal1->parentElement()
|
||||||
|
|| !conductor->terminal2->parentElement()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertTerminal(conductor->terminal1);
|
||||||
|
insertTerminal(conductor->terminal2);
|
||||||
|
|
||||||
|
watchConductor(conductor);
|
||||||
|
bindConductorValues(m_insert_conductor_query, conductor, diagram);
|
||||||
|
if (!m_insert_conductor_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::populateConductorTable insert error : " << m_insert_conductor_query.lastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief projectDataBase::insertTerminal
|
||||||
|
Insert (or, if already present -- e.g. a junction shared by several
|
||||||
|
conductors -- silently keep) @terminal in the terminal table.
|
||||||
|
@param terminal
|
||||||
|
*/
|
||||||
|
void projectDataBase::insertTerminal(Terminal *terminal)
|
||||||
|
{
|
||||||
|
m_insert_terminal_query.bindValue(":uuid", terminal->stableUuid().toString());
|
||||||
|
m_insert_terminal_query.bindValue(":element_uuid", terminal->parentElement()->uuid().toString());
|
||||||
|
m_insert_terminal_query.bindValue(":name", terminal->name());
|
||||||
|
if (!m_insert_terminal_query.exec()) {
|
||||||
|
qDebug() << "projectDataBase::insertTerminal insert error : " << m_insert_terminal_query.lastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void projectDataBase::prepareQuery()
|
void projectDataBase::prepareQuery()
|
||||||
{
|
{
|
||||||
//INSERT DIAGRAM
|
//INSERT DIAGRAM
|
||||||
@@ -606,6 +838,23 @@ void projectDataBase::prepareQuery()
|
|||||||
update_str.append(" WHERE element_uuid = :uuid");
|
update_str.append(" WHERE element_uuid = :uuid");
|
||||||
m_update_element_query = QSqlQuery(m_data_base);
|
m_update_element_query = QSqlQuery(m_data_base);
|
||||||
m_update_element_query.prepare(update_str);
|
m_update_element_query.prepare(update_str);
|
||||||
|
|
||||||
|
//INSERT TERMINAL
|
||||||
|
m_insert_terminal_query = QSqlQuery(m_data_base);
|
||||||
|
m_insert_terminal_query.prepare("INSERT OR IGNORE INTO terminal (uuid, element_uuid, name) VALUES (:uuid, :element_uuid, :name)");
|
||||||
|
|
||||||
|
//INSERT CONDUCTOR
|
||||||
|
m_insert_conductor_query = QSqlQuery(m_data_base);
|
||||||
|
m_insert_conductor_query.prepare("INSERT INTO conductor (uuid, diagram_uuid, terminal1_uuid, terminal1_element_uuid, terminal2_uuid, terminal2_element_uuid, text) "
|
||||||
|
"VALUES (:uuid, :diagram_uuid, :terminal1_uuid, :terminal1_element_uuid, :terminal2_uuid, :terminal2_element_uuid, :text)");
|
||||||
|
|
||||||
|
//UPDATE CONDUCTOR
|
||||||
|
m_update_conductor_query = QSqlQuery(m_data_base);
|
||||||
|
m_update_conductor_query.prepare(QStringLiteral("UPDATE conductor SET text = :text WHERE uuid = :uuid"));
|
||||||
|
|
||||||
|
//REMOVE CONDUCTOR
|
||||||
|
m_remove_conductor_query = QSqlQuery(m_data_base);
|
||||||
|
m_remove_conductor_query.prepare("DELETE FROM conductor WHERE uuid=:uuid");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
class Element;
|
class Element;
|
||||||
class QETProject;
|
class QETProject;
|
||||||
class Diagram;
|
class Diagram;
|
||||||
|
class Conductor;
|
||||||
|
class Terminal;
|
||||||
class sqlite3;
|
class sqlite3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +60,16 @@ class projectDataBase : public QObject
|
|||||||
void diagramInfoChanged (Diagram *diagram);
|
void diagramInfoChanged (Diagram *diagram);
|
||||||
void diagramOrderChanged();
|
void diagramOrderChanged();
|
||||||
|
|
||||||
|
void addConductor (Conductor *conductor);
|
||||||
|
void removeConductor (Conductor *conductor);
|
||||||
|
void updateConductor (Conductor *conductor);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
//Refresh the sender()'s row after Conductor::setProperties().
|
||||||
|
void conductorPropertiesChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataBaseUpdated();
|
void dataBaseUpdated();
|
||||||
|
|
||||||
@@ -69,6 +81,10 @@ class projectDataBase : public QObject
|
|||||||
void populateElementTable();
|
void populateElementTable();
|
||||||
void populateElementInfoTable();
|
void populateElementInfoTable();
|
||||||
void populateDiagramInfoTable();
|
void populateDiagramInfoTable();
|
||||||
|
void populateConductorTable();
|
||||||
|
void bindConductorValues(QSqlQuery &query, Conductor *conductor, Diagram *diagram);
|
||||||
|
void watchConductor(Conductor *conductor);
|
||||||
|
void insertTerminal(Terminal *terminal);
|
||||||
void prepareQuery();
|
void prepareQuery();
|
||||||
static QHash<QString, QString> elementInfoToString(
|
static QHash<QString, QString> elementInfoToString(
|
||||||
Element *elmt);
|
Element *elmt);
|
||||||
@@ -86,7 +102,11 @@ class projectDataBase : public QObject
|
|||||||
m_insert_diagram_info_query,
|
m_insert_diagram_info_query,
|
||||||
m_update_diagram_info_query,
|
m_update_diagram_info_query,
|
||||||
m_diagram_order_changed,
|
m_diagram_order_changed,
|
||||||
m_diagram_info_order_changed;
|
m_diagram_info_order_changed,
|
||||||
|
m_insert_terminal_query,
|
||||||
|
m_insert_conductor_query,
|
||||||
|
m_update_conductor_query,
|
||||||
|
m_remove_conductor_query;
|
||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1666,6 +1666,7 @@ void Diagram::addItem(QGraphicsItem *item)
|
|||||||
conductor->terminal1->addConductor(conductor);
|
conductor->terminal1->addConductor(conductor);
|
||||||
conductor->terminal2->addConductor(conductor);
|
conductor->terminal2->addConductor(conductor);
|
||||||
conductor->calculateTextItemPosition();
|
conductor->calculateTextItemPosition();
|
||||||
|
m_project->dataBase()->addConductor(conductor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {break;}
|
default: {break;}
|
||||||
@@ -1696,6 +1697,7 @@ void Diagram::removeItem(QGraphicsItem *item)
|
|||||||
Conductor *conductor = static_cast<Conductor *>(item);
|
Conductor *conductor = static_cast<Conductor *>(item);
|
||||||
conductor->terminal1->removeConductor(conductor);
|
conductor->terminal1->removeConductor(conductor);
|
||||||
conductor->terminal2->removeConductor(conductor);
|
conductor->terminal2->removeConductor(conductor);
|
||||||
|
m_project->dataBase()->removeConductor(conductor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {break;}
|
default: {break;}
|
||||||
|
|||||||
@@ -82,6 +82,13 @@ void PasteDiagramCommand::redo()
|
|||||||
{
|
{
|
||||||
first_redo = false;
|
first_redo = false;
|
||||||
|
|
||||||
|
//make new uuid for every pasted conductor, because old uuid are
|
||||||
|
//the uuid of the copied conductor
|
||||||
|
const QList <Conductor *> all_pasted_conductors = content.conductors();
|
||||||
|
for (Conductor *c : all_pasted_conductors) {
|
||||||
|
c -> newUuid();
|
||||||
|
}
|
||||||
|
|
||||||
//this is the first paste, we do some actions for the new element
|
//this is the first paste, we do some actions for the new element
|
||||||
const QList <Element *> elmts_list = content.m_elements;
|
const QList <Element *> elmts_list = content.m_elements;
|
||||||
for (Element *e : elmts_list)
|
for (Element *e : elmts_list)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "elementspanelwidget.h"
|
#include "elementspanelwidget.h"
|
||||||
#include "diagram.h"
|
#include "diagram.h"
|
||||||
|
#include "qetgraphicsitem/conductor.h"
|
||||||
#include "editor/ui/qetelementeditor.h"
|
#include "editor/ui/qetelementeditor.h"
|
||||||
#include "elementscategoryeditor.h"
|
#include "elementscategoryeditor.h"
|
||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
@@ -684,6 +685,13 @@ void ElementsPanelWidget::duplicateDiagram()
|
|||||||
elmt->newUuid();
|
elmt->newUuid();
|
||||||
new_diagram->restoreText(elmt);
|
new_diagram->restoreText(elmt);
|
||||||
}
|
}
|
||||||
|
else if (Conductor *cond = dynamic_cast<Conductor *>(item)) {
|
||||||
|
// Same reasoning for conductors: conductor.uuid is the PRIMARY
|
||||||
|
// KEY of the conductor table, and its insert is a plain INSERT,
|
||||||
|
// so a duplicated uuid fails and the wire silently disappears
|
||||||
|
// from the wiring list and the per-element wire count.
|
||||||
|
cond->newUuid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ Conductor::Conductor(Terminal *p1, Terminal* p2) :
|
|||||||
//set Zvalue at 11 to be upper than the DiagramImageItem and element
|
//set Zvalue at 11 to be upper than the DiagramImageItem and element
|
||||||
setZValue(11);
|
setZValue(11);
|
||||||
m_previous_z_value = zValue();
|
m_previous_z_value = zValue();
|
||||||
|
m_uuid = QUuid::createUuid();
|
||||||
|
|
||||||
//Add this conductor to the list of conductors of each of the two terminals
|
//Add this conductor to the list of conductors of each of the two terminals
|
||||||
bool ajout_p1 = terminal1 -> addConductor(this);
|
bool ajout_p1 = terminal1 -> addConductor(this);
|
||||||
@@ -1005,6 +1006,18 @@ void Conductor::pointsToSegments(const QList<QPointF>& points_list) {
|
|||||||
*/
|
*/
|
||||||
bool Conductor::fromXml(QDomElement &dom_element)
|
bool Conductor::fromXml(QDomElement &dom_element)
|
||||||
{
|
{
|
||||||
|
//Older project files have no conductor uuid attribute at all --
|
||||||
|
//generate one on load, same treatment terminal uuids got when
|
||||||
|
//that field was introduced (see terminal1/terminal2 handling in
|
||||||
|
//toXml() below).
|
||||||
|
m_uuid = QUuid(dom_element.attribute(QStringLiteral("uuid")));
|
||||||
|
if (m_uuid.isNull()) {
|
||||||
|
//Absent, empty or malformed: mint one. A null uuid is not a usable
|
||||||
|
//identity -- every conductor carrying one would collide with every
|
||||||
|
//other on the conductor table's primary key.
|
||||||
|
m_uuid = QUuid::createUuid();
|
||||||
|
}
|
||||||
|
|
||||||
setPos(dom_element.attribute("x", nullptr).toDouble(),
|
setPos(dom_element.attribute("x", nullptr).toDouble(),
|
||||||
dom_element.attribute("y", nullptr).toDouble());
|
dom_element.attribute("y", nullptr).toDouble());
|
||||||
|
|
||||||
@@ -1043,6 +1056,7 @@ QDomElement Conductor::toXml(QDomDocument &dom_document,
|
|||||||
{
|
{
|
||||||
QDomElement dom_element = dom_document.createElement("conductor");
|
QDomElement dom_element = dom_document.createElement("conductor");
|
||||||
|
|
||||||
|
dom_element.setAttribute("uuid", m_uuid.toString());
|
||||||
dom_element.setAttribute("x", QString::number(pos().x()));
|
dom_element.setAttribute("x", QString::number(pos().x()));
|
||||||
dom_element.setAttribute("y", QString::number(pos().y()));
|
dom_element.setAttribute("y", QString::number(pos().y()));
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "../conductorproperties.h"
|
#include "../conductorproperties.h"
|
||||||
|
|
||||||
#include <QGraphicsPathItem>
|
#include <QGraphicsPathItem>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
class ConductorProfile;
|
class ConductorProfile;
|
||||||
class ConductorSegmentProfile;
|
class ConductorSegmentProfile;
|
||||||
@@ -77,6 +78,8 @@ class Conductor : public QGraphicsObject
|
|||||||
int type() const override { return Type; }
|
int type() const override { return Type; }
|
||||||
Diagram *diagram() const;
|
Diagram *diagram() const;
|
||||||
ConductorTextItem *textItem() const;
|
ConductorTextItem *textItem() const;
|
||||||
|
QUuid uuid() const {return m_uuid;}
|
||||||
|
void newUuid() {m_uuid = QUuid::createUuid();} //create new uuid for this conductor
|
||||||
void updatePath(const QRectF & = QRectF());
|
void updatePath(const QRectF & = QRectF());
|
||||||
|
|
||||||
//This method do nothing, it's only made to be used with Q_PROPERTY
|
//This method do nothing, it's only made to be used with Q_PROPERTY
|
||||||
@@ -205,6 +208,7 @@ class Conductor : public QGraphicsObject
|
|||||||
Highlight must_highlight_;
|
Highlight must_highlight_;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
bool m_freeze_label = false;
|
bool m_freeze_label = false;
|
||||||
|
QUuid m_uuid;
|
||||||
|
|
||||||
/// QPen et QBrush objects used to draw conductors
|
/// QPen et QBrush objects used to draw conductors
|
||||||
static QPen conductor_pen;
|
static QPen conductor_pen;
|
||||||
|
|||||||
@@ -820,6 +820,60 @@ QUuid Terminal::uuid() const
|
|||||||
return d->m_uuid;
|
return d->m_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Terminal::stableUuid
|
||||||
|
An identity for this terminal that exists on every element, not only on
|
||||||
|
those saved by a uuid-aware element editor.
|
||||||
|
|
||||||
|
uuid() comes from the catalog .elmt definition and is empty for every
|
||||||
|
element authored before that field existed -- which is most of the
|
||||||
|
installed base. Anything keyed on uuid() alone therefore cannot see those
|
||||||
|
elements at all.
|
||||||
|
|
||||||
|
When there is no uuid, derive one from the terminal's local position and
|
||||||
|
orientation inside its element. That is not an arbitrary choice: it is the
|
||||||
|
same thing the project format itself uses to match a conductor back to a
|
||||||
|
terminal ("each connection is made by using the local position of the
|
||||||
|
terminal and a dynamic id" -- TerminalData::m_uuid). m_pos is the position
|
||||||
|
read from the definition and is not touched by moving the element on the
|
||||||
|
folio, so the result is stable across loads, saves and folio moves, and it
|
||||||
|
is unique within an element except where a definition genuinely declares
|
||||||
|
two terminals at the same point -- three cases in the whole example corpus,
|
||||||
|
and harmless, because two terminals sharing a position and orientation are
|
||||||
|
indistinguishable in every observable respect: they merge to one terminal
|
||||||
|
row and every conductor on either of them still resolves to the right
|
||||||
|
element and name.
|
||||||
|
|
||||||
|
Derived values are UUID v5 in a fixed namespace, so they are reproducible
|
||||||
|
without being written to the file, and cannot collide with the v4 uuids
|
||||||
|
the element editor generates.
|
||||||
|
|
||||||
|
@return the terminal's own uuid when it has one, otherwise a derived one
|
||||||
|
*/
|
||||||
|
QUuid Terminal::stableUuid() const
|
||||||
|
{
|
||||||
|
if (!d->m_uuid.isNull()) {
|
||||||
|
return d->m_uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fixed namespace for terminal identities derived from geometry.
|
||||||
|
static const QUuid derived_ns(QStringLiteral("{6b1f6d1e-6a1a-5f7e-9a3d-9c0a5b2d7e11}"));
|
||||||
|
|
||||||
|
//Position and orientation only. The name is deliberately excluded: it
|
||||||
|
//is not stable across a save cycle -- QET rewrites a terminal named
|
||||||
|
//"_" as unnamed, which would silently change the identity of 1421 of
|
||||||
|
//industrial.qet's 1790 terminals on the first resave. It is also not
|
||||||
|
//needed: keying on geometry alone produces exactly the same number of
|
||||||
|
//collisions across the example corpus, and it means renaming a
|
||||||
|
//terminal does not change what it is.
|
||||||
|
const QString key = QStringLiteral("%1|%2|%3")
|
||||||
|
.arg(d->m_pos.x(), 0, 'f', 4)
|
||||||
|
.arg(d->m_pos.y(), 0, 'f', 4)
|
||||||
|
.arg(static_cast<int>(d->m_orientation));
|
||||||
|
|
||||||
|
return QUuid::createUuidV5(derived_ns, key);
|
||||||
|
}
|
||||||
|
|
||||||
QString Terminal::name() const
|
QString Terminal::name() const
|
||||||
{
|
{
|
||||||
if (d->m_use_master_label && parent_element_) {
|
if (d->m_use_master_label && parent_element_) {
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class Terminal : public QGraphicsObject
|
|||||||
Diagram *diagram () const;
|
Diagram *diagram () const;
|
||||||
Element *parentElement () const;
|
Element *parentElement () const;
|
||||||
QUuid uuid () const;
|
QUuid uuid () const;
|
||||||
|
QUuid stableUuid () const;
|
||||||
QString name () const;
|
QString name () const;
|
||||||
QString baseName () const;
|
QString baseName () const;
|
||||||
TerminalData::Type terminalType() const;
|
TerminalData::Type terminalType() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user