Merge pull request #1248 from ispyisail/feature/wiring-terminal-identity

Add terminal index and uuid to the wiring list export
This commit is contained in:
Laurent Trinques
2026-10-02 13:44:52 +02:00
committed by GitHub
5 changed files with 127 additions and 8 deletions
+8 -1
View File
@@ -620,6 +620,12 @@ QHash<Element *, int> folioIndex(QETProject &project)
/// From-to wiring list: one row per conductor, each endpoint resolved to its
/// element label and terminal name.
///
/// Most symbols leave their terminals unnamed, so each end also carries the
/// terminal's index -- the one the scripting API's addConductor() takes,
/// empty for two terminals at one point -- and its uuid, the one the project
/// file names the terminal by. These come last, after the columns the list
/// has always had, so a reader of those is not disturbed.
///
/// Reads wiring_list_view out of the project database. --export-cables produces
/// the same logical list from the document XML instead, and the two are meant
/// to agree: running both and diffing them is a direct check that the database
@@ -632,7 +638,8 @@ int exportWiring(QETProject &project, const QString &output)
static const QStringList columns {
"wire_number", "from_element_label", "from_terminal",
"to_element_label", "to_terminal", "diagram_position", "conductor_uuid"
"to_element_label", "to_terminal", "diagram_position", "conductor_uuid",
"from_terminal_index", "from_terminal_uuid", "to_terminal_index", "to_terminal_uuid"
};
QSqlQuery query = project.dataBase()->newQuery(
+70 -6
View File
@@ -180,8 +180,37 @@ struct DocumentTerminal
QString uuid;
QString name;
bool master_label = false;
QVariant index;
};
//The index each of @p points has in Element::terminals() -- the index
//the scripting API's addConductor() and conductor calls take -- or a
//null QVariant for a point another terminal shares. Element::
//parseTerminal() sorts the list top to bottom, then left to right, on
//each terminal's position in its definition, and the sort is not
//stable, so which of two terminals at the same point comes first is
//not defined: no index is given rather than one that can change.
QList<QVariant> terminalIndexes(const QList<QPointF> &points)
{
QList<int> order;
for (int i = 0 ; i < points.size() ; ++i) {
order << i;
}
std::stable_sort(order.begin(), order.end(), [&points](int a, int b) {
if (points.at(a).y() == points.at(b).y()) {
return points.at(a).x() < points.at(b).x();
}
return points.at(a).y() < points.at(b).y();
});
QList<QVariant> indexes(points.size());
for (int i = 0 ; i < order.size() ; ++i) {
if (points.count(points.at(order.at(i))) == 1) {
indexes[order.at(i)] = i;
}
}
return indexes;
}
struct DocumentDefinition
{
QString type;
@@ -391,6 +420,25 @@ bool projectDataBase::populateFromDocument(const QDomDocument &document, QString
data.fromXml(definition);
read.type = data.typeToString();
read.sub_type = data.masterTypeToString();
//Every terminal the element is built with counts towards
//the indexes, as Element::parseTerminal() keeps every one
//whose position reads, in every <description>.
QList<QDomElement> parsed;
QList<QPointF> points;
for (QDomElement d = definition.firstChildElement(QStringLiteral("description")) ;
!d.isNull() ; d = d.nextSiblingElement(QStringLiteral("description"))) {
for (QDomElement t = d.firstChildElement(QStringLiteral("terminal")) ;
!t.isNull() ; t = t.nextSiblingElement(QStringLiteral("terminal")))
{
qreal x, y;
if (QET::attributeIsAReal(t, QStringLiteral("x"), &x)
&& QET::attributeIsAReal(t, QStringLiteral("y"), &y)) {
parsed << t;
points << QPointF(x, y);
}
}
}
const QList<QVariant> indexes = terminalIndexes(points);
const QDomElement description = definition.firstChildElement(QStringLiteral("description"));
for (QDomElement t = description.firstChildElement(QStringLiteral("terminal")) ;
!t.isNull() ; t = t.nextSiblingElement(QStringLiteral("terminal")))
@@ -403,6 +451,10 @@ bool projectDataBase::populateFromDocument(const QDomDocument &document, QString
terminal.uuid = terminal_uuid.toString();
terminal.name = t.attribute(QStringLiteral("name"));
terminal.master_label = t.attribute(QStringLiteral("use_master_label")) == QLatin1String("true");
const int place = parsed.indexOf(t);
if (place >= 0) {
terminal.index = indexes.at(place);
}
read.terminals.insert(terminal_uuid, terminal);
}
known = definitions.insert(type, read);
@@ -582,8 +634,8 @@ bool projectDataBase::populateFromDocument(const QDomDocument &document, QString
for (const auto &end : {std::make_pair(conductor.element1, conductor.terminal1),
std::make_pair(conductor.element2, conductor.terminal2)}) {
const DocumentElement &owner = elements.at(element_index.value(end.first));
insertTerminal(end.second, end.first,
owner.terminals.value(QUuid(end.second)).name);
const DocumentTerminal &terminal = owner.terminals.value(QUuid(end.second));
insertTerminal(end.second, end.first, terminal.name, terminal.index);
}
m_insert_conductor_query.bindValue(QStringLiteral(":uuid"), conductor.uuid);
m_insert_conductor_query.bindValue(QStringLiteral(":diagram_uuid"), conductor.diagram_uuid);
@@ -1560,6 +1612,7 @@ bool projectDataBase::createDataBase()
"uuid VARCHAR(50) NOT NULL, "
"element_uuid VARCHAR(50) NOT NULL,"
"name VARCHAR(50),"
"terminal_index INTEGER,"
"PRIMARY KEY (uuid, element_uuid),"
"FOREIGN KEY (element_uuid) REFERENCES element (uuid)"
")");
@@ -1812,7 +1865,11 @@ void projectDataBase::createWiringListView()
"t2.element_uuid AS to_element_uuid,"
"ei2.label AS to_element_label,"
"t2.name AS to_terminal,"
"d.pos AS diagram_position"
"d.pos AS diagram_position,"
"t1.uuid AS from_terminal_uuid,"
"t1.terminal_index AS from_terminal_index,"
"t2.uuid AS to_terminal_uuid,"
"t2.terminal_index AS to_terminal_index"
" FROM conductor c"
" JOIN terminal t1 ON c.terminal1_uuid = t1.uuid AND c.terminal1_element_uuid = t1.element_uuid"
" JOIN terminal t2 ON c.terminal2_uuid = t2.uuid AND c.terminal2_element_uuid = t2.element_uuid"
@@ -1999,9 +2056,15 @@ void projectDataBase::populateConductorTable()
*/
void projectDataBase::insertTerminal(Terminal *terminal)
{
const QList<Terminal *> terminals = terminal->parentElement()->terminals();
QList<QPointF> points;
for (const Terminal *t : terminals) {
points << terminal->parentElement()->mapFromScene(t->dockConductor());
}
insertTerminal(terminal->stableUuid().toString(),
terminal->parentElement()->uuid().toString(),
terminal->name());
terminal->name(),
terminalIndexes(points).value(terminals.indexOf(terminal)));
}
/**
@@ -2009,11 +2072,12 @@ void projectDataBase::insertTerminal(Terminal *terminal)
insertTerminal(Terminal *) from values rather than a live terminal.
*/
void projectDataBase::insertTerminal(const QString &uuid, const QString &element_uuid,
const QString &name)
const QString &name, const QVariant &index)
{
m_insert_terminal_query.bindValue(":uuid", uuid);
m_insert_terminal_query.bindValue(":element_uuid", element_uuid);
m_insert_terminal_query.bindValue(":name", name);
m_insert_terminal_query.bindValue(":terminal_index", index);
if (!m_insert_terminal_query.exec()) {
qDebug() << "projectDataBase::insertTerminal insert error : " << m_insert_terminal_query.lastError();
}
@@ -2146,7 +2210,7 @@ void projectDataBase::prepareQuery()
//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)");
m_insert_terminal_query.prepare("INSERT OR IGNORE INTO terminal (uuid, element_uuid, name, terminal_index) VALUES (:uuid, :element_uuid, :name, :terminal_index)");
//INSERT CONDUCTOR
m_insert_conductor_query = QSqlQuery(m_data_base);
+1 -1
View File
@@ -150,7 +150,7 @@ class projectDataBase : public QObject
void watchConductor(Conductor *conductor);
void insertTerminal(Terminal *terminal);
void insertTerminal(const QString &uuid, const QString &element_uuid,
const QString &name);
const QString &name, const QVariant &index);
void prepareQuery();
static QHash<QString, QString> elementInfoToString(
Element *elmt);