diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index cabd1ee3b..cdfa8bd8d 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -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 diff --git a/sources/TerminalStrip/terminalcatalog.h b/sources/TerminalStrip/terminalcatalog.h new file mode 100644 index 000000000..5c48939b7 --- /dev/null +++ b/sources/TerminalStrip/terminalcatalog.h @@ -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 . +*/ +#ifndef TERMINALCATALOG_H +#define TERMINALCATALOG_H + +#include + +/** + * @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 §ions() + { + static const QVector 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 &widthEntries() + { + static const QVector 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 diff --git a/sources/TerminalStrip/ui/terminalstripmodel.cpp b/sources/TerminalStrip/ui/terminalstripmodel.cpp index 165944fa9..0cf0f3d04 100644 --- a/sources/TerminalStrip/ui/terminalstripmodel.cpp +++ b/sources/TerminalStrip/ui/terminalstripmodel.cpp @@ -16,6 +16,7 @@ along with QElectroTech. If not, see . */ #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 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(), §ion_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); } } diff --git a/sources/editor/ui/elementpropertieseditorwidget.cpp b/sources/editor/ui/elementpropertieseditorwidget.cpp index fad80adf4..d06823b9b 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.cpp +++ b/sources/editor/ui/elementpropertieseditorwidget.cpp @@ -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 #include #include +#include #include +#include +#include #include #include #include @@ -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::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()) diff --git a/sources/editor/ui/elementpropertieseditorwidget.h b/sources/editor/ui/elementpropertieseditorwidget.h index e58cdd1b8..7565f880d 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.h +++ b/sources/editor/ui/elementpropertieseditorwidget.h @@ -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: diff --git a/sources/editor/ui/elementpropertieseditorwidget.ui b/sources/editor/ui/elementpropertieseditorwidget.ui index 138cd9dfa..9eb8754e4 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.ui +++ b/sources/editor/ui/elementpropertieseditorwidget.ui @@ -259,6 +259,57 @@ + + + + Section (mm²) + + + + + + + true + + + QComboBox::NoInsert + + + + + + + Width / manufacturer + + + + + + + true + + + QComboBox::NoInsert + + + + + + + Color + + + + + + + true + + + QComboBox::NoInsert + + +