From eb8f85903877c203b39d35c35788acd8726bea93 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Thu, 9 Apr 2026 08:36:54 +0200 Subject: [PATCH] Terminal numbering --- cmake/qet_compilation_vars.cmake | 3 + sources/qetdiagrameditor.cpp | 31 ++++- sources/qetdiagrameditor.h | 3 + sources/ui/elementinfowidget.cpp | 17 +++ sources/ui/elementinfowidget.ui | 13 ++ sources/ui/terminalnumberingdialog.cpp | 178 +++++++++++++++++++++++++ sources/ui/terminalnumberingdialog.h | 35 +++++ sources/ui/terminalnumberingdialog.ui | 139 +++++++++++++++++++ 8 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 sources/ui/terminalnumberingdialog.cpp create mode 100644 sources/ui/terminalnumberingdialog.h create mode 100644 sources/ui/terminalnumberingdialog.ui diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index f93ffe1ff..859033cc6 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -88,6 +88,7 @@ set(QET_RES_FILES ${QET_DIR}/sources/ui/dynamicelementtextitemeditor.ui ${QET_DIR}/sources/ui/elementinfopartwidget.ui ${QET_DIR}/sources/ui/elementinfowidget.ui + ${QET_DIR}/sources/ui/terminalnumberingdialog.ui ${QET_DIR}/sources/ui/formulaassistantdialog.ui ${QET_DIR}/sources/ui/imagepropertieswidget.ui ${QET_DIR}/sources/ui/importelementdialog.ui @@ -632,6 +633,8 @@ set(QET_SRC_FILES ${QET_DIR}/sources/ui/elementinfopartwidget.h ${QET_DIR}/sources/ui/elementinfowidget.cpp ${QET_DIR}/sources/ui/elementinfowidget.h + ${QET_DIR}/sources/ui/terminalnumberingdialog.cpp + ${QET_DIR}/sources/ui/terminalnumberingdialog.h ${QET_DIR}/sources/ui/elementpropertieswidget.cpp ${QET_DIR}/sources/ui/elementpropertieswidget.h ${QET_DIR}/sources/ui/formulaassistantdialog.cpp diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 7785411f1..398b15014 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -46,6 +46,7 @@ #include "ui/diagrameditorhandlersizewidget.h" #include "TerminalStrip/ui/addterminalstripitemdialog.h" #include "wiringlistexport.h" +#include "ui/terminalnumberingdialog.h" #ifdef BUILD_WITHOUT_KF5 #else @@ -477,6 +478,10 @@ void QETDiagramEditor::setUpActions() } }); + // Terminal Numbering + m_terminal_numbering = new QAction(QET::Icons::TerminalStrip, tr("Numérotation automatique des bornes"), this); + connect(m_terminal_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_terminalNumbering); + #ifdef QET_EXPORT_PROJECT_DB m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this); connect(m_export_project_db, &QAction::triggered, [this]() { @@ -847,6 +852,7 @@ void QETDiagramEditor::setUpMenu() menu_project -> addAction(m_terminal_strip_dialog); menu_project -> addAction(m_project_terminalBloc); menu_project -> addAction(m_project_export_wiring_list); + menu_project -> addAction(m_terminal_numbering); #ifdef QET_EXPORT_PROJECT_DB menu_project -> addSeparator(); menu_project -> addAction(m_export_project_db); @@ -1580,6 +1586,7 @@ void QETDiagramEditor::slot_updateActions() m_project_export_conductor_num-> setEnabled(opened_project); m_terminal_strip_dialog -> setEnabled(editable_project); m_project_export_wiring_list -> setEnabled(opened_project); + m_terminal_numbering -> setEnabled(editable_project); #ifdef QET_EXPORT_PROJECT_DB m_export_project_db -> setEnabled(editable_project); #endif @@ -2510,7 +2517,27 @@ void QETDiagramEditor::generateTerminalBlock() #endif if ( !success ) { QMessageBox::warning(nullptr, - QObject::tr("Error launching qet_tb_generator plugin"), - message); + QObject::tr("Error launching qet_tb_generator plugin"), + message); + } +} + +/** + * @brief QETDiagramEditor::slot_terminalNumbering + * Opens the dialog for automatic terminal numbering and applies the generated undo command. + */ +void QETDiagramEditor::slot_terminalNumbering() { + TerminalNumberingDialog dialog(this); + if (dialog.exec() == QDialog::Accepted) { + QETProject *project = currentProject(); + if (!project) return; + + // Fetch the generated undo command from the dialog logic + QUndoCommand *macro = dialog.getUndoCommand(project); + + // If changes were made, push them to the global undo stack + if (macro) { + undo_group.activeStack()->push(macro); + } } } diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 9fe010dd7..f456a162a 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -42,6 +42,7 @@ class RecentFiles; class DiagramPropertiesEditorDockWidget; class ElementsCollectionWidget; class AutoNumberingDockWidget; +class TerminalNumberingDialog; #ifdef BUILD_WITHOUT_KF5 #else @@ -132,6 +133,7 @@ class QETDiagramEditor : public QETMainWindow void projectWasClosed(ProjectView *); void editProjectProperties(ProjectView *); void editProjectProperties(QETProject *); + void slot_terminalNumbering(); void editDiagramProperties(DiagramView *); void editDiagramProperties(Diagram *); void addDiagramToProject(QETProject *); @@ -201,6 +203,7 @@ class QETDiagramEditor : public QETMainWindow *m_project_terminalBloc, ///< generate terminal block *m_project_export_conductor_num,///m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply); } /** @@ -170,6 +171,7 @@ void ElementInfoWidget::disableLiveEdit() { for (ElementInfoPartWidget *eipw : m_eipw_list) disconnect(eipw, &ElementInfoPartWidget::textChanged, this, &ElementInfoWidget::apply); + disconnect(ui->m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply); } /** @@ -193,6 +195,12 @@ void ElementInfoWidget::buildInterface() } ui->scroll_vlayout->addStretch(); + // Show checkbox only if the element is a terminal + if (m_element.data()->elementData().m_type == ElementData::Terminal) { + ui->m_auto_num_locked_cb->setVisible(true); + } else { + ui->m_auto_num_locked_cb->setVisible(false); + } } /** @@ -231,6 +239,11 @@ void ElementInfoWidget::updateUi() for (ElementInfoPartWidget *eipw : m_eipw_list) { eipw -> setText (element_info[eipw->key()].toString()); } + // Load the lock status for auto numbering + if (m_element->elementData().m_type == ElementData::Terminal) { + QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString(); + ui->m_auto_num_locked_cb->setChecked(lock_value == QLatin1String("true")); + } if (m_live_edit) { enableLiveEdit(); @@ -259,6 +272,10 @@ DiagramContext ElementInfoWidget::currentInfo() const } } + // Save the auto numbering lock status + if (m_element->elementData().m_type == ElementData::Terminal) { + info_.addValue(QStringLiteral("auto_num_locked"), ui->m_auto_num_locked_cb->isChecked() ? QStringLiteral("true") : QStringLiteral("false")); + } return info_; } diff --git a/sources/ui/elementinfowidget.ui b/sources/ui/elementinfowidget.ui index 05159a50d..14ae995ec 100644 --- a/sources/ui/elementinfowidget.ui +++ b/sources/ui/elementinfowidget.ui @@ -29,6 +29,19 @@ 0 + + + + Exclure de la numérotation auto + + + Qt::LeftToRight + + + margin: 5px; font-weight: bold; + + + diff --git a/sources/ui/terminalnumberingdialog.cpp b/sources/ui/terminalnumberingdialog.cpp new file mode 100644 index 000000000..689fc5cda --- /dev/null +++ b/sources/ui/terminalnumberingdialog.cpp @@ -0,0 +1,178 @@ +#include "terminalnumberingdialog.h" +#include "ui_terminalnumberingdialog.h" +#include "../qetproject.h" +#include "../diagram.h" +#include "../qetgraphicsitem/element.h" +#include "../undocommand/changeelementinformationcommand.h" +#include +#include + +/** + * @brief TerminalNumberingDialog::TerminalNumberingDialog + * Constructor + * @param parent + */ +TerminalNumberingDialog::TerminalNumberingDialog(QWidget *parent) : +QDialog(parent), +ui(new Ui::TerminalNumberingDialog) +{ + ui->setupUi(this); +} + +/** + * @brief TerminalNumberingDialog::~TerminalNumberingDialog + * Destructor + */ +TerminalNumberingDialog::~TerminalNumberingDialog() +{ + delete ui; +} + +/** + * @brief TerminalNumberingDialog::isXAxisPriority + * @return true if X axis has priority, false if Y axis has priority + */ +bool TerminalNumberingDialog::isXAxisPriority() const +{ + return ui->rb_priority_x->isChecked(); +} + +/** + * @brief TerminalNumberingDialog::isAlphanumeric + * @return true if alphanumeric sorting is enabled, false if numeric only + */ +bool TerminalNumberingDialog::isAlphanumeric() const +{ + return ui->rb_type_alpha->isChecked(); +} + +/** + * @brief TerminalNumberingDialog::getUndoCommand + * Scans the given project for terminals, sorts them according to user preferences + * (X/Y axis, alphanumeric rules), and generates an undo command containing all label changes. + * * @param project Pointer to the current QETProject + * @return QUndoCommand* containing the modifications, or nullptr if no changes are needed. + */ +QUndoCommand* TerminalNumberingDialog::getUndoCommand(QETProject *project) const { + if (!project) return nullptr; + + bool axisX = isXAxisPriority(); + bool alpha = isAlphanumeric(); + + // 1. Helper structure to store and sort terminal data + struct TermInfo { + Element *elmt; + QString prefix; + QString suffix; + int folioIndex; + qreal x; + qreal y; + }; + QList termList; + + // 2. Collect all terminals from all folios in the project + foreach (Diagram *diagram, project->diagrams()) { + int fIndex = diagram->folioIndex(); + foreach (QGraphicsItem *qgi, diagram->items()) { + if (Element *elmt = qgraphicsitem_cast(qgi)) { + + // Check if the element is actually a terminal + if (elmt->elementData().m_type == ElementData::Terminal) { + DiagramContext info = elmt->elementInformations(); + + // Ignore locked terminals (if the user checked a 'lock' property) + if (info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true")) { + continue; + } + + QString label = elmt->actualLabel(); + if (label.isEmpty()) continue; + + // Split prefix (e.g., "-X1") and suffix (e.g., "1" or "A") + QString prefix = label; + QString suffix = ""; + int colonIndex = label.lastIndexOf(':'); + if (colonIndex != -1) { + prefix = label.left(colonIndex); + suffix = label.mid(colonIndex + 1); + } + + // If user chose purely numeric, skip terminals with alphabetical suffixes + if (!alpha && !suffix.isEmpty()) { + bool isNum; + suffix.toInt(&isNum); + if (!isNum) continue; + } + + TermInfo ti; + ti.elmt = elmt; + ti.prefix = prefix; + ti.suffix = suffix; + ti.folioIndex = fIndex; + ti.x = elmt->pos().x(); + ti.y = elmt->pos().y(); + termList.append(ti); + } + } + } + } + + // 3. Sort terminals based on user selection (X or Y axis priority) + std::sort(termList.begin(), termList.end(), [axisX](const TermInfo &a, const TermInfo &b) { + // First sort by BMK Prefix alphabetically (case insensitive) + int prefixCmp = a.prefix.compare(b.prefix, Qt::CaseInsensitive); + if (prefixCmp != 0) return prefixCmp < 0; + + // Then sort by folio (page) index + if (a.folioIndex != b.folioIndex) return a.folioIndex < b.folioIndex; + + // Finally sort by coordinates (with a 1.0px tolerance to handle slight misalignments) + if (axisX) { + if (qAbs(a.x - b.x) > 1.0) return a.x < b.x; + return a.y < b.y; + } else { + if (qAbs(a.y - b.y) > 1.0) return a.y < b.y; + return a.x < b.x; + } + }); + + // 4. Generate new numbering and create the undo command macro + QUndoCommand *macro = new QUndoCommand(QObject::tr("Automatic terminal numbering")); + QMap counters; + + foreach (const TermInfo &ti, termList) { + // Increment the counter for this terminal block (e.g., "-X3") + counters[ti.prefix]++; + int newNum = counters[ti.prefix]; + + // Determine if the original suffix was a pure number + QString newLabel; + bool isNum; + ti.suffix.toInt(&isNum); + + if (isNum || ti.suffix.isEmpty()) { + // If it was a number (e.g., "1") or empty, update it with the new counter + newLabel = ti.prefix + ":" + QString::number(newNum); + } else { + // If it was alphabetical (e.g., "N", "PE"), keep the original text but consume the count! + newLabel = ti.prefix + ":" + ti.suffix; + } + + DiagramContext oldInfo = ti.elmt->elementInformations(); + DiagramContext newInfo = oldInfo; + newInfo.addValue(QStringLiteral("label"), newLabel); + + // Create an undo command only if the label actually changes + if (oldInfo != newInfo) { + new ChangeElementInformationCommand(ti.elmt, oldInfo, newInfo, macro); + } + } + + // 5. Return the macro if it contains changes, otherwise delete and return null + if (macro->childCount() > 0) { + return macro; + } else { + delete macro; + return nullptr; + } +} diff --git a/sources/ui/terminalnumberingdialog.h b/sources/ui/terminalnumberingdialog.h new file mode 100644 index 000000000..c3e756ba5 --- /dev/null +++ b/sources/ui/terminalnumberingdialog.h @@ -0,0 +1,35 @@ +#ifndef TERMINALNUMBERINGDIALOG_H +#define TERMINALNUMBERINGDIALOG_H + +#include + +class QETProject; +class QUndoCommand; + +namespace Ui { + class TerminalNumberingDialog; +} + +/** + * @brief The TerminalNumberingDialog class + * Dialog to configure the automatic numbering of terminals. + */ +class TerminalNumberingDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TerminalNumberingDialog(QWidget *parent = nullptr); + ~TerminalNumberingDialog(); + + // Getters for the user's choices + bool isXAxisPriority() const; + bool isAlphanumeric() const; + + QUndoCommand* getUndoCommand(QETProject *project) const; + +private: + Ui::TerminalNumberingDialog *ui; +}; + +#endif // TERMINALNUMBERINGDIALOG_H diff --git a/sources/ui/terminalnumberingdialog.ui b/sources/ui/terminalnumberingdialog.ui new file mode 100644 index 000000000..4a6bc97a2 --- /dev/null +++ b/sources/ui/terminalnumberingdialog.ui @@ -0,0 +1,139 @@ + + + TerminalNumberingDialog + + + + 0 + 0 + 400 + 300 + + + + Numérotation automatique des bornes + + + + + + Cette fonction numérote les bornes du projet selon leur position. Les bornes vides ou verrouillées sont ignorées.Le marquage des bornes doit être configuré au préalable comme suit : '-X:AB'. La partie avant les deux-points (le bornier) peut être nommée au choix. 'AB' peut être composé de chiffres ou de lettres." + + + true + + + + + + + Priorité des axes + + + + + + Priorité à l'axe X (horizontal) + + + true + + + + + + + Priorité à l'axe Y (vertical) + + + + + + + + + + Type de numérotation + + + + + + Numérique uniquement (1, 2, 3...) + + + true + + + + + + + Alphanumérique (A, B, C... 1, 2...) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + TerminalNumberingDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TerminalNumberingDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +