Improve terminal_strip

This commit is contained in:
Laurent Trinques
2026-10-15 14:38:11 +02:00
parent 892a899a20
commit e883d2c3bf
11 changed files with 708 additions and 9 deletions
+261 -3
View File
@@ -20,8 +20,12 @@
#include "../../qetgraphicsitem/element.h"
#include "../physicalterminal.h"
#include "../realterminal.h"
#include "../terminalcolor.h"
#include "../terminalstripbridge.h"
#include <QColor>
#include <QCoreApplication>
#include <QDebug>
#include <QLocale>
#include <QBrush>
#include <QVector>
#include <QComboBox>
@@ -47,10 +51,37 @@ const int TYPE_CELL = 11;
const int FUNCTION_CELL = 12;
const int LED_CELL = 13;
const int SHIELD_CELL = 14;
const int COLOR_CELL = 15;
const int SECTION_CELL = 16;
const int WIDTH_CELL = 17;
const int COLUMN_COUNT = 15;
const int COLUMN_COUNT = 18;
static QVector<bool> UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
static QVector<bool> UNMODIFIED_CELL_VECTOR(COLUMN_COUNT, false);
/**
* @brief parsePositiveNumber
* Convert the text written by the user to a number >= 0
* (a section in mm2 or a width in mm).
* The comma and the dot are both accepted as decimal separator.
* @param text
* @param ok : true if the text is valid (empty text is valid and mean 0)
* @return
*/
static qreal parsePositiveNumber(const QString &text, bool *ok)
{
auto text_ = text.trimmed();
text_.replace(QLatin1Char(','), QLatin1Char('.'));
if (text_.isEmpty()) {
*ok = true;
return 0;
}
const auto value_ = text_.toDouble(ok);
if (*ok && value_ < 0) {
*ok = false;
}
return *ok ? value_ : 0;
}
/**
* @brief TerminalStripModel::levelForColumn
@@ -95,6 +126,9 @@ TerminalStripModel::Column TerminalStripModel::columnTypeForIndex(const QModelIn
case 12 : return Function;
case 13 : return Led;
case 14 : return Shield;
case 15 : return Color;
case 16 : return Section;
case 17 : return Width;
default : return Invalid;
}
}
@@ -172,6 +206,9 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
case CABLE_WIRE_CELL : return mrtd.cable_wire;
case TYPE_CELL : return ElementData::translatedTerminalType(mrtd.type_);
case FUNCTION_CELL : return ElementData::translatedTerminalFunction(mrtd.function_);
case COLOR_CELL : return TerminalColor::displayName(mrtd.color_, mrtd.stripe_color_);
case SECTION_CELL : return mrtd.section_ > 0 ? QLocale().toString(mrtd.section_, 'g', 6) : QString();
case WIDTH_CELL : return mrtd.width_mm_ > 0 ? QLocale().toString(mrtd.width_mm_, 'g', 6) : QString();
default : return QVariant();
}
}
@@ -181,6 +218,9 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
case LABEL_CELL : return mrtd.label_;
case CABLE_CELL : return mrtd.cable_;
case CABLE_WIRE_CELL : return mrtd.cable_wire;
case COLOR_CELL : return TerminalColor::toSpec(mrtd.color_, mrtd.stripe_color_);
case SECTION_CELL : return mrtd.section_ > 0 ? QLocale().toString(mrtd.section_, 'g', 6) : QString();
case WIDTH_CELL : return mrtd.width_mm_ > 0 ? QLocale().toString(mrtd.width_mm_, 'g', 6) : QString();
default: return QVariant();
}
@@ -203,6 +243,13 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
return QBrush(Qt::yellow);
}
}
else if (role == Qt::DecorationRole &&
index.column() == COLOR_CELL)
{
if (mrtd.color_.isValid()) {
return TerminalColor::swatch(mrtd.color_, mrtd.stripe_color_);
}
}
else if (role == Qt::DecorationRole &&
(index.column() == LEVEL_0_CELL ||
index.column() == LEVEL_1_CELL ||
@@ -279,6 +326,46 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value
modified_ = true;
modified_cell = SHIELD_CELL;
}
else if (column_ == COLOR_CELL &&
role == Qt::EditRole)
{
//An empty text remove the color, an unknown text is ignored.
//The text can be a name of the palette (gray, blue, green/yellow...),
//or a color "#rrggbb" or "#rrggbb/#rrggbb"
QColor color_, stripe_;
if (TerminalColor::parse(value.toString(), &color_, &stripe_) &&
(mrtd.color_ != color_ || mrtd.stripe_color_ != stripe_))
{
mrtd.color_ = color_;
mrtd.stripe_color_ = stripe_;
modified_ = true;
modified_cell = COLOR_CELL;
}
}
else if (column_ == SECTION_CELL &&
role == Qt::EditRole)
{
bool ok_ = false;
const auto section_ = parsePositiveNumber(value.toString(), &ok_);
if (ok_ && !qFuzzyCompare(1 + mrtd.section_, 1 + section_))
{
mrtd.section_ = section_;
modified_ = true;
modified_cell = SECTION_CELL;
}
}
else if (column_ == WIDTH_CELL &&
role == Qt::EditRole)
{
bool ok_ = false;
const auto width_ = parsePositiveNumber(value.toString(), &ok_);
if (ok_ && !qFuzzyCompare(1 + mrtd.width_mm_, 1 + width_))
{
mrtd.width_mm_ = width_;
modified_ = true;
modified_cell = WIDTH_CELL;
}
}
//Set the modification to the terminal data
if (modified_)
@@ -326,6 +413,9 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
case FUNCTION_CELL : return tr("Function");
case LED_CELL: return tr("led");
case SHIELD_CELL: return tr("Shield");
case COLOR_CELL: return tr("Color");
case SECTION_CELL: return tr("Section (mm²)");
case WIDTH_CELL: return tr("Width (mm)");
default : return QVariant();
}
}
@@ -340,7 +430,8 @@ Qt::ItemFlags TerminalStripModel::flags(const QModelIndex &index) const
auto c = index.column();
if (c == LABEL_CELL || c == TYPE_CELL || c == FUNCTION_CELL
|| c == CABLE_CELL || c == CABLE_WIRE_CELL)
|| c == CABLE_CELL || c == CABLE_WIRE_CELL
|| c == COLOR_CELL || c == SECTION_CELL || c == WIDTH_CELL)
flags = flags | Qt::ItemIsEditable;
if (c == LED_CELL || c == SHIELD_CELL) {
flags = flags | Qt::ItemIsUserCheckable;
@@ -819,6 +910,40 @@ QPixmap TerminalStripModel::bridgePixmapFor(const QModelIndex &index) const
* and a spinbox to edit the level of a terminal
**********************************************************/
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; };
const WidthEntry WIDTH_ENTRIES[] {
{5.1, "Weidmüller WDU 2.5"},
{5.2, "WAGO 2002 (TOPJOB S)"},
{6.0, "ABB Entrelec M 4/6"},
{6.1, "Weidmüller WDU 4"},
{6.2, "Phoenix Contact UT 4"},
{8.0, "ABB Entrelec M 6/8, M 4/8"},
{8.2, "Phoenix Contact UT 6"},
{10.0, "ABB Entrelec M 10/10"},
{10.2, "Phoenix Contact UT 10"},
{11.9, "Weidmüller WDU 16/ZA"},
{12.2, "Phoenix Contact UT 16"},
{16.0, "Phoenix Contact UT 35, Weidmüller WDU 35N"},
{26.0, "ABB Entrelec M 35/26.FF"},
{31.0, "ABB Entrelec M 70/31.AF"},
{35.0, "ABB Entrelec M 120/35.F"},
{42.0, "ABB Entrelec M 300/42.FF"}
};
QString widthItemText(double mm, const QString &label = QString())
{
const auto text_ = QCoreApplication::translate("TerminalStripModelDelegate", "%1 mm").arg(QLocale().toString(mm, 'g', 6));
return label.isEmpty() ? text_ : text_ + QStringLiteral(" - ") + label;
}
}
TerminalStripModelDelegate::TerminalStripModelDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{}
@@ -850,10 +975,125 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
return qcb;
}
if (index.column() == SECTION_CELL) {
auto qcb = new QComboBox(parent);
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};
for (const auto section_ : sections_) {
qcb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
}
return qcb;
}
if (index.column() == WIDTH_CELL) {
auto qcb = new QComboBox(parent);
qcb->setObjectName(QStringLiteral("terminal_width"));
qcb->addItem(tr("None (default)"), 0.0);
for (const auto &entry : WIDTH_ENTRIES) {
qcb->addItem(widthItemText(entry.mm, QString::fromUtf8(entry.label)), entry.mm);
}
return qcb;
}
if (index.column() == COLOR_CELL) {
auto qcb = new QComboBox(parent);
qcb->setObjectName(QStringLiteral("terminal_color"));
qcb->addItem(tr("None (default)"), QString());
for (const auto &entry : TerminalColor::palette())
{
const auto spec_ = TerminalColor::specOf(entry);
QColor main_, stripe_;
TerminalColor::parse(spec_, &main_, &stripe_);
qcb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)),
TerminalColor::translatedName(entry),
spec_);
}
return qcb;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
void TerminalStripModelDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if (index.isValid() &&
editor->objectName() == QLatin1String("terminal_color"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor))
{
const auto spec_ = index.data(Qt::EditRole).toString();
auto pos_ = qcb->findData(spec_);
if (pos_ < 0)
{
//The color is not in the palette (typed or pasted), keep it in the list
QColor main_, stripe_;
TerminalColor::parse(spec_, &main_, &stripe_);
qcb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)), spec_, spec_);
pos_ = qcb->count() - 1;
}
qcb->setCurrentIndex(pos_);
}
return;
}
if (index.isValid() &&
editor->objectName() == QLatin1String("terminal_section"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor))
{
bool ok_ = false;
const auto section_ = parsePositiveNumber(index.data(Qt::EditRole).toString(), &ok_);
auto pos_ = -1;
for (auto i = 0 ; i < qcb->count() ; ++i)
{
if (qFuzzyCompare(1 + qcb->itemData(i).toDouble(), 1 + section_)) {
pos_ = i;
break;
}
}
if (pos_ < 0)
{
//The section is not in the list (typed or pasted), keep it in the list
qcb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
pos_ = qcb->count() - 1;
}
qcb->setCurrentIndex(pos_);
}
return;
}
if (index.isValid() &&
editor->objectName() == QLatin1String("terminal_width"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor))
{
bool ok_ = false;
const auto width_ = parsePositiveNumber(index.data(Qt::EditRole).toString(), &ok_);
auto pos_ = -1;
for (auto i = 0 ; i < qcb->count() ; ++i)
{
if (qFuzzyCompare(1 + qcb->itemData(i).toDouble(), 1 + width_)) {
pos_ = i;
break;
}
}
if (pos_ < 0)
{
//The width is not in the list (typed or pasted), keep it in the list
qcb->addItem(widthItemText(width_), width_);
pos_ = qcb->count() - 1;
}
qcb->setCurrentIndex(pos_);
}
return;
}
QStyledItemDelegate::setEditorData(editor, index);
}
void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.isValid())
@@ -870,6 +1110,24 @@ void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemMode
model->setData(index, qcb->currentData(), Qt::EditRole);
}
}
else if (editor->objectName() == QLatin1String("terminal_section"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
model->setData(index, qcb->currentData().toDouble(), Qt::EditRole);
}
}
else if (editor->objectName() == QLatin1String("terminal_width"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
model->setData(index, qcb->currentData().toDouble(), Qt::EditRole);
}
}
else if (editor->objectName() == QLatin1String("terminal_color"))
{
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
model->setData(index, qcb->currentData(), Qt::EditRole);
}
}
else {
QStyledItemDelegate::setModelData(editor, model, index);
}