Element editor: add section, width and color to terminal elements

Terminal block elements can now define, in the element properties
dialog (Terminal block element group):
- the section in mm2 (combo box with the usual sections, editable)
- the width / manufacturer reference (Weidmuller, Phoenix Contact,
  WAGO, ABB Entrelec), filtered by the selected section
- the color, using the palette of the terminal strip (editable,
  accepts a name, #rrggbb or #rrggbb/#rrggbb)

Values are stored in the element informations (terminal_section,
terminal_width, terminal_color) with the dot as decimal separator,
the keys already read by RealTerminal. An empty value removes the key.

The sections and the manufacturer widths move from
terminalstripmodel.cpp to the new header-only terminalcatalog.h,
shared by the terminal strip editor and the element editor.
This commit is contained in:
Laurent Trinques
2026-10-16 07:50:34 +02:00
parent cc9fe1a5c8
commit 5cbc1c4b8d
6 changed files with 314 additions and 32 deletions
+1
View File
@@ -711,6 +711,7 @@ set(QET_SRC_FILES
${QET_DIR}/sources/TerminalStrip/physicalterminal.h
${QET_DIR}/sources/TerminalStrip/realterminal.cpp
${QET_DIR}/sources/TerminalStrip/realterminal.h
${QET_DIR}/sources/TerminalStrip/terminalcatalog.h
${QET_DIR}/sources/TerminalStrip/terminalstripbridge.cpp
${QET_DIR}/sources/TerminalStrip/terminalstripbridge.h
${QET_DIR}/sources/TerminalStrip/terminalstrip.cpp
+70
View File
@@ -0,0 +1,70 @@
/*
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 TERMINALCATALOG_H
#define TERMINALCATALOG_H
#include <QVector>
/**
* @brief The TerminalCatalog namespace
* Data shared between the terminal strip editor and the element editor :
* usual sections (mm2) and widths (mm) of the terminals sold by the manufacturers.
* Only the values found in the catalogs of the manufacturers are listed,
* any other value can be typed by the user.
*/
namespace TerminalCatalog
{
/**
* Width (mm) of a terminal sold by a manufacturer.
* For ABB Entrelec the value is the spacing (pitch) given by the catalog.
*/
struct WidthEntry { double mm; const char *label; double section; };
inline const QVector<double> &sections()
{
static const QVector<double> sections_ {0.5, 0.75, 1, 1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240, 300};
return sections_;
}
inline const QVector<WidthEntry> &widthEntries()
{
static const QVector<WidthEntry> entries_ {
{5.1, "Weidmüller WDU 2.5", 2.5},
{5.2, "WAGO 2002 (TOPJOB S)", 2.5},
{6.0, "ABB Entrelec M 4/6", 4.0},
{6.1, "Weidmüller WDU 4", 4.0},
{6.2, "Phoenix Contact UT 4", 4.0},
{8.0, "ABB Entrelec M 6/8", 6.0},
{8.0, "ABB Entrelec M 4/8", 4.0},
{8.2, "Phoenix Contact UT 6", 6.0},
{10.0, "ABB Entrelec M 10/10", 10.0},
{10.2, "Phoenix Contact UT 10", 10.0},
{11.9, "Weidmüller WDU 16/ZA", 16.0},
{12.2, "Phoenix Contact UT 16", 16.0},
{16.0, "Phoenix Contact UT 35", 35.0},
{16.0, "Weidmüller WDU 35N", 35.0},
{26.0, "ABB Entrelec M 35/26.FF", 35.0},
{31.0, "ABB Entrelec M 70/31.AF", 70.0},
{35.0, "ABB Entrelec M 120/35.F", 120.0},
{42.0, "ABB Entrelec M 300/42.FF", 300.0}
};
return entries_;
}
}
#endif // TERMINALCATALOG_H
@@ -16,6 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "terminalstripmodel.h"
#include "../terminalcatalog.h"
#include "../terminalstrip.h"
#include "../../qetgraphicsitem/element.h"
#include "../physicalterminal.h"
@@ -911,34 +912,6 @@ QPixmap TerminalStripModel::bridgePixmapFor(const QModelIndex &index) const
**********************************************************/
namespace {
/**
* Widths (mm) of terminals sold by the manufacturers.
* Only the values found in the catalogs of the manufacturers are listed,
* any other width can be typed in the cell.
* For ABB Entrelec the value is the spacing (pitch) given by the catalog.
*/
struct WidthEntry { double mm; const char *label; double section; };
const WidthEntry WIDTH_ENTRIES[] {
{5.1, "Weidmüller WDU 2.5", 2.5},
{5.2, "WAGO 2002 (TOPJOB S)", 2.5},
{6.0, "ABB Entrelec M 4/6", 4.0},
{6.1, "Weidmüller WDU 4", 4.0},
{6.2, "Phoenix Contact UT 4", 4.0},
{8.0, "ABB Entrelec M 6/8", 6.0},
{8.0, "ABB Entrelec M 4/8", 4.0},
{8.2, "Phoenix Contact UT 6", 6.0},
{10.0, "ABB Entrelec M 10/10", 10.0},
{10.2, "Phoenix Contact UT 10", 10.0},
{11.9, "Weidmüller WDU 16/ZA", 16.0},
{12.2, "Phoenix Contact UT 16", 16.0},
{16.0, "Phoenix Contact UT 35", 35.0},
{16.0, "Weidmüller WDU 35N", 35.0},
{26.0, "ABB Entrelec M 35/26.FF", 35.0},
{31.0, "ABB Entrelec M 70/31.AF", 70.0},
{35.0, "ABB Entrelec M 120/35.F", 120.0},
{42.0, "ABB Entrelec M 300/42.FF", 300.0}
};
QString widthItemText(double mm, const QString &label = QString())
{
const auto text_ = QCoreApplication::translate("TerminalStripModelDelegate", "%1 mm").arg(QLocale().toString(mm, 'g', 6));
@@ -982,8 +955,7 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
qcb->setObjectName(QStringLiteral("terminal_section"));
qcb->addItem(tr("None (default)"), 0.0);
//Usual sections, in mm2
static const QVector<double> sections_ {0.5, 0.75, 1, 1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240, 300};
for (const auto section_ : sections_) {
for (const auto section_ : TerminalCatalog::sections()) {
qcb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
}
@@ -1000,7 +972,7 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
const auto section = parsePositiveNumber(section_index.data(Qt::EditRole).toString(), &section_ok);
bool has_compatible_entry = false;
if (section_ok && section > 0.0) {
for (const auto &entry : WIDTH_ENTRIES) {
for (const auto &entry : TerminalCatalog::widthEntries()) {
if (qFuzzyCompare(1 + entry.section, 1 + section)) {
qcb->addItem(widthItemText(entry.mm, QString::fromUtf8(entry.label)), entry.mm);
has_compatible_entry = true;
@@ -1009,7 +981,7 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
}
// If the section has no catalog match (or is unspecified), keep all widths available.
if (!has_compatible_entry) {
for (const auto &entry : WIDTH_ENTRIES) {
for (const auto &entry : TerminalCatalog::widthEntries()) {
qcb->addItem(widthItemText(entry.mm, QString::fromUtf8(entry.label)), entry.mm);
}
}
@@ -20,6 +20,9 @@
#include "../../qet.h"
#include "../../qetapp.h"
#include "../../qetinformation.h"
#include "../../TerminalStrip/terminalcatalog.h"
#include "../../TerminalStrip/terminalcolor.h"
#include "../../TerminalStrip/realterminal.h"
#include "ui_elementpropertieseditorwidget.h"
#include "../../qet.h"
@@ -36,7 +39,10 @@
#include <QGroupBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLocale>
#include <QRegularExpression>
#include <QPushButton>
#include <QClipboard>
#include <QApplication>
@@ -71,6 +77,61 @@ QWidget* EditorDelegate::createEditor(QWidget *parent,
return nullptr;
}
namespace {
/**
* @brief leadingNumber
* Extract the first number of a text like "2,5 mm²" or "5.1 mm - WAGO".
* The comma and the dot are both accepted as decimal separator.
* @return the number, or 0 if the text is empty or has no number.
*/
double leadingNumber(const QString &text)
{
static const QRegularExpression re(QStringLiteral("(\\d+(?:[.,]\\d+)?)"));
const auto match = re.match(text);
if (!match.hasMatch())
return 0;
auto number = match.captured(1);
number.replace(QLatin1Char(','), QLatin1Char('.'));
return number.toDouble();
}
/// Value of a terminal size combo (picked in the list or typed).
double comboValue(const QComboBox *cb)
{
return leadingNumber(cb->currentText());
}
/// Color of a terminal combo as "#rrggbb" or "#rrggbb/#rrggbb" (empty = none).
/// A text which is not understood keeps the value the combo was loaded with.
QString colorSpec(const QComboBox *cb)
{
const auto index = cb->findText(cb->currentText());
if (index >= 0)
return cb->itemData(index).toString();
QColor main_, stripe_;
if (TerminalColor::parse(cb->currentText(), &main_, &stripe_))
return TerminalColor::toSpec(main_, stripe_);
return cb->property("origSpec").toString();
}
/// Set the text of an editable combo : select the item with this value or write the value.
void setComboValue(QComboBox *cb, double value, const QString &suffix)
{
if (value <= 0) {
cb->setCurrentIndex(0);
return;
}
for (int i = 1; i < cb->count(); ++i) {
if (qFuzzyCompare(1 + cb->itemData(i).toDouble(), 1 + value)) {
cb->setCurrentIndex(i);
return;
}
}
cb->setCurrentText(QLocale().toString(value, 'g', 6) + suffix);
}
}
/**
* @brief ElementPropertiesEditorWidget::ElementPropertiesEditorWidget
* @param data
@@ -177,6 +238,12 @@ void ElementPropertiesEditorWidget::upDateInterface()
QET::infoFlagIsTrue(info.value(QStringLiteral("auto_num_locked")).toString()));
ui->m_potential_isolating_cb->setChecked(
QET::infoFlagIsTrue(info.value(QStringLiteral("potential_isolating")).toString()));
//Section (mm2) and width (mm), stored with the dot as decimal separator
populateTerminalSizeCombos(
info.value(RealTerminal::sectionInfoKey()).toString().toDouble(),
info.value(RealTerminal::widthInfoKey()).toString().toDouble());
populateTerminalColorCombo(info.value(RealTerminal::colorInfoKey()).toString());
}
ui->m_exclude_from_bom_cb->setChecked(
@@ -361,6 +428,105 @@ void ElementPropertiesEditorWidget::populateTree()
}
}
/**
@brief ElementPropertiesEditorWidget::populateTerminalSizeCombos
Fill the section and width combo boxes of the terminal group box
and select @a section (mm2) and @a width (mm), 0 means "none".
The combo boxes are editable : a value not in the list can be typed.
*/
void ElementPropertiesEditorWidget::populateTerminalSizeCombos(double section, double width)
{
QSignalBlocker blocker(ui->m_terminal_section_cb);
ui->m_terminal_section_cb->clear();
ui->m_terminal_section_cb->addItem(tr("None (default)"), 0.0);
for (const auto section_ : TerminalCatalog::sections()) {
ui->m_terminal_section_cb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
}
setComboValue(ui->m_terminal_section_cb, section, tr(" mm²"));
connect(ui->m_terminal_section_cb, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this]() { refreshTerminalWidthCombo(); });
connect(ui->m_terminal_section_cb->lineEdit(), &QLineEdit::editingFinished,
this, [this]() { refreshTerminalWidthCombo(); });
refreshTerminalWidthCombo();
setComboValue(ui->m_terminal_width_cb, width, tr(" mm"));
}
/**
@brief ElementPropertiesEditorWidget::populateTerminalColorCombo
Fill the color combo box with the palette of the terminal strip
and select @a spec ("#rrggbb" or "#rrggbb/#rrggbb", empty = none).
The combo box is editable : a color can be typed as a name or as "#rrggbb".
*/
void ElementPropertiesEditorWidget::populateTerminalColorCombo(const QString &spec)
{
auto *cb = ui->m_terminal_color_cb;
cb->setProperty("origSpec", spec);
cb->clear();
cb->addItem(tr("None (default)"), QString());
for (const auto &entry : TerminalColor::palette())
{
QColor main_, stripe_;
TerminalColor::parse(TerminalColor::specOf(entry), &main_, &stripe_);
cb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)),
TerminalColor::translatedName(entry),
TerminalColor::specOf(entry));
}
if (spec.isEmpty()) {
cb->setCurrentIndex(0);
return;
}
const auto index = cb->findData(spec);
if (index >= 0) {
cb->setCurrentIndex(index);
} else {
//The color is not in the palette, keep it in the list
QColor main_, stripe_;
TerminalColor::parse(spec, &main_, &stripe_);
cb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)), spec, spec);
cb->setCurrentIndex(cb->count() - 1);
}
}
/**
@brief ElementPropertiesEditorWidget::refreshTerminalWidthCombo
List the manufacturer terminals compatible with the selected section.
If the section has no match in the catalog (or is not set),
all the widths are listed. The current width is kept.
*/
void ElementPropertiesEditorWidget::refreshTerminalWidthCombo()
{
const auto current_width = comboValue(ui->m_terminal_width_cb);
const auto section = comboValue(ui->m_terminal_section_cb);
auto item_text = [](const TerminalCatalog::WidthEntry &entry) {
return tr("%1 mm").arg(QLocale().toString(entry.mm, 'g', 6))
+ QStringLiteral(" - ") + QString::fromUtf8(entry.label);
};
bool has_compatible_entry = false;
if (section > 0) {
for (const auto &entry : TerminalCatalog::widthEntries()) {
if (qFuzzyCompare(1 + entry.section, 1 + section)) {
has_compatible_entry = true;
break;
}
}
}
QSignalBlocker blocker(ui->m_terminal_width_cb);
ui->m_terminal_width_cb->clear();
ui->m_terminal_width_cb->addItem(tr("None (default)"), 0.0);
for (const auto &entry : TerminalCatalog::widthEntries()) {
if (!has_compatible_entry || qFuzzyCompare(1 + entry.section, 1 + section)) {
ui->m_terminal_width_cb->addItem(item_text(entry), entry.mm);
}
}
setComboValue(ui->m_terminal_width_cb, current_width, tr(" mm"));
}
/**
@brief ElementPropertiesEditorWidget::on_m_buttonBox_accepted
Action on button accepted : the new information is set
@@ -424,6 +590,25 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
m_data.m_informations.addValue(QStringLiteral("potential_isolating"), QStringLiteral("true"));
else
m_data.m_informations.remove(QStringLiteral("potential_isolating"));
//Section and width : stored with the dot as decimal separator, whatever the locale
const auto section_ = comboValue(ui->m_terminal_section_cb);
if (section_ > 0)
m_data.m_informations.addValue(RealTerminal::sectionInfoKey(), QString::number(section_, 'g', 6));
else
m_data.m_informations.remove(RealTerminal::sectionInfoKey());
const auto width_ = comboValue(ui->m_terminal_width_cb);
if (width_ > 0)
m_data.m_informations.addValue(RealTerminal::widthInfoKey(), QString::number(width_, 'g', 6));
else
m_data.m_informations.remove(RealTerminal::widthInfoKey());
const auto color_ = colorSpec(ui->m_terminal_color_cb);
if (!color_.isEmpty())
m_data.m_informations.addValue(RealTerminal::colorInfoKey(), color_);
else
m_data.m_informations.remove(RealTerminal::colorInfoKey());
}
if (ui->m_exclude_from_bom_cb->isChecked())
@@ -81,6 +81,9 @@ class ElementPropertiesEditorWidget : public QDialog
void createPlcConfigWidgets();
void populatePlcTable();
void readPlcTable();
void populateTerminalSizeCombos(double section, double width);
void refreshTerminalWidthCombo();
void populateTerminalColorCombo(const QString &spec);
//SLOTS
private slots:
@@ -259,6 +259,57 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_terminal_section">
<property name="text">
<string>Section (mm²)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="m_terminal_section_cb">
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_terminal_width">
<property name="text">
<string>Width / manufacturer</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="m_terminal_width_cb">
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_terminal_color">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="m_terminal_color_cb">
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>