mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-05-25 07:20:00 +02:00
terminaldata: add No, Nc, Common types for SW contacts
Extend TerminalData::Type enum with three new semantic values: - No : Normally Open terminal of a switch (SW) contact - Nc : Normally Closed terminal of a switch (SW) contact - Common : Common terminal of a switch (SW) contact Update typeToString() and typeFromString() accordingly. Fully backward compatible: existing Generic/Inner/Outer types are unchanged. Elements without typed terminals fall back to the previous behavior (first 2 named terminals). terminal: expose terminalType() as public accessor Add Terminal::terminalType() returning the TerminalData::Type of this terminal. This allows crossrefitem and other consumers to filter terminals by semantic role (No, Nc, Common) without accessing TerminalData internals directly. terminaleditor: add No, Nc, Common entries to type combobox Expose the three new TerminalData types (No, Nc, Common) in the element editor UI so users can assign a semantic role to each terminal of a SW contact element. Also fix a pre-existing bug in updateForm() where m_type_cb was incorrectly using m_orientation_cb->findData() instead of m_type_cb->findData(), preventing the type from being restored correctly when selecting a terminal. terminaleditor: add No, Nc, Common entries to type combobox Expose the three new TerminalData types (No, Nc, Common) in the element editor UI so users can assign a semantic role to each terminal of a SW contact element. Also fix a pre-existing bug in updateForm() where m_type_cb was incorrectly using m_orientation_cb->findData() instead of m_type_cb->findData(), preventing the type from being restored correctly when selecting a terminal.
This commit is contained in:
@@ -61,7 +61,7 @@ void TerminalEditor::updateForm()
|
||||
ui->m_y_dsb->setValue(m_part->property("y").toReal());
|
||||
ui->m_orientation_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->property("orientation")));
|
||||
ui->m_name_le->setText(m_part->terminalName());
|
||||
ui->m_type_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->terminalType()));
|
||||
ui->m_type_cb->setCurrentIndex(ui->m_type_cb->findData(m_part->terminalType()));
|
||||
|
||||
activeConnections(true);
|
||||
}
|
||||
@@ -122,6 +122,9 @@ void TerminalEditor::init()
|
||||
ui->m_type_cb->addItem(tr("Générique"), TerminalData::Generic);
|
||||
ui->m_type_cb->addItem(tr("Bornier intérieur"), TerminalData::Inner);
|
||||
ui->m_type_cb->addItem(tr("Bornier extérieur"), TerminalData::Outer);
|
||||
ui->m_type_cb->addItem(tr("NO (contact SW)"), TerminalData::No);
|
||||
ui->m_type_cb->addItem(tr("NC (contact SW)"), TerminalData::Nc);
|
||||
ui->m_type_cb->addItem(tr("Commun (contact SW)"), TerminalData::Common);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -174,6 +174,12 @@ QString TerminalData::typeToString(TerminalData::Type type)
|
||||
return QString("Inner");
|
||||
case Outer :
|
||||
return QString("Outer");
|
||||
case No :
|
||||
return QString("No");
|
||||
case Nc :
|
||||
return QString("Nc");
|
||||
case Common :
|
||||
return QString("Common");
|
||||
}
|
||||
return QString("Generic");
|
||||
}
|
||||
@@ -193,6 +199,12 @@ TerminalData::Type TerminalData::typeFromString(const QString &string)
|
||||
return TerminalData::Inner;
|
||||
} else if (string == "Outer") {
|
||||
return TerminalData::Outer;
|
||||
} else if (string == "No") {
|
||||
return TerminalData::No;
|
||||
} else if (string == "Nc") {
|
||||
return TerminalData::Nc;
|
||||
} else if (string == "Common") {
|
||||
return TerminalData::Common;
|
||||
} else {
|
||||
qDebug() << "TerminalData::typeFromString, argument string is invalid"
|
||||
" failsafe type 'TerminalData::Generic' is returned";
|
||||
|
||||
@@ -41,7 +41,10 @@ class TerminalData : public PropertiesInterface
|
||||
enum Type {
|
||||
Generic,
|
||||
Inner,
|
||||
Outer
|
||||
Outer,
|
||||
No, ///< Normally Open terminal (for SW contacts)
|
||||
Nc, ///< Normally Closed terminal (for SW contacts)
|
||||
Common ///< Common terminal (for SW contacts)
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
|
||||
@@ -493,11 +493,86 @@ void CrossRefItem::setUpCrossBoundingRect(QPainter &painter)
|
||||
|
||||
QStringList no_str, nc_str;
|
||||
|
||||
// Helper lambda: build "[13-14] pos" string for an element.
|
||||
// For power contacts (e.g. 3-pole contactor), all named terminals
|
||||
// are collected (e.g. "[1-2-3-4-5-6] pos").
|
||||
// For other contacts (NO/NC/SW), only the first 2 named terminals
|
||||
// are used — users are expected to name and order their terminals
|
||||
// in the element editor.
|
||||
// Helper lambda: build "[13-14] pos" for an element.
|
||||
// - Power: all terminals sorted numerically → "[1-2-3-4-5-6] pos"
|
||||
// - SW with typed terminals: show relevant pair per column (handled below)
|
||||
// - Others: first 2 named terminals
|
||||
auto buildLabel = [this](Element *elmt, bool is_no_col) -> QString {
|
||||
const bool is_power =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
|
||||
QStringList tnames;
|
||||
|
||||
if (is_sw) {
|
||||
// Check if terminals have explicit No/Nc/Common types
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString no_name, nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
// NO column: show NO+Common pair; NC column: show NC+Common pair
|
||||
if (is_no_col)
|
||||
tnames << no_name << common_name;
|
||||
else
|
||||
tnames << nc_name << common_name;
|
||||
} else {
|
||||
// Fallback: first 2 named terminals
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames << tn; if (tnames.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames << tn;
|
||||
if (!is_power && tnames.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
if (is_power) {
|
||||
std::sort(tnames.begin(), tnames.end(),
|
||||
[](const QString &a, const QString &b){
|
||||
return a.toInt() < b.toInt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QString pos = elementPositionText(elmt, true);
|
||||
if (!tnames.isEmpty())
|
||||
return QStringLiteral("[") + tnames.join("-") + QStringLiteral("] ") + pos;
|
||||
return pos;
|
||||
};
|
||||
|
||||
for (auto elmt : NOElements()) {
|
||||
no_str.append(elementPositionText(elmt, true));
|
||||
no_str.append(buildLabel(elmt, true));
|
||||
}
|
||||
for (auto elmt : NCElements()) {
|
||||
nc_str.append(elementPositionText(elmt, true));
|
||||
nc_str.append(buildLabel(elmt, false));
|
||||
}
|
||||
|
||||
//There is no string to display, we return now
|
||||
@@ -606,7 +681,7 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||
else if (type == "delayOff") option += DelayOff;
|
||||
else if (type == "delayOnOff") option += DelayOnOff;
|
||||
|
||||
QRectF br = drawContact(painter, option, elmt);
|
||||
QRectF br = drawContact(painter, option, elmt, i);
|
||||
bounding_rect = bounding_rect.united(br);
|
||||
}
|
||||
}
|
||||
@@ -625,19 +700,68 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||
@param elmt : the element to display text (the position of the contact)
|
||||
@return The bounding rect of the draw (contact + text)
|
||||
*/
|
||||
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, int pole_index)
|
||||
{
|
||||
QString str = elementPositionText(elmt);
|
||||
|
||||
// Collect terminal names from the element definition (.elmt)
|
||||
// e.g. name="13" and name="14" on each terminal
|
||||
// For power contacts, sort numerically and pick the pair for pole_index.
|
||||
// For SW contacts with typed terminals (No/Nc/Common), filter by role.
|
||||
QStringList terminal_names;
|
||||
const bool is_power_ctc =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw = (flags & SW) && !(flags & NOC);
|
||||
|
||||
// Check if SW terminals have explicit No/Nc/Common types
|
||||
bool sw_has_typed_terminals = false;
|
||||
if (is_sw) {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
sw_has_typed_terminals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tname = t->name();
|
||||
if (!tname.isEmpty())
|
||||
terminal_names << tname;
|
||||
}
|
||||
|
||||
if (is_power_ctc) {
|
||||
std::sort(terminal_names.begin(), terminal_names.end(),
|
||||
[](const QString &a, const QString &b){
|
||||
return a.toInt() < b.toInt();
|
||||
});
|
||||
// Pick the pair for this pole: pole 0 → [0,1], pole 1 → [2,3], etc.
|
||||
int idx = pole_index * 2;
|
||||
if (idx + 1 < terminal_names.size())
|
||||
terminal_names = QStringList() << terminal_names[idx] << terminal_names[idx+1];
|
||||
else
|
||||
terminal_names.clear();
|
||||
} else if (is_sw && sw_has_typed_terminals) {
|
||||
// Build [NO_name, Common_name, NC_name] from typed terminals
|
||||
QString no_name, nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
// drawText expects: [0]=NC, [1]=NO, [2]=Common
|
||||
// (drawText uses [1] for NO top-left, [0] for NC bottom-left, [2] for Common right)
|
||||
terminal_names.clear();
|
||||
terminal_names << nc_name << no_name << common_name;
|
||||
}
|
||||
|
||||
int offset = m_drawed_contacts*10;
|
||||
QRectF bounding_rect = QRectF(0, offset, 24, 10);
|
||||
|
||||
@@ -795,13 +919,13 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt)
|
||||
// [0]=12 (NO, top-left), [1]=14 (common, top-center), [2]=13 (NC, bottom-center)
|
||||
if (terminal_names.size() >= 1)
|
||||
painter.drawText(QRectF(0, offset, 8, 8),
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[0]); // 12 NO left
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[1]); // 12 NO left
|
||||
if (terminal_names.size() >= 2)
|
||||
painter.drawText(QRectF(16, offset+4, 8, 6),
|
||||
Qt::AlignRight|Qt::AlignTop, terminal_names[1]); // 14 common right
|
||||
Qt::AlignRight|Qt::AlignTop, terminal_names[2]); // 14 common right
|
||||
if (terminal_names.size() >= 3)
|
||||
painter.drawText(QRectF(0, offset+9, 8, 6),
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[2]); // 13 NC left-bottom
|
||||
Qt::AlignLeft|Qt::AlignTop, terminal_names[0]); // 13 NC left-bottom
|
||||
painter.setFont(QETApp::diagramTextsFont(5));
|
||||
}
|
||||
|
||||
@@ -903,7 +1027,60 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
|
||||
painter.setPen(pen);
|
||||
|
||||
// Collect terminal names for NO column.
|
||||
// Power: all terminals sorted numerically.
|
||||
// SW with typed terminals: NO+Common pair.
|
||||
// Others: first 2 named terminals.
|
||||
const bool is_power_no =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw_no =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
QStringList tnames;
|
||||
if (is_sw_no) {
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString no_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::No) no_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
tnames << no_name << common_name;
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames << tn; if (tnames.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames << tn;
|
||||
if (!is_power_no && tnames.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString terminal_label;
|
||||
if (!tnames.isEmpty())
|
||||
terminal_label = QStringLiteral("[") + tnames.join("-") + QStringLiteral("]");
|
||||
|
||||
QString str = elementPositionText(elmt, true);
|
||||
if (!terminal_label.isEmpty())
|
||||
str = terminal_label + QStringLiteral(" ") + str;
|
||||
|
||||
QRectF bounding = painter.boundingRect(
|
||||
QRectF(no_top_left,
|
||||
QSize(middle_cross, 1)),
|
||||
@@ -932,7 +1109,60 @@ void CrossRefItem::fillCrossRef(QPainter &painter)
|
||||
:pen.setColor(Qt::black);
|
||||
painter.setPen(pen);
|
||||
|
||||
// Collect terminal names for NC column.
|
||||
// Power: all terminals sorted numerically.
|
||||
// SW with typed terminals: NC+Common pair.
|
||||
// Others: first 2 named terminals.
|
||||
const bool is_power_nc =
|
||||
elmt->kindInformations()["type"].toString() == "power";
|
||||
const bool is_sw_nc =
|
||||
elmt->kindInformations()["state"].toString() == "SW";
|
||||
QStringList tnames_nc;
|
||||
if (is_sw_nc) {
|
||||
bool has_typed = false;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (t->terminalType() == TerminalData::No ||
|
||||
t->terminalType() == TerminalData::Nc ||
|
||||
t->terminalType() == TerminalData::Common) {
|
||||
has_typed = true; break;
|
||||
}
|
||||
}
|
||||
if (has_typed) {
|
||||
QString nc_name, common_name;
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
if (!t->name().isEmpty()) {
|
||||
if (t->terminalType() == TerminalData::Nc) nc_name = t->name();
|
||||
else if (t->terminalType() == TerminalData::Common) common_name = t->name();
|
||||
}
|
||||
}
|
||||
tnames_nc << nc_name << common_name;
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) { tnames_nc << tn; if (tnames_nc.size() >= 2) break; }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Terminal *t : elmt->terminals()) {
|
||||
if (!t) continue;
|
||||
const QString tn = t->name();
|
||||
if (!tn.isEmpty()) {
|
||||
tnames_nc << tn;
|
||||
if (!is_power_nc && tnames_nc.size() >= 2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QString terminal_label;
|
||||
if (!tnames_nc.isEmpty())
|
||||
terminal_label = QStringLiteral("[") + tnames_nc.join("-") + QStringLiteral("]");
|
||||
|
||||
QString str = elementPositionText(elmt, true);
|
||||
if (!terminal_label.isEmpty())
|
||||
str = terminal_label + QStringLiteral(" ") + str;
|
||||
|
||||
QRectF bounding = painter.boundingRect(
|
||||
QRectF(nc_top_left,
|
||||
QSize(middle_cross, 1)),
|
||||
|
||||
@@ -107,7 +107,7 @@ class CrossRefItem : public QGraphicsObject
|
||||
void setUpCrossBoundingRect(QPainter &painter);
|
||||
void drawAsCross(QPainter &painter);
|
||||
void drawAsContacts(QPainter &painter);
|
||||
QRectF drawContact(QPainter &painter, int flags, Element *elmt);
|
||||
QRectF drawContact(QPainter &painter, int flags, Element *elmt, int pole_index = 0);
|
||||
void fillCrossRef(QPainter &painter);
|
||||
void AddExtraInfo(QPainter &painter, const QString&);
|
||||
QList<Element *> NOElements() const;
|
||||
|
||||
@@ -753,6 +753,15 @@ QString Terminal::name() const
|
||||
return d->m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Terminal::terminalType
|
||||
@return the type of this terminal (Generic, Inner, Outer, No, Nc, Common)
|
||||
*/
|
||||
TerminalData::Type Terminal::terminalType() const
|
||||
{
|
||||
return d->m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Conductor::relatedPotentialTerminal
|
||||
Return terminal at the same potential from the same
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
#ifndef TERMINAL_H
|
||||
#define TERMINAL_H
|
||||
#include "../qet.h"
|
||||
#include "../properties/terminaldata.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtXml>
|
||||
class Conductor;
|
||||
class Diagram;
|
||||
class Element;
|
||||
class TerminalData;
|
||||
|
||||
|
||||
/**
|
||||
@brief The Terminal class
|
||||
@@ -75,6 +76,7 @@ class Terminal : public QGraphicsObject
|
||||
Element *parentElement () const;
|
||||
QUuid uuid () const;
|
||||
QString name () const;
|
||||
TerminalData::Type terminalType() const;
|
||||
|
||||
QList<Conductor *> conductors() const;
|
||||
Qet::Orientation orientation() const;
|
||||
|
||||
Reference in New Issue
Block a user