mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-07-30 07:44:13 +02:00
Merge pull request #545 from Kellermorph/terminal-name
Implement slave contact groups — label transfer, terminal assignment and UI fixes
This commit is contained in:
@@ -623,6 +623,8 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/ui/borderpropertieswidget.h
|
${QET_DIR}/sources/ui/borderpropertieswidget.h
|
||||||
${QET_DIR}/sources/ui/compositetexteditdialog.cpp
|
${QET_DIR}/sources/ui/compositetexteditdialog.cpp
|
||||||
${QET_DIR}/sources/ui/compositetexteditdialog.h
|
${QET_DIR}/sources/ui/compositetexteditdialog.h
|
||||||
|
${QET_DIR}/sources/ui/contactgroupselectiondialog.cpp
|
||||||
|
${QET_DIR}/sources/ui/contactgroupselectiondialog.h
|
||||||
${QET_DIR}/sources/ui/conductorpropertiesdialog.cpp
|
${QET_DIR}/sources/ui/conductorpropertiesdialog.cpp
|
||||||
${QET_DIR}/sources/ui/conductorpropertiesdialog.h
|
${QET_DIR}/sources/ui/conductorpropertiesdialog.h
|
||||||
${QET_DIR}/sources/ui/conductorpropertieswidget.cpp
|
${QET_DIR}/sources/ui/conductorpropertieswidget.cpp
|
||||||
|
|||||||
@@ -85,11 +85,14 @@ ElementData ElementScene::elementData() {
|
|||||||
void ElementScene::setElementData(ElementData data)
|
void ElementScene::setElementData(ElementData data)
|
||||||
{
|
{
|
||||||
bool emit_ = m_element_data.m_informations != data.m_informations;
|
bool emit_ = m_element_data.m_informations != data.m_informations;
|
||||||
|
bool type_changed = m_element_data.m_type != data.m_type;
|
||||||
|
|
||||||
m_element_data = data;
|
m_element_data = data;
|
||||||
|
|
||||||
if (emit_)
|
if (emit_)
|
||||||
emit elementInfoChanged();
|
emit elementInfoChanged();
|
||||||
|
if (type_changed)
|
||||||
|
emit elementTypeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ class ElementScene : public QGraphicsScene
|
|||||||
/// Signal emitted when need zoomFit
|
/// Signal emitted when need zoomFit
|
||||||
void needZoomFit();
|
void needZoomFit();
|
||||||
void elementInfoChanged();
|
void elementInfoChanged();
|
||||||
|
/// Signal emitted when the element type changes
|
||||||
|
void elementTypeChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ElementScene::ItemOptions)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ElementScene::ItemOptions)
|
||||||
|
|||||||
@@ -460,6 +460,22 @@ void PartTerminal::setLabelColor(QColor color)
|
|||||||
emit labelColorChanged();
|
emit labelColorChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartTerminal::setUseMasterLabel(bool use)
|
||||||
|
{
|
||||||
|
if (d->m_use_master_label == use) return;
|
||||||
|
d->m_use_master_label = use;
|
||||||
|
update();
|
||||||
|
emit useMasterLabelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PartTerminal::setMasterLabelIndex(int index)
|
||||||
|
{
|
||||||
|
if (d->m_master_label_index == index) return;
|
||||||
|
d->m_master_label_index = index;
|
||||||
|
update();
|
||||||
|
emit masterLabelIndexChanged();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Updates the position of the second point according to the position
|
Updates the position of the second point according to the position
|
||||||
and orientation of the terminal.
|
and orientation of the terminal.
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ class PartTerminal : public CustomElementGraphicPart
|
|||||||
Q_PROPERTY(Qt::Alignment label_valignment READ labelVAlignment WRITE setLabelVAlignment)
|
Q_PROPERTY(Qt::Alignment label_valignment READ labelVAlignment WRITE setLabelVAlignment)
|
||||||
Q_PROPERTY(bool label_frame READ labelFrame WRITE setLabelFrame)
|
Q_PROPERTY(bool label_frame READ labelFrame WRITE setLabelFrame)
|
||||||
Q_PROPERTY(QColor label_color READ labelColor WRITE setLabelColor)
|
Q_PROPERTY(QColor label_color READ labelColor WRITE setLabelColor)
|
||||||
|
Q_PROPERTY(bool use_master_label READ useMasterLabel WRITE setUseMasterLabel)
|
||||||
|
Q_PROPERTY(int master_label_index READ masterLabelIndex WRITE setMasterLabelIndex)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// constructors, destructor
|
// constructors, destructor
|
||||||
@@ -62,6 +64,8 @@ class PartTerminal : public CustomElementGraphicPart
|
|||||||
void labelVAlignmentChanged();
|
void labelVAlignmentChanged();
|
||||||
void labelFrameChanged();
|
void labelFrameChanged();
|
||||||
void labelColorChanged();
|
void labelColorChanged();
|
||||||
|
void useMasterLabelChanged();
|
||||||
|
void masterLabelIndexChanged();
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
public:
|
public:
|
||||||
@@ -130,6 +134,12 @@ class PartTerminal : public CustomElementGraphicPart
|
|||||||
QColor labelColor() const { return d->m_label_color; }
|
QColor labelColor() const { return d->m_label_color; }
|
||||||
void setLabelColor(QColor color);
|
void setLabelColor(QColor color);
|
||||||
|
|
||||||
|
bool useMasterLabel() const { return d->m_use_master_label; }
|
||||||
|
void setUseMasterLabel(bool use);
|
||||||
|
|
||||||
|
int masterLabelIndex() const { return d->m_master_label_index; }
|
||||||
|
void setMasterLabelIndex(int index);
|
||||||
|
|
||||||
void setNewUuid();
|
void setNewUuid();
|
||||||
|
|
||||||
QRectF labelRect() const;
|
QRectF labelRect() const;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@
|
|||||||
#include "../../qetinformation.h"
|
#include "../../qetinformation.h"
|
||||||
|
|
||||||
#include <QItemDelegate>
|
#include <QItemDelegate>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QSignalBlocker>
|
||||||
|
#include <QTableWidgetItem>
|
||||||
|
#include <QHeaderView>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief The EditorDelegate class
|
@brief The EditorDelegate class
|
||||||
@@ -108,6 +113,13 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
|||||||
ui->max_slaves_spinbox->setEnabled(true);
|
ui->max_slaves_spinbox->setEnabled(true);
|
||||||
ui->max_slaves_spinbox->setValue(m_data.m_max_slaves);
|
ui->max_slaves_spinbox->setValue(m_data.m_max_slaves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Slave contact groups checkbox
|
||||||
|
ui->m_slave_groups_checkbox->setChecked(m_data.m_slave_contact_groups_enabled);
|
||||||
|
ui->m_slave_groups_table->setEnabled(m_data.m_slave_contact_groups_enabled);
|
||||||
|
if (m_data.m_slave_contact_groups_enabled) {
|
||||||
|
populateSlaveGroupsTable();
|
||||||
|
}
|
||||||
} else if (m_data.m_type == ElementData::Terminal) {
|
} else if (m_data.m_type == ElementData::Terminal) {
|
||||||
ui->m_terminal_type_cb->setCurrentIndex(
|
ui->m_terminal_type_cb->setCurrentIndex(
|
||||||
ui->m_terminal_type_cb->findData(
|
ui->m_terminal_type_cb->findData(
|
||||||
@@ -168,6 +180,11 @@ void ElementPropertiesEditorWidget::setUpInterface()
|
|||||||
|
|
||||||
// NEU: Checkbox mit der Zahlenbox verbinden (Aktivieren/Deaktivieren)
|
// NEU: Checkbox mit der Zahlenbox verbinden (Aktivieren/Deaktivieren)
|
||||||
connect(ui->max_slaves_checkbox, SIGNAL(toggled(bool)), ui->max_slaves_spinbox, SLOT(setEnabled(bool)));
|
connect(ui->max_slaves_checkbox, SIGNAL(toggled(bool)), ui->max_slaves_spinbox, SLOT(setEnabled(bool)));
|
||||||
|
connect(ui->max_slaves_spinbox, QOverload<int>::of(&QSpinBox::valueChanged), [this](int) {
|
||||||
|
if (ui->m_slave_groups_checkbox->isChecked()) {
|
||||||
|
populateSlaveGroupsTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
populateTree();
|
populateTree();
|
||||||
}
|
}
|
||||||
@@ -250,6 +267,8 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
|||||||
} else {
|
} else {
|
||||||
m_data.m_max_slaves = -1;
|
m_data.m_max_slaves = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readSlaveGroupsFromTable();
|
||||||
}
|
}
|
||||||
else if (m_data.m_type == ElementData::Terminal)
|
else if (m_data.m_type == ElementData::Terminal)
|
||||||
{
|
{
|
||||||
@@ -299,3 +318,217 @@ void ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged(int in
|
|||||||
|
|
||||||
updateTree();
|
updateTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementPropertiesEditorWidget::on_max_slaves_checkbox_toggled
|
||||||
|
* When max_slaves checkbox is unchecked, also uncheck slave groups checkbox
|
||||||
|
*/
|
||||||
|
void ElementPropertiesEditorWidget::on_max_slaves_checkbox_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (!checked && ui->m_slave_groups_checkbox->isChecked()) {
|
||||||
|
ui->m_slave_groups_checkbox->setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementPropertiesEditorWidget::on_m_slave_groups_checkbox_toggled
|
||||||
|
* When slave groups checkbox is toggled, enable/disable the table
|
||||||
|
* Also ensure max_slaves checkbox is checked when enabling groups
|
||||||
|
*/
|
||||||
|
void ElementPropertiesEditorWidget::on_m_slave_groups_checkbox_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->m_slave_groups_table->setEnabled(checked);
|
||||||
|
|
||||||
|
if (checked && !ui->max_slaves_checkbox->isChecked()) {
|
||||||
|
ui->max_slaves_checkbox->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
populateSlaveGroupsTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementPropertiesEditorWidget::populateSlaveGroupsTable
|
||||||
|
* Fill the slave contact groups table from m_data
|
||||||
|
*/
|
||||||
|
void ElementPropertiesEditorWidget::populateSlaveGroupsTable()
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker_table(ui->m_slave_groups_table);
|
||||||
|
QSignalBlocker blocker_spinbox(ui->max_slaves_spinbox);
|
||||||
|
ui->m_slave_groups_table->setRowCount(0);
|
||||||
|
|
||||||
|
int row_count = ui->max_slaves_checkbox->isChecked()
|
||||||
|
? ui->max_slaves_spinbox->value() : 0;
|
||||||
|
|
||||||
|
// If we have existing groups, use their count (up to max_slaves)
|
||||||
|
int existing_groups = m_data.m_slave_contact_groups.size();
|
||||||
|
|
||||||
|
// Adjust the groups list to match the spinbox value
|
||||||
|
while (m_data.m_slave_contact_groups.size() < row_count) {
|
||||||
|
ElementData::SlaveContactGroup group;
|
||||||
|
group.type = ElementData::NO;
|
||||||
|
group.subtype = ElementData::SSimple;
|
||||||
|
group.contactCount = 1;
|
||||||
|
group.terminalCount = 2;
|
||||||
|
m_data.m_slave_contact_groups.append(group);
|
||||||
|
}
|
||||||
|
while (m_data.m_slave_contact_groups.size() > row_count) {
|
||||||
|
m_data.m_slave_contact_groups.removeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find max terminal count across all groups to determine T columns
|
||||||
|
int max_tc = 0;
|
||||||
|
for (const auto &g : m_data.m_slave_contact_groups) {
|
||||||
|
max_tc = qMax(max_tc, g.terminalCount);
|
||||||
|
}
|
||||||
|
max_tc = qMax(max_tc, 2); // at least T1, T2
|
||||||
|
|
||||||
|
// Set up 4 fixed columns + max_tc label columns
|
||||||
|
int total_cols = 4 + max_tc;
|
||||||
|
ui->m_slave_groups_table->setColumnCount(total_cols);
|
||||||
|
|
||||||
|
// Set T column headers
|
||||||
|
for (int t = 0; t < max_tc; ++t) {
|
||||||
|
ui->m_slave_groups_table->setHorizontalHeaderItem(
|
||||||
|
4 + t, new QTableWidgetItem(tr("T%1").arg(t + 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set column widths for readability
|
||||||
|
ui->m_slave_groups_table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
ui->m_slave_groups_table->horizontalHeader()->setMinimumSectionSize(60);
|
||||||
|
ui->m_slave_groups_table->setColumnWidth(0, 180); // Type
|
||||||
|
ui->m_slave_groups_table->setColumnWidth(1, 180); // Subtype
|
||||||
|
ui->m_slave_groups_table->setColumnWidth(2, 80); // Contacts
|
||||||
|
ui->m_slave_groups_table->setColumnWidth(3, 80); // Bornes
|
||||||
|
|
||||||
|
ui->m_slave_groups_table->setRowCount(m_data.m_slave_contact_groups.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < m_data.m_slave_contact_groups.size(); ++i) {
|
||||||
|
auto &group = m_data.m_slave_contact_groups[i];
|
||||||
|
|
||||||
|
// Type column
|
||||||
|
auto *type_cb = new QComboBox(ui->m_slave_groups_table);
|
||||||
|
type_cb->addItem(tr("Normalement ouvert"), ElementData::NO);
|
||||||
|
type_cb->addItem(tr("Normalement fermé"), ElementData::NC);
|
||||||
|
type_cb->addItem(tr("Inverseur"), ElementData::SW);
|
||||||
|
type_cb->addItem(tr("Autre"), ElementData::Other);
|
||||||
|
type_cb->setCurrentIndex(type_cb->findData(group.type));
|
||||||
|
ui->m_slave_groups_table->setCellWidget(i, 0, type_cb);
|
||||||
|
|
||||||
|
// Subtype column
|
||||||
|
auto *subtype_cb = new QComboBox(ui->m_slave_groups_table);
|
||||||
|
subtype_cb->addItem(tr("Simple"), ElementData::SSimple);
|
||||||
|
subtype_cb->addItem(tr("Puissance"), ElementData::Power);
|
||||||
|
subtype_cb->addItem(tr("Temporisé travail"), ElementData::DelayOn);
|
||||||
|
subtype_cb->addItem(tr("Temporisé repos"), ElementData::DelayOff);
|
||||||
|
subtype_cb->addItem(tr("Temporisé travail & repos"), ElementData::delayOnOff);
|
||||||
|
subtype_cb->setCurrentIndex(subtype_cb->findData(group.subtype));
|
||||||
|
ui->m_slave_groups_table->setCellWidget(i, 1, subtype_cb);
|
||||||
|
|
||||||
|
// Contact count
|
||||||
|
auto *contact_ct = new QSpinBox(ui->m_slave_groups_table);
|
||||||
|
contact_ct->setMinimum(1);
|
||||||
|
contact_ct->setMaximum(20);
|
||||||
|
contact_ct->setValue(group.contactCount);
|
||||||
|
ui->m_slave_groups_table->setCellWidget(i, 2, contact_ct);
|
||||||
|
|
||||||
|
// Terminal count
|
||||||
|
auto *terminal_ct = new QSpinBox(ui->m_slave_groups_table);
|
||||||
|
terminal_ct->setMinimum(1);
|
||||||
|
terminal_ct->setMaximum(20);
|
||||||
|
terminal_ct->setValue(group.terminalCount);
|
||||||
|
ui->m_slave_groups_table->setCellWidget(i, 3, terminal_ct);
|
||||||
|
|
||||||
|
// When terminal count changes, rebuild the table to update T columns
|
||||||
|
connect(terminal_ct, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||||
|
this, [this, terminal_ct, i](int val) {
|
||||||
|
if (i < m_data.m_slave_contact_groups.size()) {
|
||||||
|
m_data.m_slave_contact_groups[i].terminalCount = val;
|
||||||
|
readSlaveGroupsFromTable();
|
||||||
|
populateSlaveGroupsTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto-generate labels if empty
|
||||||
|
QStringList labels = group.labels;
|
||||||
|
while (labels.size() < group.terminalCount) {
|
||||||
|
labels << tr("T%1").arg(labels.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill T1..TN columns
|
||||||
|
for (int t = 0; t < max_tc; ++t) {
|
||||||
|
auto *item = new QTableWidgetItem(
|
||||||
|
t < labels.size() ? labels.at(t) : QString());
|
||||||
|
if (t >= group.terminalCount) {
|
||||||
|
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
item->setBackground(QBrush(QColor(240, 240, 240)));
|
||||||
|
}
|
||||||
|
ui->m_slave_groups_table->setItem(i, 4 + t, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store updated labels back
|
||||||
|
group.labels = labels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementPropertiesEditorWidget::readSlaveGroupsFromTable
|
||||||
|
* Read the slave contact groups from the table back into m_data
|
||||||
|
*/
|
||||||
|
void ElementPropertiesEditorWidget::readSlaveGroupsFromTable()
|
||||||
|
{
|
||||||
|
m_data.m_slave_contact_groups.clear();
|
||||||
|
|
||||||
|
if (!ui->m_slave_groups_checkbox->isChecked()) {
|
||||||
|
m_data.m_slave_contact_groups_enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.m_slave_contact_groups_enabled = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < ui->m_slave_groups_table->rowCount(); ++i) {
|
||||||
|
ElementData::SlaveContactGroup group;
|
||||||
|
|
||||||
|
auto *type_cb = qobject_cast<QComboBox *>(
|
||||||
|
ui->m_slave_groups_table->cellWidget(i, 0));
|
||||||
|
if (type_cb) {
|
||||||
|
group.type = type_cb->currentData().value<ElementData::SlaveState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *subtype_cb = qobject_cast<QComboBox *>(
|
||||||
|
ui->m_slave_groups_table->cellWidget(i, 1));
|
||||||
|
if (subtype_cb) {
|
||||||
|
group.subtype = subtype_cb->currentData().value<ElementData::SlaveType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *contact_ct = qobject_cast<QSpinBox *>(
|
||||||
|
ui->m_slave_groups_table->cellWidget(i, 2));
|
||||||
|
if (contact_ct) {
|
||||||
|
group.contactCount = contact_ct->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *terminal_ct = qobject_cast<QSpinBox *>(
|
||||||
|
ui->m_slave_groups_table->cellWidget(i, 3));
|
||||||
|
if (terminal_ct) {
|
||||||
|
group.terminalCount = terminal_ct->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read labels from T1..TN columns
|
||||||
|
for (int t = 0; t < group.terminalCount; ++t) {
|
||||||
|
int col = 4 + t;
|
||||||
|
if (col < ui->m_slave_groups_table->columnCount()) {
|
||||||
|
auto *item = ui->m_slave_groups_table->item(i, col);
|
||||||
|
if (item && !item->text().isEmpty()) {
|
||||||
|
group.labels.append(item->text());
|
||||||
|
} else {
|
||||||
|
group.labels << tr("T%1").arg(t + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
group.labels << tr("T%1").arg(t + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.m_slave_contact_groups.append(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,11 +49,15 @@ class ElementPropertiesEditorWidget : public QDialog
|
|||||||
void setUpInterface();
|
void setUpInterface();
|
||||||
void updateTree();
|
void updateTree();
|
||||||
void populateTree();
|
void populateTree();
|
||||||
|
void populateSlaveGroupsTable();
|
||||||
|
void readSlaveGroupsFromTable();
|
||||||
|
|
||||||
//SLOTS
|
//SLOTS
|
||||||
private slots:
|
private slots:
|
||||||
void on_m_buttonBox_accepted();
|
void on_m_buttonBox_accepted();
|
||||||
void on_m_base_type_cb_currentIndexChanged(int index);
|
void on_m_base_type_cb_currentIndexChanged(int index);
|
||||||
|
void on_m_slave_groups_checkbox_toggled(bool checked);
|
||||||
|
void on_max_slaves_checkbox_toggled(bool checked);
|
||||||
|
|
||||||
//ATTRIBUTES
|
//ATTRIBUTES
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -121,6 +121,55 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="m_slave_groups_checkbox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Définir les éléments esclave</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QTableWidget" name="m_slave_groups_table">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>150</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Contact</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Nb. contacts</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Nb. bornes</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -1192,6 +1192,12 @@ void QETElementEditor::initGui()
|
|||||||
updateInformations();
|
updateInformations();
|
||||||
fillPartsList();
|
fillPartsList();
|
||||||
|
|
||||||
|
// When the element type changes, update the terminal editor master label visibility
|
||||||
|
connect(m_elmt_scene, &ElementScene::elementTypeChanged, this, [this]() {
|
||||||
|
auto *te = static_cast<TerminalEditor *>(m_editors["terminal"]);
|
||||||
|
if (te) te->refreshMasterLabelVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
statusBar()->showMessage(tr("Éditeur d'éléments", "status bar message"));
|
statusBar()->showMessage(tr("Éditeur d'éléments", "status bar message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
#include <QFontDialog>
|
#include <QFontDialog>
|
||||||
|
#include "../elementscene.h"
|
||||||
|
#include "qetelementeditor.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TerminalEditor::TerminalEditor
|
* @brief TerminalEditor::TerminalEditor
|
||||||
@@ -101,6 +103,26 @@ void TerminalEditor::updateForm()
|
|||||||
|
|
||||||
ui->m_text_props_gb->setEnabled(m_part->showName());
|
ui->m_text_props_gb->setEnabled(m_part->showName());
|
||||||
|
|
||||||
|
// Update master label fields
|
||||||
|
bool is_slave = updateMasterLabelVisibility();
|
||||||
|
if (is_slave) {
|
||||||
|
PartTerminal *pt = m_part;
|
||||||
|
if (pt) {
|
||||||
|
ui->m_use_master_label_cb->setChecked(pt->useMasterLabel());
|
||||||
|
ui->m_master_label_cb->setEnabled(pt->useMasterLabel());
|
||||||
|
ui->m_name_le->setEnabled(!pt->useMasterLabel());
|
||||||
|
int idx = ui->m_master_label_cb->findData(pt->masterLabelIndex());
|
||||||
|
if (idx >= 0) {
|
||||||
|
ui->m_master_label_cb->setCurrentIndex(idx);
|
||||||
|
}
|
||||||
|
// Show T-label in name field when master label is active
|
||||||
|
if (pt->useMasterLabel()) {
|
||||||
|
int label_idx = pt->masterLabelIndex();
|
||||||
|
ui->m_name_le->setText(tr("T%1").arg(label_idx + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
activeConnections(true);
|
activeConnections(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +187,14 @@ void TerminalEditor::init()
|
|||||||
ui->m_type_cb->addItem(tr("Commun (contact SW)"), TerminalData::Common);
|
ui->m_type_cb->addItem(tr("Commun (contact SW)"), TerminalData::Common);
|
||||||
|
|
||||||
ui->m_text_props_gb->setEnabled(false);
|
ui->m_text_props_gb->setEnabled(false);
|
||||||
|
|
||||||
|
// Populate master label dropdown (T1-T20)
|
||||||
|
for (int i = 1; i <= 20; ++i) {
|
||||||
|
ui->m_master_label_cb->addItem(tr("T%1").arg(i), i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if parent element is a Slave to show/hide master label group
|
||||||
|
updateMasterLabelVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -427,6 +457,10 @@ void TerminalEditor::activeConnections(bool active)
|
|||||||
this, &TerminalEditor::labelAlignClicked);
|
this, &TerminalEditor::labelAlignClicked);
|
||||||
m_editor_connections << connect(ui->m_label_frame_cb, &QCheckBox::toggled,
|
m_editor_connections << connect(ui->m_label_frame_cb, &QCheckBox::toggled,
|
||||||
this, &TerminalEditor::labelFrameEdited);
|
this, &TerminalEditor::labelFrameEdited);
|
||||||
|
m_editor_connections << connect(ui->m_use_master_label_cb, &QCheckBox::toggled,
|
||||||
|
this, &TerminalEditor::useMasterLabelEdited);
|
||||||
|
m_editor_connections << connect(ui->m_master_label_cb, QOverload<int>::of(&QComboBox::activated),
|
||||||
|
this, &TerminalEditor::masterLabelIndexEdited);
|
||||||
} else {
|
} else {
|
||||||
for (auto const & con : std::as_const(m_editor_connections)) {
|
for (auto const & con : std::as_const(m_editor_connections)) {
|
||||||
QObject::disconnect(con);
|
QObject::disconnect(con);
|
||||||
@@ -452,6 +486,8 @@ void TerminalEditor::activeChangeConnections(bool active)
|
|||||||
m_change_connections << connect(m_part, &PartTerminal::labelVAlignmentChanged, this, &TerminalEditor::updateForm);
|
m_change_connections << connect(m_part, &PartTerminal::labelVAlignmentChanged, this, &TerminalEditor::updateForm);
|
||||||
m_change_connections << connect(m_part, &PartTerminal::labelFrameChanged, this, &TerminalEditor::updateForm);
|
m_change_connections << connect(m_part, &PartTerminal::labelFrameChanged, this, &TerminalEditor::updateForm);
|
||||||
m_change_connections << connect(m_part, &PartTerminal::labelColorChanged, this, &TerminalEditor::updateForm);
|
m_change_connections << connect(m_part, &PartTerminal::labelColorChanged, this, &TerminalEditor::updateForm);
|
||||||
|
m_change_connections << connect(m_part, &PartTerminal::useMasterLabelChanged, this, &TerminalEditor::updateForm);
|
||||||
|
m_change_connections << connect(m_part, &PartTerminal::masterLabelIndexChanged, this, &TerminalEditor::updateForm);
|
||||||
} else {
|
} else {
|
||||||
for (auto &con : m_change_connections) {
|
for (auto &con : m_change_connections) {
|
||||||
QObject::disconnect(con);
|
QObject::disconnect(con);
|
||||||
@@ -459,3 +495,95 @@ void TerminalEditor::activeChangeConnections(bool active)
|
|||||||
m_change_connections.clear();
|
m_change_connections.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalEditor::useMasterLabelEdited()
|
||||||
|
{
|
||||||
|
if (m_locked) return;
|
||||||
|
m_locked = true;
|
||||||
|
|
||||||
|
bool use = ui->m_use_master_label_cb->isChecked();
|
||||||
|
ui->m_master_label_cb->setEnabled(use);
|
||||||
|
|
||||||
|
QSignalBlocker name_blocker(ui->m_name_le);
|
||||||
|
|
||||||
|
if (m_part->useMasterLabel() != use) {
|
||||||
|
auto undo = new QPropertyUndoCommand(m_part, "use_master_label",
|
||||||
|
m_part->useMasterLabel(), use);
|
||||||
|
undo->setText(tr("Modifier l'étiquette du maître"));
|
||||||
|
undoStack().push(undo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use) {
|
||||||
|
int idx = ui->m_master_label_cb->currentData().toInt();
|
||||||
|
QString t_label = tr("T%1").arg(idx + 1);
|
||||||
|
ui->m_name_le->setText(t_label);
|
||||||
|
ui->m_name_le->setEnabled(false);
|
||||||
|
if (m_part->terminalName() != t_label) {
|
||||||
|
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||||
|
m_part->terminalName(), t_label);
|
||||||
|
undo->setText(tr("Modifier le nom de la borne"));
|
||||||
|
undoStack().push(undo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui->m_name_le->setEnabled(true);
|
||||||
|
if (!m_part->terminalName().isEmpty()) {
|
||||||
|
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||||
|
m_part->terminalName(), QString());
|
||||||
|
undo->setText(tr("Modifier le nom de la borne"));
|
||||||
|
undoStack().push(undo);
|
||||||
|
}
|
||||||
|
ui->m_name_le->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalEditor::masterLabelIndexEdited()
|
||||||
|
{
|
||||||
|
if (m_locked) return;
|
||||||
|
m_locked = true;
|
||||||
|
|
||||||
|
int idx = ui->m_master_label_cb->currentData().toInt();
|
||||||
|
|
||||||
|
if (m_part->masterLabelIndex() != idx) {
|
||||||
|
auto undo = new QPropertyUndoCommand(m_part, "master_label_index",
|
||||||
|
m_part->masterLabelIndex(), idx);
|
||||||
|
undo->setText(tr("Modifier l'index de l'étiquette du maître"));
|
||||||
|
undoStack().push(undo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui->m_use_master_label_cb->isChecked()) {
|
||||||
|
QString t_label = tr("T%1").arg(idx + 1);
|
||||||
|
ui->m_name_le->setText(t_label);
|
||||||
|
if (m_part->terminalName() != t_label) {
|
||||||
|
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||||
|
m_part->terminalName(), t_label);
|
||||||
|
undo->setText(tr("Modifier le nom de la borne"));
|
||||||
|
undoStack().push(undo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerminalEditor::updateMasterLabelVisibility()
|
||||||
|
{
|
||||||
|
QETElementEditor *editor = elementEditor();
|
||||||
|
if (!editor || !editor->elementScene()) {
|
||||||
|
ui->m_master_label_gb->setVisible(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementData data = editor->elementScene()->elementData();
|
||||||
|
bool is_slave = (data.m_type == ElementData::Slave);
|
||||||
|
ui->m_master_label_gb->setVisible(is_slave);
|
||||||
|
return is_slave;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalEditor::refreshMasterLabelVisibility()
|
||||||
|
{
|
||||||
|
updateMasterLabelVisibility();
|
||||||
|
if (m_part) {
|
||||||
|
updateForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ class TerminalEditor : public ElementItemEditor
|
|||||||
bool setPart(CustomElementPart *new_part) override;
|
bool setPart(CustomElementPart *new_part) override;
|
||||||
CustomElementPart *currentPart() const override;
|
CustomElementPart *currentPart() const override;
|
||||||
QList<CustomElementPart *> currentParts() const override {return QList<CustomElementPart *>();}
|
QList<CustomElementPart *> currentParts() const override {return QList<CustomElementPart *>();}
|
||||||
|
public slots:
|
||||||
|
void refreshMasterLabelVisibility();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
@@ -66,6 +68,9 @@ class TerminalEditor : public ElementItemEditor
|
|||||||
void labelColorClicked();
|
void labelColorClicked();
|
||||||
void activeConnections(bool active);
|
void activeConnections(bool active);
|
||||||
void activeChangeConnections(bool active);
|
void activeChangeConnections(bool active);
|
||||||
|
void useMasterLabelEdited();
|
||||||
|
void masterLabelIndexEdited();
|
||||||
|
bool updateMasterLabelVisibility();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::TerminalEditor *ui;
|
Ui::TerminalEditor *ui;
|
||||||
|
|||||||
@@ -214,6 +214,32 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="6" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="m_master_label_gb">
|
||||||
|
<property name="title">
|
||||||
|
<string>Étiquette du maître</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QCheckBox" name="m_use_master_label_cb">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reprendre du maître</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="m_master_label_cb">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
@@ -49,18 +49,7 @@ bool ElementData::fromXml(const QDomElement &xml_element)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- OUR DEBUG BLOCK STARTS HERE ---
|
m_type = typeFromString(xml_element.attribute(QStringLiteral("link_type"), QStringLiteral("simple")));
|
||||||
// We retrieve the string from the XML and store it temporarily
|
|
||||||
QString raw_type_string = xml_element.attribute(QStringLiteral("link_type"), QStringLiteral("simple"));
|
|
||||||
|
|
||||||
qDebug() << "\n=== NEW COMPONENT IS LOADING ===";
|
|
||||||
qDebug() << "[XML Parser] Raw “link_type” string from the .elmt file:" << raw_type_string;
|
|
||||||
|
|
||||||
// Now we’ll pass it on to your translation function
|
|
||||||
m_type = typeFromString(raw_type_string);
|
|
||||||
|
|
||||||
qDebug() << "[XML Parser] Translated ElementData type:" << typeToString(m_type);
|
|
||||||
// --- THIS IS WHERE OUR DEBUG BLOCK ENDS ---
|
|
||||||
|
|
||||||
kindInfoFromXml(xml_element);
|
kindInfoFromXml(xml_element);
|
||||||
m_informations.fromXml(xml_element.firstChildElement(QStringLiteral("elementInformations")),
|
m_informations.fromXml(xml_element.firstChildElement(QStringLiteral("elementInformations")),
|
||||||
@@ -98,6 +87,31 @@ QDomElement ElementData::kindInfoToXml(QDomDocument &document)
|
|||||||
|
|
||||||
returned_elmt.appendChild(xml_max_slaves);
|
returned_elmt.appendChild(xml_max_slaves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save slave contact groups if enabled
|
||||||
|
if (m_slave_contact_groups_enabled) {
|
||||||
|
auto xml_groups = document.createElement(QStringLiteral("slaveContactGroups"));
|
||||||
|
for (const auto &group : m_slave_contact_groups) {
|
||||||
|
auto xml_group = document.createElement(QStringLiteral("group"));
|
||||||
|
xml_group.setAttribute(QStringLiteral("type"),
|
||||||
|
slaveStateToString(group.type));
|
||||||
|
xml_group.setAttribute(QStringLiteral("subtype"),
|
||||||
|
slaveTypeToString(group.subtype));
|
||||||
|
xml_group.setAttribute(QStringLiteral("contactCount"),
|
||||||
|
group.contactCount);
|
||||||
|
xml_group.setAttribute(QStringLiteral("terminalCount"),
|
||||||
|
group.terminalCount);
|
||||||
|
|
||||||
|
for (const auto &label : group.labels) {
|
||||||
|
auto xml_label = document.createElement(QStringLiteral("label"));
|
||||||
|
auto label_txt = document.createTextNode(label);
|
||||||
|
xml_label.appendChild(label_txt);
|
||||||
|
xml_group.appendChild(xml_label);
|
||||||
|
}
|
||||||
|
xml_groups.appendChild(xml_group);
|
||||||
|
}
|
||||||
|
returned_elmt.appendChild(xml_groups);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (m_type == ElementData::Slave)
|
else if (m_type == ElementData::Slave)
|
||||||
{
|
{
|
||||||
@@ -247,6 +261,15 @@ bool ElementData::operator==(const ElementData &data) const
|
|||||||
if(data.m_master_type != m_master_type) {
|
if(data.m_master_type != m_master_type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (data.m_max_slaves != m_max_slaves) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data.m_slave_contact_groups_enabled != m_slave_contact_groups_enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data.m_slave_contact_groups != m_slave_contact_groups) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (data.m_type == ElementData::Slave) {
|
else if (data.m_type == ElementData::Slave) {
|
||||||
if (data.m_slave_state != m_slave_state ||
|
if (data.m_slave_state != m_slave_state ||
|
||||||
@@ -606,8 +629,71 @@ void ElementData::kindInfoFromXml(const QDomElement &xml_element)
|
|||||||
} else if (name == QLatin1String("function")) {
|
} else if (name == QLatin1String("function")) {
|
||||||
m_terminal_function = terminalFunctionFromString(dom_elmt.text());
|
m_terminal_function = terminalFunctionFromString(dom_elmt.text());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse slave contact groups for Master elements
|
||||||
|
if (m_type == ElementData::Master) {
|
||||||
|
auto xml_kind = xml_element.firstChildElement(QStringLiteral("kindInformations"));
|
||||||
|
auto xml_groups = xml_kind.firstChildElement(QStringLiteral("slaveContactGroups"));
|
||||||
|
if (!xml_groups.isNull()) {
|
||||||
|
m_slave_contact_groups_enabled = true;
|
||||||
|
auto group_list = QETXML::findInDomElement(xml_groups, QStringLiteral("group"));
|
||||||
|
for (const auto &xml_group : group_list) {
|
||||||
|
SlaveContactGroup group;
|
||||||
|
group.type = slaveStateFromString(
|
||||||
|
xml_group.attribute(QStringLiteral("type"), QStringLiteral("NO")));
|
||||||
|
group.subtype = slaveTypeFromString(
|
||||||
|
xml_group.attribute(QStringLiteral("subtype"), QStringLiteral("simple")));
|
||||||
|
group.contactCount = xml_group.attribute(
|
||||||
|
QStringLiteral("contactCount"), QStringLiteral("1")).toInt();
|
||||||
|
group.terminalCount = xml_group.attribute(
|
||||||
|
QStringLiteral("terminalCount"), QStringLiteral("1")).toInt();
|
||||||
|
|
||||||
|
auto label_list = QETXML::findInDomElement(xml_group, QStringLiteral("label"));
|
||||||
|
for (const auto &xml_label : label_list) {
|
||||||
|
group.labels.append(xml_label.text());
|
||||||
|
}
|
||||||
|
m_slave_contact_groups.append(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementData::slaveContactGroupTypeToString
|
||||||
|
* Convert a SlaveState to string for XML storage in slave contact groups.
|
||||||
|
* Maps: NO -> "NO", NC -> "NC", SW -> "SW", Other -> "Other"
|
||||||
|
*/
|
||||||
|
QString ElementData::slaveContactGroupTypeToString(ElementData::SlaveState type)
|
||||||
|
{
|
||||||
|
return slaveStateToString(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementData::slaveContactGroupTypeFromString
|
||||||
|
* Convert a string from XML to SlaveState for slave contact groups.
|
||||||
|
*/
|
||||||
|
ElementData::SlaveState ElementData::slaveContactGroupTypeFromString(const QString &string)
|
||||||
|
{
|
||||||
|
return slaveStateFromString(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementData::slaveContactGroupSubtypeToString
|
||||||
|
* Convert a SlaveType to string for XML storage in slave contact groups.
|
||||||
|
*/
|
||||||
|
QString ElementData::slaveContactGroupSubtypeToString(ElementData::SlaveType type)
|
||||||
|
{
|
||||||
|
return slaveTypeToString(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ElementData::slaveContactGroupSubtypeFromString
|
||||||
|
* Convert a string from XML to SlaveType for slave contact groups.
|
||||||
|
*/
|
||||||
|
ElementData::SlaveType ElementData::slaveContactGroupSubtypeFromString(const QString &string)
|
||||||
|
{
|
||||||
|
return slaveTypeFromString(string);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
#include "../diagramcontext.h"
|
#include "../diagramcontext.h"
|
||||||
#include "../NameList/nameslist.h"
|
#include "../NameList/nameslist.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ElementData class
|
* @brief The ElementData class
|
||||||
* WARNING
|
* WARNING
|
||||||
@@ -86,6 +89,31 @@ class ElementData : public PropertiesInterface
|
|||||||
};
|
};
|
||||||
Q_ENUM(TerminalFunction)
|
Q_ENUM(TerminalFunction)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SlaveContactGroup struct
|
||||||
|
* Defines a contact group that a master element provides for slave elements.
|
||||||
|
* Each group specifies the type, subtype, number of displayed contacts,
|
||||||
|
* number of terminals, and the labels for each terminal (T1-T20).
|
||||||
|
*/
|
||||||
|
struct SlaveContactGroup {
|
||||||
|
SlaveState type = NO; ///< Contact type (NO/NC/SW/Other)
|
||||||
|
SlaveType subtype = SSimple; ///< Contact subtype (Simple/Power/Delay*)
|
||||||
|
int contactCount = 1; ///< Number of displayed contacts
|
||||||
|
int terminalCount = 1; ///< Number of terminals (Anschlüsse)
|
||||||
|
QStringList labels; ///< Terminal labels (T1-T20), max 20 entries
|
||||||
|
|
||||||
|
bool operator==(const SlaveContactGroup &other) const {
|
||||||
|
return type == other.type
|
||||||
|
&& subtype == other.subtype
|
||||||
|
&& contactCount == other.contactCount
|
||||||
|
&& terminalCount == other.terminalCount
|
||||||
|
&& labels == other.labels;
|
||||||
|
}
|
||||||
|
bool operator!=(const SlaveContactGroup &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ElementData() {}
|
ElementData() {}
|
||||||
~ElementData() override {}
|
~ElementData() override {}
|
||||||
|
|
||||||
@@ -130,12 +158,19 @@ class ElementData : public PropertiesInterface
|
|||||||
static ElementData::TerminalFunction terminalFunctionFromString(const QString &string);
|
static ElementData::TerminalFunction terminalFunctionFromString(const QString &string);
|
||||||
static QString translatedTerminalFunction(ElementData::TerminalFunction function);
|
static QString translatedTerminalFunction(ElementData::TerminalFunction function);
|
||||||
|
|
||||||
|
static QString slaveContactGroupTypeToString(ElementData::SlaveState type);
|
||||||
|
static ElementData::SlaveState slaveContactGroupTypeFromString(const QString &string);
|
||||||
|
static QString slaveContactGroupSubtypeToString(ElementData::SlaveType type);
|
||||||
|
static ElementData::SlaveType slaveContactGroupSubtypeFromString(const QString &string);
|
||||||
|
|
||||||
// must be public, because this class is a private member
|
// must be public, because this class is a private member
|
||||||
// of Element/ element editor and they must access this data
|
// of Element/ element editor and they must access this data
|
||||||
ElementData::Type m_type = ElementData::Simple;
|
ElementData::Type m_type = ElementData::Simple;
|
||||||
|
|
||||||
ElementData::MasterType m_master_type = ElementData::Coil;
|
ElementData::MasterType m_master_type = ElementData::Coil;
|
||||||
int m_max_slaves{-1};
|
int m_max_slaves{-1};
|
||||||
|
bool m_slave_contact_groups_enabled{false}; ///< Whether slave contact groups table is active
|
||||||
|
QVector<SlaveContactGroup> m_slave_contact_groups; ///< Contact groups defined by master
|
||||||
|
|
||||||
ElementData::SlaveType m_slave_type = ElementData::SSimple;
|
ElementData::SlaveType m_slave_type = ElementData::SSimple;
|
||||||
ElementData::SlaveState m_slave_state = ElementData::NO;
|
ElementData::SlaveState m_slave_state = ElementData::NO;
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ QDomElement TerminalData::toXml(QDomDocument &xml_document) const
|
|||||||
xml_element.setAttribute("label_color", m_label_color.name());
|
xml_element.setAttribute("label_color", m_label_color.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save master label override settings
|
||||||
|
if (m_use_master_label) {
|
||||||
|
xml_element.setAttribute("use_master_label", "true");
|
||||||
|
xml_element.setAttribute("master_label_index", m_master_label_index);
|
||||||
|
}
|
||||||
|
|
||||||
return(xml_element);
|
return(xml_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +203,10 @@ bool TerminalData::fromXml (const QDomElement &xml_element)
|
|||||||
m_label_color = QColor(color_str);
|
m_label_color = QColor(color_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read master label override settings
|
||||||
|
m_use_master_label = (xml_element.attribute("use_master_label") == QLatin1String("true"));
|
||||||
|
m_master_label_index = xml_element.attribute("master_label_index", "0").toInt();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,11 @@ class TerminalData : public PropertiesInterface
|
|||||||
/// Color of the text label
|
/// Color of the text label
|
||||||
QColor m_label_color = Qt::black;
|
QColor m_label_color = Qt::black;
|
||||||
|
|
||||||
|
/// Whether this terminal uses a label from the master's contact group
|
||||||
|
bool m_use_master_label = false;
|
||||||
|
/// Index into the master's contact group labels (T1=0, T2=1, ..., T20=19)
|
||||||
|
int m_master_label_index = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGraphicsObject* q{nullptr};
|
QGraphicsObject* q{nullptr};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -741,7 +741,9 @@ bool Element::fromXml(QDomElement &e,
|
|||||||
QStringLiteral("links_uuids"),
|
QStringLiteral("links_uuids"),
|
||||||
QStringLiteral("link_uuid"));
|
QStringLiteral("link_uuid"));
|
||||||
foreach (QDomElement qdo, uuid_list) {
|
foreach (QDomElement qdo, uuid_list) {
|
||||||
tmp_uuids_link << QUuid(qdo.attribute(QStringLiteral("uuid")));
|
QUuid uuid(qdo.attribute(QStringLiteral("uuid")));
|
||||||
|
int group_index = qdo.attribute(QStringLiteral("group_index"), QStringLiteral("-1")).toInt();
|
||||||
|
tmp_uuids_link << LinkInfo(uuid, group_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//uuid of this element
|
//uuid of this element
|
||||||
@@ -932,6 +934,13 @@ QDomElement Element::toXml(
|
|||||||
QDomElement link_uuid =
|
QDomElement link_uuid =
|
||||||
document.createElement(QStringLiteral("link_uuid"));
|
document.createElement(QStringLiteral("link_uuid"));
|
||||||
link_uuid.setAttribute(QStringLiteral("uuid"), elmt->uuid().toString());
|
link_uuid.setAttribute(QStringLiteral("uuid"), elmt->uuid().toString());
|
||||||
|
|
||||||
|
// Save group index if assigned (for slave->master links)
|
||||||
|
int gi = m_group_index_map.value(elmt, -1);
|
||||||
|
if (gi >= 0) {
|
||||||
|
link_uuid.setAttribute(QStringLiteral("group_index"), gi);
|
||||||
|
}
|
||||||
|
|
||||||
links_uuids.appendChild(link_uuid);
|
links_uuids.appendChild(link_uuid);
|
||||||
}
|
}
|
||||||
element.appendChild(links_uuids);
|
element.appendChild(links_uuids);
|
||||||
@@ -1267,8 +1276,21 @@ void Element::initLink(QETProject *prj)
|
|||||||
if (tmp_uuids_link.isEmpty()) return;
|
if (tmp_uuids_link.isEmpty()) return;
|
||||||
|
|
||||||
ElementProvider ep(prj);
|
ElementProvider ep(prj);
|
||||||
foreach (Element *elmt, ep.fromUuids(tmp_uuids_link)) {
|
QList<QUuid> uuids;
|
||||||
|
for (const auto &linkInfo : tmp_uuids_link) {
|
||||||
|
uuids.append(linkInfo.uuid);
|
||||||
|
}
|
||||||
|
QList<Element *> elements = ep.fromUuids(uuids);
|
||||||
|
for (int i = 0; i < tmp_uuids_link.size(); ++i) {
|
||||||
|
for (Element *elmt : elements) {
|
||||||
|
if (elmt->uuid() == tmp_uuids_link[i].uuid) {
|
||||||
elmt->linkToElement(this);
|
elmt->linkToElement(this);
|
||||||
|
if (tmp_uuids_link[i].group_index >= 0) {
|
||||||
|
m_group_index_map[elmt] = tmp_uuids_link[i].group_index;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tmp_uuids_link.clear();
|
tmp_uuids_link.clear();
|
||||||
}
|
}
|
||||||
@@ -1304,6 +1326,34 @@ QString Element::linkTypeToString() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Element::groupIndexForElement
|
||||||
|
* Returns the group index assigned to the given linked element.
|
||||||
|
* For slave elements, this indicates which contact group of the master
|
||||||
|
* this slave is assigned to.
|
||||||
|
* @param elmt the linked element to query
|
||||||
|
* @return group index, or -1 if not assigned
|
||||||
|
*/
|
||||||
|
int Element::groupIndexForElement(Element *elmt) const
|
||||||
|
{
|
||||||
|
return m_group_index_map.value(elmt, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Element::setGroupIndexForElement
|
||||||
|
* Sets the group index for a linked element.
|
||||||
|
* @param elmt the linked element
|
||||||
|
* @param index the group index to assign
|
||||||
|
*/
|
||||||
|
void Element::setGroupIndexForElement(Element *elmt, int index)
|
||||||
|
{
|
||||||
|
if (index >= 0) {
|
||||||
|
m_group_index_map[elmt] = index;
|
||||||
|
} else {
|
||||||
|
m_group_index_map.remove(elmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Element::setElementInformations
|
@brief Element::setElementInformations
|
||||||
Set new information for this element.
|
Set new information for this element.
|
||||||
|
|||||||
@@ -62,6 +62,20 @@ class Element : public QetGraphicsItem
|
|||||||
Thumbnail = 64,
|
Thumbnail = 64,
|
||||||
ConductorDefinition = 128};
|
ConductorDefinition = 128};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The LinkInfo struct
|
||||||
|
* Stores link data for element connections.
|
||||||
|
* For slave elements, group_index indicates which contact group
|
||||||
|
* of the master this slave is assigned to (-1 = no group assigned).
|
||||||
|
*/
|
||||||
|
struct LinkInfo {
|
||||||
|
QUuid uuid;
|
||||||
|
int group_index = -1; ///< Index into master's slaveContactGroups, -1 = not assigned
|
||||||
|
|
||||||
|
LinkInfo() = default;
|
||||||
|
LinkInfo(const QUuid &u, int gi = -1) : uuid(u), group_index(gi) {}
|
||||||
|
};
|
||||||
|
|
||||||
Element(const ElementsLocation &location,
|
Element(const ElementsLocation &location,
|
||||||
QGraphicsItem * = nullptr,
|
QGraphicsItem * = nullptr,
|
||||||
int *state = nullptr,
|
int *state = nullptr,
|
||||||
@@ -181,6 +195,9 @@ class Element : public QetGraphicsItem
|
|||||||
virtual void initLink(QETProject *);
|
virtual void initLink(QETProject *);
|
||||||
QList<Element *> linkedElements ();
|
QList<Element *> linkedElements ();
|
||||||
|
|
||||||
|
int groupIndexForElement(Element *elmt) const;
|
||||||
|
void setGroupIndexForElement(Element *elmt, int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief linkType
|
* @brief linkType
|
||||||
* use elementData function instead
|
* use elementData function instead
|
||||||
@@ -228,7 +245,8 @@ class Element : public QetGraphicsItem
|
|||||||
protected:
|
protected:
|
||||||
//ATTRIBUTES related to linked element
|
//ATTRIBUTES related to linked element
|
||||||
QList <Element *> connected_elements;
|
QList <Element *> connected_elements;
|
||||||
QList <QUuid> tmp_uuids_link;
|
QList <LinkInfo> tmp_uuids_link;
|
||||||
|
QHash <Element *, int> m_group_index_map; ///< Maps linked elements to their group index (for slave->master links)
|
||||||
QUuid m_uuid;
|
QUuid m_uuid;
|
||||||
kind m_link_type = Element::Simple;
|
kind m_link_type = Element::Simple;
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,8 @@ void Terminal::paint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw label if show_name is enabled
|
// Draw label if show_name is enabled
|
||||||
if (d->m_show_name && !d->m_name.isEmpty()) {
|
const QString display_name = name();
|
||||||
|
if (d->m_show_name && !display_name.isEmpty()) {
|
||||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
||||||
painter->setFont(d->m_label_font);
|
painter->setFont(d->m_label_font);
|
||||||
@@ -282,7 +283,7 @@ void Terminal::paint(
|
|||||||
|
|
||||||
QPointF label_pos = d->m_pos + d->m_label_pos;
|
QPointF label_pos = d->m_pos + d->m_label_pos;
|
||||||
QFontMetrics fm(d->m_label_font);
|
QFontMetrics fm(d->m_label_font);
|
||||||
QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name);
|
QSizeF text_size = fm.size(Qt::TextSingleLine, display_name);
|
||||||
|
|
||||||
if (!qFuzzyIsNull(d->m_label_rotation)) {
|
if (!qFuzzyIsNull(d->m_label_rotation)) {
|
||||||
painter->save();
|
painter->save();
|
||||||
@@ -290,7 +291,7 @@ void Terminal::paint(
|
|||||||
painter->rotate(d->m_label_rotation);
|
painter->rotate(d->m_label_rotation);
|
||||||
QRectF text_rect(-text_size.width()/2.0, -text_size.height()/2.0,
|
QRectF text_rect(-text_size.width()/2.0, -text_size.height()/2.0,
|
||||||
text_size.width(), text_size.height());
|
text_size.width(), text_size.height());
|
||||||
painter->drawText(text_rect, static_cast<int>(d->m_label_halignment | d->m_label_valignment), d->m_name);
|
painter->drawText(text_rect, static_cast<int>(d->m_label_halignment | d->m_label_valignment), display_name);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
} else {
|
} else {
|
||||||
qreal dx = 0, dy = 0;
|
qreal dx = 0, dy = 0;
|
||||||
@@ -306,7 +307,7 @@ void Terminal::paint(
|
|||||||
if (d->m_label_frame) {
|
if (d->m_label_frame) {
|
||||||
painter->drawRect(text_rect.adjusted(-1, -1, 1, 1));
|
painter->drawRect(text_rect.adjusted(-1, -1, 1, 1));
|
||||||
}
|
}
|
||||||
painter->drawText(text_rect, static_cast<int>(Qt::AlignLeft | Qt::AlignTop), d->m_name);
|
painter->drawText(text_rect, static_cast<int>(Qt::AlignLeft | Qt::AlignTop), display_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,12 +379,13 @@ QLineF Terminal::HelpLine() const
|
|||||||
@return Le rectangle (en precision flottante) delimitant la borne et ses alentours.
|
@return Le rectangle (en precision flottante) delimitant la borne et ses alentours.
|
||||||
*/
|
*/
|
||||||
QRectF Terminal::boundingRect() const {
|
QRectF Terminal::boundingRect() const {
|
||||||
if (!d->m_show_name || d->m_name.isEmpty()) {
|
const QString display_name = name();
|
||||||
|
if (!d->m_show_name || display_name.isEmpty()) {
|
||||||
return m_br;
|
return m_br;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFontMetrics fm(d->m_label_font);
|
QFontMetrics fm(d->m_label_font);
|
||||||
QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name);
|
QSizeF text_size = fm.size(Qt::TextSingleLine, display_name);
|
||||||
QPointF label_pos = d->m_pos + d->m_label_pos;
|
QPointF label_pos = d->m_pos + d->m_label_pos;
|
||||||
|
|
||||||
qreal dx = 0, dy = 0;
|
qreal dx = 0, dy = 0;
|
||||||
@@ -808,6 +810,25 @@ QUuid Terminal::uuid() const
|
|||||||
|
|
||||||
QString Terminal::name() const
|
QString Terminal::name() const
|
||||||
{
|
{
|
||||||
|
if (d->m_use_master_label && parent_element_) {
|
||||||
|
// Find the master element in the slave's linked elements
|
||||||
|
for (Element *elmt : parent_element_->linkedElements()) {
|
||||||
|
if (elmt->linkType() == Element::Master) {
|
||||||
|
int group_idx = elmt->groupIndexForElement(parent_element_);
|
||||||
|
if (group_idx >= 0) {
|
||||||
|
const auto &groups = elmt->elementData().m_slave_contact_groups;
|
||||||
|
if (group_idx < groups.size()) {
|
||||||
|
int label_idx = d->m_master_label_index;
|
||||||
|
const QStringList &labels = groups.at(group_idx).labels;
|
||||||
|
if (label_idx >= 0 && label_idx < labels.size()) {
|
||||||
|
return labels.at(label_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return d->m_name;
|
return d->m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,6 +841,28 @@ TerminalData::Type Terminal::terminalType() const
|
|||||||
return d->m_type;
|
return d->m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Terminal::setUseMasterLabel
|
||||||
|
Set whether this terminal uses a label from the master's contact group
|
||||||
|
@param use true to use master label
|
||||||
|
*/
|
||||||
|
void Terminal::setUseMasterLabel(bool use)
|
||||||
|
{
|
||||||
|
d->m_use_master_label = use;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Terminal::setMasterLabelIndex
|
||||||
|
Set the index into the master's contact group labels
|
||||||
|
@param index the label index (0-based)
|
||||||
|
*/
|
||||||
|
void Terminal::setMasterLabelIndex(int index)
|
||||||
|
{
|
||||||
|
d->m_master_label_index = index;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Conductor::relatedPotentialTerminal
|
@brief Conductor::relatedPotentialTerminal
|
||||||
Return terminal at the same potential from the same
|
Return terminal at the same potential from the same
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ class Terminal : public QGraphicsObject
|
|||||||
QUuid uuid () const;
|
QUuid uuid () const;
|
||||||
QString name () const;
|
QString name () const;
|
||||||
TerminalData::Type terminalType() const;
|
TerminalData::Type terminalType() const;
|
||||||
|
bool useMasterLabel() const { return d->m_use_master_label; }
|
||||||
|
void setUseMasterLabel(bool use);
|
||||||
|
int masterLabelIndex() const { return d->m_master_label_index; }
|
||||||
|
void setMasterLabelIndex(int index);
|
||||||
|
|
||||||
QList<Conductor *> conductors() const;
|
QList<Conductor *> conductors() const;
|
||||||
Qet::Orientation orientation() const;
|
Qet::Orientation orientation() const;
|
||||||
|
|||||||
@@ -1179,6 +1179,22 @@ ElementsLocation QETProject::importElement(ElementsLocation &location)
|
|||||||
}
|
}
|
||||||
//Erase the existing element, and use the newer instead
|
//Erase the existing element, and use the newer instead
|
||||||
else if (action == QET::Erase) {
|
else if (action == QET::Erase) {
|
||||||
|
// Warn if the new element introduces slave contact groups
|
||||||
|
QDomElement new_kind = location.xml().firstChildElement("kindInformations");
|
||||||
|
if (!new_kind.firstChildElement("slaveContactGroups").isNull()) {
|
||||||
|
QMessageBox::StandardButton answer = QMessageBox::warning(nullptr,
|
||||||
|
tr("Système de contacts modifié"),
|
||||||
|
tr("Le nouvel élément définit des groupes de contacts esclaves.\n"
|
||||||
|
"Les éléments esclaves existants ne seront pas automatiquement "
|
||||||
|
"assignés. Vous devrez relier manuellement les esclaves "
|
||||||
|
"et assigner les groupes de contacts.\n\n"
|
||||||
|
"Voulez-vous continuer ?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No,
|
||||||
|
QMessageBox::Yes);
|
||||||
|
if (answer == QMessageBox::No) {
|
||||||
|
return ElementsLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
ElementsLocation parent_loc = existing_location.parent();
|
ElementsLocation parent_loc = existing_location.parent();
|
||||||
return m_elements_collection->copy(location, parent_loc);
|
return m_elements_collection->copy(location, parent_loc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "contactgroupselectiondialog.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QItemSelectionModel>
|
||||||
|
|
||||||
|
ContactGroupSelectionDialog::ContactGroupSelectionDialog(
|
||||||
|
const QVector<ElementData::SlaveContactGroup> &groups,
|
||||||
|
const QSet<int> &usedGroupIndices,
|
||||||
|
const ElementData &slaveData,
|
||||||
|
QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
m_used_indices = usedGroupIndices;
|
||||||
|
setWindowTitle(tr("Sélectionner un groupe de contacts"));
|
||||||
|
|
||||||
|
auto *main_layout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
auto *info_label = new QLabel(
|
||||||
|
tr("Sélectionnez le groupe de contacts à assigner à cet élément esclave :"));
|
||||||
|
main_layout->addWidget(info_label);
|
||||||
|
|
||||||
|
// Determine max terminal count for dynamic columns
|
||||||
|
int max_terminals = 0;
|
||||||
|
for (const auto &g : groups) {
|
||||||
|
if (g.terminalCount > max_terminals)
|
||||||
|
max_terminals = g.terminalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build column headers: #, Type, Sous-type, Contacts, Bornes, T1, T2, ...
|
||||||
|
QStringList headers;
|
||||||
|
headers << tr("#")
|
||||||
|
<< tr("Type")
|
||||||
|
<< tr("Sous-type")
|
||||||
|
<< tr("Contacts")
|
||||||
|
<< tr("Bornes");
|
||||||
|
for (int t = 0; t < max_terminals; ++t) {
|
||||||
|
headers << tr("T%1").arg(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_table = new QTableWidget(groups.size(), headers.size(), this);
|
||||||
|
m_table->setHorizontalHeaderLabels(headers);
|
||||||
|
m_table->setSelectionBehavior(QTableWidget::SelectRows);
|
||||||
|
m_table->setSelectionMode(QTableWidget::SingleSelection);
|
||||||
|
m_table->setEditTriggers(QTableWidget::NoEditTriggers);
|
||||||
|
m_table->verticalHeader()->setVisible(false);
|
||||||
|
m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
m_table->horizontalHeader()->setStretchLastSection(false);
|
||||||
|
m_table->verticalHeader()->setDefaultSectionSize(24);
|
||||||
|
|
||||||
|
// Populate table rows
|
||||||
|
for (int row = 0; row < groups.size(); ++row) {
|
||||||
|
const auto &g = groups.at(row);
|
||||||
|
|
||||||
|
auto *num_item = new QTableWidgetItem(QString::number(row + 1));
|
||||||
|
num_item->setTextAlignment(Qt::AlignCenter);
|
||||||
|
m_table->setItem(row, 0, num_item);
|
||||||
|
|
||||||
|
m_table->setItem(row, 1, new QTableWidgetItem(typeToString(g.type)));
|
||||||
|
m_table->setItem(row, 2, new QTableWidgetItem(subtypeToString(g.subtype)));
|
||||||
|
|
||||||
|
auto *ctc_item = new QTableWidgetItem(QString::number(g.contactCount));
|
||||||
|
ctc_item->setTextAlignment(Qt::AlignCenter);
|
||||||
|
m_table->setItem(row, 3, ctc_item);
|
||||||
|
|
||||||
|
auto *term_item = new QTableWidgetItem(QString::number(g.terminalCount));
|
||||||
|
term_item->setTextAlignment(Qt::AlignCenter);
|
||||||
|
m_table->setItem(row, 4, term_item);
|
||||||
|
|
||||||
|
// Fill T1..TN label columns
|
||||||
|
for (int t = 0; t < max_terminals; ++t) {
|
||||||
|
int col = 5 + t;
|
||||||
|
QString label;
|
||||||
|
if (t < g.labels.size()) {
|
||||||
|
label = g.labels.at(t);
|
||||||
|
} else if (t < g.terminalCount) {
|
||||||
|
label = tr("T%1").arg(t + 1);
|
||||||
|
}
|
||||||
|
auto *label_item = new QTableWidgetItem(label);
|
||||||
|
label_item->setTextAlignment(Qt::AlignCenter);
|
||||||
|
m_table->setItem(row, col, label_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark used group rows as disabled (grayed out)
|
||||||
|
QFont disabled_font;
|
||||||
|
disabled_font.setStrikeOut(true);
|
||||||
|
QColor disabled_color(Qt::gray);
|
||||||
|
|
||||||
|
for (int row = 0; row < groups.size(); ++row) {
|
||||||
|
bool disabled = false;
|
||||||
|
QString reason;
|
||||||
|
|
||||||
|
if (m_used_indices.contains(row)) {
|
||||||
|
disabled = true;
|
||||||
|
reason = tr("(déjà assigné)");
|
||||||
|
} else {
|
||||||
|
const auto &g = groups.at(row);
|
||||||
|
if (g.type != slaveData.m_slave_state) {
|
||||||
|
disabled = true;
|
||||||
|
reason = tr("(état ne correspond pas)");
|
||||||
|
} else if (g.subtype != slaveData.m_slave_type) {
|
||||||
|
disabled = true;
|
||||||
|
reason = tr("(sous-type ne correspond pas)");
|
||||||
|
} else if (g.contactCount != slaveData.m_contact_count) {
|
||||||
|
disabled = true;
|
||||||
|
reason = tr("(nombre de contacts ne correspond pas)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
m_disabled_rows.insert(row);
|
||||||
|
for (int col = 0; col < m_table->columnCount(); ++col) {
|
||||||
|
auto *item = m_table->item(row, col);
|
||||||
|
if (item) {
|
||||||
|
item->setForeground(disabled_color);
|
||||||
|
item->setFont(disabled_font);
|
||||||
|
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
|
||||||
|
item->setToolTip(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Show circled "?" as a widget in the first column
|
||||||
|
auto *num_item = m_table->item(row, 0);
|
||||||
|
if (num_item) {
|
||||||
|
num_item->setToolTip(reason);
|
||||||
|
auto *question_label = new QLabel(this);
|
||||||
|
question_label->setText("?");
|
||||||
|
question_label->setAlignment(Qt::AlignCenter);
|
||||||
|
question_label->setStyleSheet(
|
||||||
|
"QLabel {"
|
||||||
|
" color: #1a73e8;"
|
||||||
|
" font-weight: bold;"
|
||||||
|
" font-size: 8px;"
|
||||||
|
" border: 1.5px solid #1a73e8;"
|
||||||
|
" border-radius: 7px;"
|
||||||
|
" min-width: 12px; max-width: 12px;"
|
||||||
|
" min-height: 12px; max-height: 12px;"
|
||||||
|
"}");
|
||||||
|
question_label->setToolTip(reason);
|
||||||
|
m_table->setCellWidget(row, 0, question_label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select first available (non-disabled) row
|
||||||
|
int first_available = 0;
|
||||||
|
for (int row = 0; row < groups.size(); ++row) {
|
||||||
|
if (!m_disabled_rows.contains(row)) {
|
||||||
|
first_available = row;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_table->selectRow(first_available);
|
||||||
|
main_layout->addWidget(m_table);
|
||||||
|
|
||||||
|
// Calculate width based on column count: base + ~60px per column
|
||||||
|
int table_width = 50 + headers.size() * 65;
|
||||||
|
int table_height = 60 + groups.size() * 26;
|
||||||
|
m_table->setMinimumWidth(table_width);
|
||||||
|
m_table->setMinimumHeight(table_height);
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
auto *button_layout = new QHBoxLayout();
|
||||||
|
button_layout->addStretch();
|
||||||
|
|
||||||
|
m_ok_button = new QPushButton(tr("OK"), this);
|
||||||
|
button_layout->addWidget(m_ok_button);
|
||||||
|
|
||||||
|
auto *cancel_button = new QPushButton(tr("Annuler"), this);
|
||||||
|
button_layout->addWidget(cancel_button);
|
||||||
|
|
||||||
|
main_layout->addLayout(button_layout);
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
connect(m_ok_button, &QPushButton::clicked, this, [this]() {
|
||||||
|
auto *item = m_table->currentItem();
|
||||||
|
if (item && !m_disabled_rows.contains(item->row())) {
|
||||||
|
m_selected_index = item->row();
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject);
|
||||||
|
connect(m_table, &QTableWidget::cellDoubleClicked, this, [this](int row, int) {
|
||||||
|
if (!m_disabled_rows.contains(row)) {
|
||||||
|
m_selected_index = row;
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int ContactGroupSelectionDialog::selectedIndex() const
|
||||||
|
{
|
||||||
|
return m_selected_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ContactGroupSelectionDialog::typeToString(ElementData::SlaveState type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ElementData::NO: return tr("Normalement ouvert");
|
||||||
|
case ElementData::NC: return tr("Normalement fermé");
|
||||||
|
case ElementData::SW: return tr("Inverseur");
|
||||||
|
case ElementData::Other: return tr("Autre");
|
||||||
|
default: return tr("Inconnu");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ContactGroupSelectionDialog::subtypeToString(ElementData::SlaveType subtype)
|
||||||
|
{
|
||||||
|
switch (subtype) {
|
||||||
|
case ElementData::SSimple: return tr("Simple");
|
||||||
|
case ElementData::Power: return tr("Puissance");
|
||||||
|
case ElementData::DelayOn: return tr("Temporisé travail");
|
||||||
|
case ElementData::DelayOff: return tr("Temporisé repos");
|
||||||
|
case ElementData::delayOnOff: return tr("Temporisé travail & repos");
|
||||||
|
default: return tr("Inconnu");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef CONTACTGROUPSELECTIONDIALOG_H
|
||||||
|
#define CONTACTGROUPSELECTIONDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
#include "../properties/elementdata.h"
|
||||||
|
|
||||||
|
class QTableWidget;
|
||||||
|
class QTableWidgetItem;
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief The ContactGroupSelectionDialog class
|
||||||
|
A dialog that displays all slave contact groups defined by a master element
|
||||||
|
in a table format. The user can select one group to assign to a slave element.
|
||||||
|
Columns: #, Type, Subtype, Contacts, Terminals, T1, T2, ..., TN
|
||||||
|
*/
|
||||||
|
class ContactGroupSelectionDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContactGroupSelectionDialog(
|
||||||
|
const QVector<ElementData::SlaveContactGroup> &groups,
|
||||||
|
const QSet<int> &usedGroupIndices,
|
||||||
|
const ElementData &slaveData,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
int selectedIndex() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTableWidget *m_table = nullptr;
|
||||||
|
QPushButton *m_ok_button = nullptr;
|
||||||
|
int m_selected_index = -1;
|
||||||
|
QSet<int> m_used_indices;
|
||||||
|
QSet<int> m_disabled_rows;
|
||||||
|
|
||||||
|
static QString typeToString(ElementData::SlaveState type);
|
||||||
|
static QString subtypeToString(ElementData::SlaveType subtype);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONTACTGROUPSELECTIONDIALOG_H
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "linksingleelementwidget.h"
|
#include "linksingleelementwidget.h"
|
||||||
|
#include "contactgroupselectiondialog.h"
|
||||||
#include "../qetgraphicsitem/masterelement.h"
|
#include "../qetgraphicsitem/masterelement.h"
|
||||||
#include "../qetgraphicsitem/conductor.h"
|
#include "../qetgraphicsitem/conductor.h"
|
||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
|
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief LinkSingleElementWidget::LinkSingleElementWidget
|
@brief LinkSingleElementWidget::LinkSingleElementWidget
|
||||||
Default constructor
|
Default constructor
|
||||||
@@ -175,6 +177,7 @@ void LinkSingleElementWidget::apply()
|
|||||||
m_unlink = false;
|
m_unlink = false;
|
||||||
m_element_to_link = nullptr;
|
m_element_to_link = nullptr;
|
||||||
m_pending_qtwi = nullptr;
|
m_pending_qtwi = nullptr;
|
||||||
|
m_pending_group_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,8 +191,12 @@ QUndoCommand *LinkSingleElementWidget::associatedUndo() const
|
|||||||
|
|
||||||
if (m_element_to_link || m_unlink)
|
if (m_element_to_link || m_unlink)
|
||||||
{
|
{
|
||||||
if (m_element_to_link)
|
if (m_element_to_link) {
|
||||||
undo->setLink(m_element_to_link);
|
undo->setLink(m_element_to_link);
|
||||||
|
if (m_pending_group_index >= 0) {
|
||||||
|
undo->setGroupIndex(m_pending_group_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (m_unlink)
|
else if (m_unlink)
|
||||||
undo->unlinkAll();
|
undo->unlinkAll();
|
||||||
|
|
||||||
@@ -531,6 +538,35 @@ void LinkSingleElementWidget::linkTriggered()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_element_to_link = m_qtwi_elmt_hash.value(m_qtwi_at_context_menu);
|
m_element_to_link = m_qtwi_elmt_hash.value(m_qtwi_at_context_menu);
|
||||||
|
m_pending_group_index = -1;
|
||||||
|
|
||||||
|
//If linking a slave to a master with contact groups, show group selection dialog
|
||||||
|
if (m_element->linkType() == Element::Slave
|
||||||
|
&& m_element_to_link
|
||||||
|
&& m_element_to_link->linkType() == Element::Master)
|
||||||
|
{
|
||||||
|
const auto &groups = m_element_to_link->elementData().m_slave_contact_groups;
|
||||||
|
if (!groups.isEmpty())
|
||||||
|
{
|
||||||
|
// Collect already-used group indices from the master
|
||||||
|
QSet<int> used_indices;
|
||||||
|
for (Element *linked : m_element_to_link->linkedElements()) {
|
||||||
|
int idx = m_element_to_link->groupIndexForElement(linked);
|
||||||
|
if (idx >= 0) {
|
||||||
|
used_indices.insert(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactGroupSelectionDialog dlg(groups, used_indices,
|
||||||
|
m_element->elementData(), this);
|
||||||
|
if (dlg.exec() == QDialog::Accepted && dlg.selectedIndex() >= 0) {
|
||||||
|
m_pending_group_index = dlg.selectedIndex();
|
||||||
|
} else {
|
||||||
|
m_element_to_link = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(m_live_edit)
|
if(m_live_edit)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "abstractelementpropertieseditorwidget.h"
|
#include "abstractelementpropertieseditorwidget.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class Element;
|
class Element;
|
||||||
@@ -101,6 +103,8 @@ class LinkSingleElementWidget : public AbstractElementPropertiesEditorWidget
|
|||||||
Element *m_showed_element = nullptr,
|
Element *m_showed_element = nullptr,
|
||||||
*m_element_to_link = nullptr;
|
*m_element_to_link = nullptr;
|
||||||
|
|
||||||
|
int m_pending_group_index = -1;
|
||||||
|
|
||||||
QMenu *m_context_menu{nullptr};
|
QMenu *m_context_menu{nullptr};
|
||||||
QAction *m_link_action{nullptr},
|
QAction *m_link_action{nullptr},
|
||||||
*m_show_qtwi{nullptr},
|
*m_show_qtwi{nullptr},
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
* along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "masterpropertieswidget.h"
|
#include "masterpropertieswidget.h"
|
||||||
|
#include "contactgroupselectiondialog.h"
|
||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
#include "../diagramposition.h"
|
#include "../diagramposition.h"
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MasterPropertiesWidget::MasterPropertiesWidget
|
* @brief MasterPropertiesWidget::MasterPropertiesWidget
|
||||||
* Default constructor
|
* Default constructor
|
||||||
@@ -176,6 +178,8 @@ void MasterPropertiesWidget::apply()
|
|||||||
{
|
{
|
||||||
if (QUndoCommand *undo = associatedUndo())
|
if (QUndoCommand *undo = associatedUndo())
|
||||||
m_element -> diagram() -> undoStack().push(undo);
|
m_element -> diagram() -> undoStack().push(undo);
|
||||||
|
|
||||||
|
m_pending_group_indices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,8 +228,23 @@ QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
|||||||
if (to_link.isEmpty())
|
if (to_link.isEmpty())
|
||||||
undo->unlinkAll();
|
undo->unlinkAll();
|
||||||
else
|
else
|
||||||
|
{
|
||||||
undo->setLink(to_link);
|
undo->setLink(to_link);
|
||||||
|
|
||||||
|
//Pass group indices for newly linked slaves
|
||||||
|
if (!m_pending_group_indices.isEmpty())
|
||||||
|
{
|
||||||
|
QMap<Element*, int> indices;
|
||||||
|
for (Element *slave : to_link)
|
||||||
|
{
|
||||||
|
if (m_pending_group_indices.contains(slave))
|
||||||
|
indices[slave] = m_pending_group_indices.value(slave);
|
||||||
|
}
|
||||||
|
if (!indices.isEmpty())
|
||||||
|
undo->setGroupIndices(indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return undo;
|
return undo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,6 +394,38 @@ void MasterPropertiesWidget::on_link_button_clicked()
|
|||||||
QTreeWidgetItem *qtwi = ui->m_free_tree_widget->currentItem();
|
QTreeWidgetItem *qtwi = ui->m_free_tree_widget->currentItem();
|
||||||
if (qtwi)
|
if (qtwi)
|
||||||
{
|
{
|
||||||
|
Element *slave_elmt = m_qtwi_hash.value(qtwi);
|
||||||
|
|
||||||
|
//If master has contact groups, show group selection dialog
|
||||||
|
const auto &groups = m_element->elementData().m_slave_contact_groups;
|
||||||
|
if (!groups.isEmpty() && slave_elmt)
|
||||||
|
{
|
||||||
|
// Collect already-used group indices from the master
|
||||||
|
QSet<int> used_indices;
|
||||||
|
for (Element *linked : m_element->linkedElements()) {
|
||||||
|
int idx = m_element->groupIndexForElement(linked);
|
||||||
|
if (idx >= 0) {
|
||||||
|
used_indices.insert(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't mark the current slave as used (it might be relinked)
|
||||||
|
if (slave_elmt->linkedElements().contains(m_element)) {
|
||||||
|
int current_idx = m_element->groupIndexForElement(slave_elmt);
|
||||||
|
if (current_idx >= 0) {
|
||||||
|
used_indices.remove(current_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactGroupSelectionDialog dlg(groups, used_indices,
|
||||||
|
slave_elmt->elementData(), this);
|
||||||
|
if (dlg.exec() == QDialog::Accepted && dlg.selectedIndex() >= 0) {
|
||||||
|
m_pending_group_indices[slave_elmt] = dlg.selectedIndex();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ui->m_free_tree_widget->takeTopLevelItem(
|
ui->m_free_tree_widget->takeTopLevelItem(
|
||||||
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
||||||
ui->m_link_tree_widget->insertTopLevelItem(0, qtwi);
|
ui->m_link_tree_widget->insertTopLevelItem(0, qtwi);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
#include "abstractelementpropertieseditorwidget.h"
|
#include "abstractelementpropertieseditorwidget.h"
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ class MasterPropertiesWidget : public AbstractElementPropertiesEditorWidget
|
|||||||
private:
|
private:
|
||||||
Ui::MasterPropertiesWidget *ui;
|
Ui::MasterPropertiesWidget *ui;
|
||||||
QHash <QTreeWidgetItem *, Element *> m_qtwi_hash;
|
QHash <QTreeWidgetItem *, Element *> m_qtwi_hash;
|
||||||
|
QMap <Element *, int> m_pending_group_indices;
|
||||||
QTreeWidgetItem *m_qtwi_at_context_menu = nullptr;
|
QTreeWidgetItem *m_qtwi_at_context_menu = nullptr;
|
||||||
QPointer <Element> m_showed_element;
|
QPointer <Element> m_showed_element;
|
||||||
QETProject *m_project;
|
QETProject *m_project;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
#include "../qetgraphicsitem/conductor.h"
|
#include "../qetgraphicsitem/conductor.h"
|
||||||
#include "../qetgraphicsitem/element.h"
|
#include "../qetgraphicsitem/element.h"
|
||||||
|
#include "../qetgraphicsitem/terminal.h"
|
||||||
#include "../ui/potentialselectordialog.h"
|
#include "../ui/potentialselectordialog.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,6 +177,54 @@ void LinkElementCommand::unlinkAll()
|
|||||||
void LinkElementCommand::undo()
|
void LinkElementCommand::undo()
|
||||||
{
|
{
|
||||||
if(m_element->diagram()) m_element->diagram()->showMe();
|
if(m_element->diagram()) m_element->diagram()->showMe();
|
||||||
|
|
||||||
|
//Clear group index for slave elements when undoing
|
||||||
|
if (m_element->linkType() == Element::Slave)
|
||||||
|
{
|
||||||
|
int group_idx = m_group_index;
|
||||||
|
if (m_group_indices.contains(m_element))
|
||||||
|
group_idx = m_group_indices.value(m_element);
|
||||||
|
|
||||||
|
if (group_idx >= 0)
|
||||||
|
{
|
||||||
|
// Reset master labels on slave terminals
|
||||||
|
QList<Terminal *> slave_terms = m_element->terminals();
|
||||||
|
for (Terminal *t : slave_terms)
|
||||||
|
{
|
||||||
|
t->setUseMasterLabel(false);
|
||||||
|
t->setMasterLabelIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(Element *elmt, m_element->linkedElements())
|
||||||
|
{
|
||||||
|
if (elmt->linkType() == Element::Master)
|
||||||
|
{
|
||||||
|
elmt->setGroupIndexForElement(m_element, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_element->linkType() == Element::Master)
|
||||||
|
{
|
||||||
|
for (auto it = m_group_indices.constBegin(); it != m_group_indices.constEnd(); ++it)
|
||||||
|
{
|
||||||
|
Element *slave = it.key();
|
||||||
|
if (m_element->linkedElements().contains(slave))
|
||||||
|
{
|
||||||
|
// Reset master labels on slave terminals
|
||||||
|
QList<Terminal *> slave_terms = slave->terminals();
|
||||||
|
for (Terminal *t : slave_terms)
|
||||||
|
{
|
||||||
|
t->setUseMasterLabel(false);
|
||||||
|
t->setMasterLabelIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_element->setGroupIndexForElement(slave, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
makeLink(m_linked_before);
|
makeLink(m_linked_before);
|
||||||
QUndoCommand::undo();
|
QUndoCommand::undo();
|
||||||
}
|
}
|
||||||
@@ -275,6 +324,83 @@ void LinkElementCommand::makeLink(const QList<Element *> &element_list)
|
|||||||
foreach(Element *elmt, element_list)
|
foreach(Element *elmt, element_list)
|
||||||
m_element->linkToElement(elmt);
|
m_element->linkToElement(elmt);
|
||||||
|
|
||||||
|
//Set group index for slave-master links
|
||||||
|
if (m_element->linkType() == Element::Slave)
|
||||||
|
{
|
||||||
|
int group_idx = m_group_index;
|
||||||
|
|
||||||
|
//Check if we have a per-slave group index
|
||||||
|
if (m_group_indices.contains(m_element))
|
||||||
|
group_idx = m_group_indices.value(m_element);
|
||||||
|
|
||||||
|
if (group_idx >= 0)
|
||||||
|
{
|
||||||
|
foreach(Element *elmt, element_list)
|
||||||
|
{
|
||||||
|
if (elmt->linkType() == Element::Master)
|
||||||
|
{
|
||||||
|
elmt->setGroupIndexForElement(m_element, group_idx);
|
||||||
|
|
||||||
|
// Set master labels on slave terminals
|
||||||
|
const auto &groups = elmt->elementData().m_slave_contact_groups;
|
||||||
|
if (group_idx < groups.size())
|
||||||
|
{
|
||||||
|
const QStringList &labels = groups.at(group_idx).labels;
|
||||||
|
QList<Terminal *> slave_terms = m_element->terminals();
|
||||||
|
// Sort terminals by name (T1, T2, T3...) to match label order
|
||||||
|
std::sort(slave_terms.begin(), slave_terms.end(),
|
||||||
|
[](Terminal *a, Terminal *b) {
|
||||||
|
return a->name() < b->name();
|
||||||
|
});
|
||||||
|
for (int i = 0; i < slave_terms.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i < labels.size())
|
||||||
|
{
|
||||||
|
slave_terms.at(i)->setUseMasterLabel(true);
|
||||||
|
slave_terms.at(i)->setMasterLabelIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_element->linkType() == Element::Master)
|
||||||
|
{
|
||||||
|
//For master linking to slaves, set group indices for each slave
|
||||||
|
for (auto it = m_group_indices.constBegin(); it != m_group_indices.constEnd(); ++it)
|
||||||
|
{
|
||||||
|
Element *slave = it.key();
|
||||||
|
int group_idx = it.value();
|
||||||
|
if (group_idx >= 0 && element_list.contains(slave))
|
||||||
|
{
|
||||||
|
m_element->setGroupIndexForElement(slave, group_idx);
|
||||||
|
|
||||||
|
// Set master labels on slave terminals
|
||||||
|
const auto &groups = m_element->elementData().m_slave_contact_groups;
|
||||||
|
if (group_idx < groups.size())
|
||||||
|
{
|
||||||
|
const QStringList &labels = groups.at(group_idx).labels;
|
||||||
|
QList<Terminal *> slave_terms = slave->terminals();
|
||||||
|
// Sort terminals by name (T1, T2, T3...) to match label order
|
||||||
|
std::sort(slave_terms.begin(), slave_terms.end(),
|
||||||
|
[](Terminal *a, Terminal *b) {
|
||||||
|
return a->name() < b->name();
|
||||||
|
});
|
||||||
|
for (int i = 0; i < slave_terms.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i < labels.size())
|
||||||
|
{
|
||||||
|
slave_terms.at(i)->setUseMasterLabel(true);
|
||||||
|
slave_terms.at(i)->setMasterLabelIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* At this point there may be unwanted linked elements to m_element.
|
/* At this point there may be unwanted linked elements to m_element.
|
||||||
* We must unlink it.
|
* We must unlink it.
|
||||||
* Elements from element_list are wanted so we compare element_list
|
* Elements from element_list are wanted so we compare element_list
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define LINKELEMENTCOMMAND_H
|
#define LINKELEMENTCOMMAND_H
|
||||||
|
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
class Element;
|
class Element;
|
||||||
|
|
||||||
@@ -42,6 +43,8 @@ class LinkElementCommand : public QUndoCommand
|
|||||||
void setLink (Element *element_);
|
void setLink (Element *element_);
|
||||||
void unlink (QList<Element *> element_list);
|
void unlink (QList<Element *> element_list);
|
||||||
void unlinkAll ();
|
void unlinkAll ();
|
||||||
|
void setGroupIndex(int index) { m_group_index = index; }
|
||||||
|
void setGroupIndices(const QMap<Element*, int> &indices) { m_group_indices = indices; }
|
||||||
|
|
||||||
void undo() override;
|
void undo() override;
|
||||||
void redo() override;
|
void redo() override;
|
||||||
@@ -53,6 +56,8 @@ class LinkElementCommand : public QUndoCommand
|
|||||||
private:
|
private:
|
||||||
Element *m_element;
|
Element *m_element;
|
||||||
bool m_first_redo;
|
bool m_first_redo;
|
||||||
|
int m_group_index = -1;
|
||||||
|
QMap<Element*, int> m_group_indices;
|
||||||
QList<Element *> m_linked_before; //<Linked elements before this command, or when we call "undo"
|
QList<Element *> m_linked_before; //<Linked elements before this command, or when we call "undo"
|
||||||
QList<Element *> m_linked_after; //<Linked elements after this command, or when we recall "redo"
|
QList<Element *> m_linked_after; //<Linked elements after this command, or when we recall "redo"
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user