From 4f9474a05f3ee8bb48dae08e6628a29bc9afee1a Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Thu, 6 Aug 2026 07:33:39 +0200 Subject: [PATCH] PLC Fix scroll sync, data persistence, font defaults, copy/paste, and layout fixes --- sources/editor/graphicspart/partplctable.cpp | 5 +- .../ui/elementpropertieseditorwidget.cpp | 218 +++++++++++++----- .../editor/ui/elementpropertieseditorwidget.h | 10 +- .../ui/elementpropertieseditorwidget.ui | 69 +++--- sources/properties/elementdata.cpp | 205 ++++++++++++++++ sources/properties/elementdata.h | 7 + sources/qetgraphicsitem/element.cpp | 23 +- sources/ui/masterpropertieswidget.cpp | 2 +- 8 files changed, 452 insertions(+), 87 deletions(-) diff --git a/sources/editor/graphicspart/partplctable.cpp b/sources/editor/graphicspart/partplctable.cpp index 00014a4a9..d4f474096 100644 --- a/sources/editor/graphicspart/partplctable.cpp +++ b/sources/editor/graphicspart/partplctable.cpp @@ -18,6 +18,7 @@ #include "partplctable.h" #include "../../QPropertyUndoCommand/qpropertyundocommand.h" +#include "../../qetapp.h" #include "../../QetGraphicsItemModeler/qetgraphicshandleritem.h" #include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "../../properties/elementdata.h" @@ -302,7 +303,7 @@ void PartPlcTable::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti // Draw column headers QFont header_font = plc_data.headerFont.family().isEmpty() - ? painter->font() : plc_data.headerFont; + ? QETApp::diagramTextsFont() : plc_data.headerFont; header_font.setBold(true); painter->setFont(header_font); @@ -318,7 +319,7 @@ void PartPlcTable::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti // Draw IO rows QFont cell_font = plc_data.cellFont.family().isEmpty() - ? painter->font() : plc_data.cellFont; + ? QETApp::diagramTextsFont() : plc_data.cellFont; painter->setFont(cell_font); int start_idx = block_starts.at(block); int end_idx = (block + 1 < block_starts.size()) diff --git a/sources/editor/ui/elementpropertieseditorwidget.cpp b/sources/editor/ui/elementpropertieseditorwidget.cpp index 4500a1734..202cc23a5 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.cpp +++ b/sources/editor/ui/elementpropertieseditorwidget.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,6 +43,8 @@ #include #include #include +#include +#include /** @brief The EditorDelegate class @@ -666,10 +670,15 @@ void ElementPropertiesEditorWidget::createPlcConfigWidgets() plc_layout->addLayout(toolbar); // Tables side by side: IO table (left) + Terminal table (right) - auto *tables_splitter = new QSplitter(Qt::Horizontal, m_plc_gb); + // Both share a single vertical scrollbar on the right + auto *tables_container = new QWidget(m_plc_gb); + auto *tables_layout = new QHBoxLayout(tables_container); + tables_layout->setContentsMargins(0, 0, 0, 0); + + auto *splitter = new QSplitter(Qt::Horizontal, tables_container); // IO Table - m_plc_table = new QTableWidget(tables_splitter); + m_plc_table = new QTableWidget(splitter); m_plc_table->setColumnCount(5); m_plc_table->setHorizontalHeaderLabels({ tr("Type"), tr("Adresse"), tr("Fonction"), @@ -686,10 +695,10 @@ void ElementPropertiesEditorWidget::createPlcConfigWidgets() m_plc_table->setSelectionBehavior(QAbstractItemView::SelectItems); m_plc_table->setSelectionMode(QAbstractItemView::ExtendedSelection); m_plc_table->setMinimumHeight(200); - tables_splitter->addWidget(m_plc_table); + m_plc_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Terminal table (per IO: Nb + T1-T4) - m_plc_terminal_table = new QTableWidget(tables_splitter); + m_plc_terminal_table = new QTableWidget(splitter); m_plc_terminal_table->setColumnCount(2); m_plc_terminal_table->setHorizontalHeaderLabels({ tr("Nb."), tr("T1") @@ -700,13 +709,61 @@ void ElementPropertiesEditorWidget::createPlcConfigWidgets() m_plc_terminal_table->setSelectionBehavior(QAbstractItemView::SelectItems); m_plc_terminal_table->setSelectionMode(QAbstractItemView::ExtendedSelection); m_plc_terminal_table->setMinimumHeight(200); - tables_splitter->addWidget(m_plc_terminal_table); + m_plc_terminal_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - tables_splitter->setStretchFactor(0, 3); - tables_splitter->setStretchFactor(1, 1); - tables_splitter->setSizes({500, 150}); + // Shared vertical scrollbar + m_plc_shared_scrollbar = new QScrollBar(Qt::Vertical, tables_container); + m_plc_shared_scrollbar->setMinimum(0); - plc_layout->addWidget(tables_splitter); + splitter->addWidget(m_plc_table); + splitter->addWidget(m_plc_terminal_table); + splitter->setStretchFactor(0, 3); + splitter->setStretchFactor(1, 1); + + tables_layout->addWidget(splitter); + tables_layout->addWidget(m_plc_shared_scrollbar); + + // Bidirectional sync between tables and shared scrollbar + // Use flag to prevent infinite loops + connect(m_plc_shared_scrollbar, &QScrollBar::valueChanged, + this, [this](int value) { + if (m_plc_scroll_sync) return; + m_plc_scroll_sync = true; + m_plc_table->verticalScrollBar()->setValue(value); + m_plc_terminal_table->verticalScrollBar()->setValue(value); + m_plc_scroll_sync = false; + }); + connect(m_plc_table->verticalScrollBar(), &QScrollBar::valueChanged, + this, [this](int value) { + if (m_plc_scroll_sync) return; + m_plc_scroll_sync = true; + m_plc_shared_scrollbar->setValue(value); + m_plc_terminal_table->verticalScrollBar()->setValue(value); + m_plc_scroll_sync = false; + }); + connect(m_plc_terminal_table->verticalScrollBar(), &QScrollBar::valueChanged, + this, [this](int value) { + if (m_plc_scroll_sync) return; + m_plc_scroll_sync = true; + m_plc_shared_scrollbar->setValue(value); + m_plc_table->verticalScrollBar()->setValue(value); + m_plc_scroll_sync = false; + }); + + // Update shared scrollbar range from both tables + auto syncRange = [this]() { + int max = qMax(m_plc_table->verticalScrollBar()->maximum(), + m_plc_terminal_table->verticalScrollBar()->maximum()); + m_plc_shared_scrollbar->blockSignals(true); + m_plc_shared_scrollbar->setMaximum(max); + m_plc_shared_scrollbar->blockSignals(false); + }; + connect(m_plc_table->verticalScrollBar(), &QScrollBar::rangeChanged, + this, syncRange); + connect(m_plc_terminal_table->verticalScrollBar(), &QScrollBar::rangeChanged, + this, syncRange); + + plc_layout->addWidget(tables_container); // Font settings auto *font_layout = new QHBoxLayout(); @@ -790,12 +847,25 @@ void ElementPropertiesEditorWidget::createPlcConfigWidgets() } plc_layout->addLayout(col_layout); - // Add to master group box - ui->m_master_gb->layout()->addWidget(m_plc_gb); + // Add to master group box - row 4, full width + auto *gl = qobject_cast(ui->m_master_gb->layout()); + gl->addWidget(m_plc_gb, 4, 0, 1, 2); // Connect signals connect(add_btn, &QPushButton::clicked, this, &ElementPropertiesEditorWidget::plcAddRow); connect(remove_btn, &QPushButton::clicked, this, &ElementPropertiesEditorWidget::plcRemoveRow); + + // Ctrl+V shortcut for paste + auto *paste_shortcut = new QShortcut(QKeySequence::Paste, m_plc_table); + connect(paste_shortcut, &QShortcut::activated, this, &ElementPropertiesEditorWidget::plcPasteFromClipboard); + + // Context menu for the PLC table + m_plc_table->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_plc_table, &QTableWidget::customContextMenuRequested, this, [this](const QPoint &pos) { + QMenu menu; + menu.addAction(tr("Coller depuis le presse-papiers"), this, &ElementPropertiesEditorWidget::plcPasteFromClipboard); + menu.exec(m_plc_table->mapToGlobal(pos)); + }); } /** @@ -877,12 +947,12 @@ void ElementPropertiesEditorWidget::populatePlcTable() m_plc_header_font = plc_data.headerFont; m_plc_cell_font = plc_data.cellFont; if (m_plc_header_font.family().isEmpty()) { - m_plc_header_font = QFont(m_plc_table->font()); + m_plc_header_font = QETApp::diagramTextsFont(); m_plc_header_font.setBold(true); m_plc_header_font.setPointSize(8); } if (m_plc_cell_font.family().isEmpty()) { - m_plc_cell_font = QFont(m_plc_table->font()); + m_plc_cell_font = QETApp::diagramTextsFont(); m_plc_cell_font.setPointSize(8); } m_plc_header_font_btn->setText(tr("Police des en-têtes: %1 %2pt") @@ -920,6 +990,21 @@ void ElementPropertiesEditorWidget::populatePlcTable() hdr->moveSection(hdr->visualIndex(logical), visual); } } + + // Ensure scrollbars stay hidden and sync shared scrollbar range + if (m_plc_table) { + m_plc_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_plc_table->verticalScrollBar()->setVisible(false); + } + if (m_plc_terminal_table) { + m_plc_terminal_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_plc_terminal_table->verticalScrollBar()->setVisible(false); + } + if (m_plc_shared_scrollbar && m_plc_table) { + int max = qMax(m_plc_table->verticalScrollBar()->maximum(), + m_plc_terminal_table->verticalScrollBar()->maximum()); + m_plc_shared_scrollbar->setMaximum(max); + } } /** @@ -1158,53 +1243,80 @@ void ElementPropertiesEditorWidget::plcPasteFromClipboard() return; QStringList lines = clipboard_text.split('\n', Qt::SkipEmptyParts); + if (lines.isEmpty()) + return; - int start_row = m_plc_table->rowCount(); - m_plc_table->setRowCount(start_row + lines.size()); - - for (int i = 0; i < lines.size(); ++i) { - QStringList cells = lines.at(i).split('\t'); - int row = start_row + i; - - // Type combo - auto *type_cb = new QComboBox(m_plc_table); - QStringList plc_types = ElementData::plcIOTypeList(); - for (int t = 0; t < plc_types.size(); ++t) { - type_cb->addItem(plc_types.at(t), t); + bool has_tabs = false; + for (const QString &line : lines) { + if (line.contains('\t')) { + has_tabs = true; + break; } + } - // Try to match type from clipboard - if (!cells.isEmpty()) { - QString type_str = cells.at(0).trimmed(); - int type_idx = -1; + if (!has_tabs) { + // Vertical paste: values go down the same column + int target_col = m_plc_table->currentColumn(); + if (target_col < 0) target_col = 0; + int target_row = m_plc_table->currentRow(); + if (target_row < 0) target_row = 0; + int max_rows = m_plc_table->rowCount(); + + for (int i = 0; i < lines.size(); ++i) { + int row = target_row + i; + if (row >= max_rows) break; + plcSetCellFromValue(row, target_col, lines.at(i).trimmed()); + } + } else { + // Horizontal paste: each line is a separate IO row + int target_row = m_plc_table->currentRow(); + if (target_row < 0) target_row = 0; + int max_rows = m_plc_table->rowCount(); + + for (int i = 0; i < lines.size(); ++i) { + int row = target_row + i; + if (row >= max_rows) break; + QStringList cells = lines.at(i).split('\t'); + for (int c = 0; c < cells.size(); ++c) { + if (c > 4) break; + plcSetCellFromValue(row, c, cells.at(c).trimmed()); + } + } + } +} + +/** + * @brief ElementPropertiesEditorWidget::plcSetCellFromValue + * Set a single table cell value, respecting the column widget type. + */ +void ElementPropertiesEditorWidget::plcSetCellFromValue(int row, int col, const QString &val) +{ + if (!m_plc_table || row < 0 || col < 0 || col > 4) + return; + + if (col == 0) { + auto *type_cb = qobject_cast(m_plc_table->cellWidget(row, col)); + if (!type_cb) + return; + if (!val.isEmpty()) { + QStringList plc_types = ElementData::plcIOTypeList(); for (int t = 0; t < plc_types.size(); ++t) { - if (plc_types.at(t).compare(type_str, Qt::CaseInsensitive) == 0) { - type_idx = t; - break; + if (plc_types.at(t).compare(val, Qt::CaseInsensitive) == 0) { + type_cb->setCurrentIndex(t); + return; } } - if (type_idx >= 0) - type_cb->setCurrentIndex(type_idx); } - m_plc_table->setCellWidget(row, 0, type_cb); - - // Address - m_plc_table->setItem(row, 1, new QTableWidgetItem( - cells.size() > 1 ? cells.at(1).trimmed() : QString())); - - // Function text - m_plc_table->setItem(row, 2, new QTableWidgetItem( - cells.size() > 2 ? cells.at(2).trimmed() : QString())); - - // Comment - m_plc_table->setItem(row, 3, new QTableWidgetItem( - cells.size() > 3 ? cells.at(3).trimmed() : QString())); - - // CrossRef (read-only) - auto *crossref_item = new QTableWidgetItem( - cells.size() > 4 ? cells.at(4).trimmed() : QString()); - crossref_item->setFlags(crossref_item->flags() & ~Qt::ItemIsEditable); - m_plc_table->setItem(row, 4, crossref_item); + } + else if (col == 4) { + // CrossRef - read-only + auto *item = new QTableWidgetItem(val); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + m_plc_table->setItem(row, col, item); + } + else { + // Text columns: Address, Function, Comment + m_plc_table->setItem(row, col, new QTableWidgetItem(val)); } } diff --git a/sources/editor/ui/elementpropertieseditorwidget.h b/sources/editor/ui/elementpropertieseditorwidget.h index b283a061e..7956917fa 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.h +++ b/sources/editor/ui/elementpropertieseditorwidget.h @@ -30,6 +30,7 @@ class QCheckBox; class QGroupBox; class QPushButton; class QLineEdit; +class QScrollBar; namespace Ui { class ElementPropertiesEditorWidget; @@ -74,6 +75,7 @@ class ElementPropertiesEditorWidget : public QDialog void plcTerminalCountChanged(int row, int count); void plcSelectHeaderFont(); void plcSelectCellFont(); + void plcSetCellFromValue(int row, int col, const QString &val); //ATTRIBUTES private: @@ -92,9 +94,11 @@ class ElementPropertiesEditorWidget : public QDialog QCheckBox *m_plc_show_headers_cb = nullptr; QFont m_plc_header_font; QFont m_plc_cell_font; - QList m_plc_col_visibility_checkboxes; - QList m_plc_col_width_spinboxes; - QList m_plc_col_name_edits; + QList m_plc_col_visibility_checkboxes; + QList m_plc_col_width_spinboxes; + QList m_plc_col_name_edits; + QScrollBar *m_plc_shared_scrollbar = nullptr; + bool m_plc_scroll_sync = false; }; #endif // ELEMENTPROPERTIESEDITORWIDGET_H diff --git a/sources/editor/ui/elementpropertieseditorwidget.ui b/sources/editor/ui/elementpropertieseditorwidget.ui index 904faa2d2..91802bfb0 100644 --- a/sources/editor/ui/elementpropertieseditorwidget.ui +++ b/sources/editor/ui/elementpropertieseditorwidget.ui @@ -39,7 +39,20 @@ - + + + + Qt::Vertical + + + + 20 + 40 + + + + + @@ -93,17 +106,34 @@ Élément maître - - - - - Type concret - - - - - - + + + + + + + Type concret + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + @@ -202,20 +232,7 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - - + diff --git a/sources/properties/elementdata.cpp b/sources/properties/elementdata.cpp index 6bab5ce3d..e92a4d318 100644 --- a/sources/properties/elementdata.cpp +++ b/sources/properties/elementdata.cpp @@ -267,6 +267,211 @@ QDomElement ElementData::kindInfoToXml(QDomDocument &document) return returned_elmt; } +/** + * @brief ElementData::plcMasterDataToXml + * Serialize PLC master data to XML (used by Element::toXml for diagram instances) + */ +QDomElement ElementData::plcMasterDataToXml(QDomDocument &document) const +{ + auto xml_plc = document.createElement(QStringLiteral("plcMasterData")); + xml_plc.setAttribute(QStringLiteral("rowHeight"), + QString::number(m_plc_master_data.rowHeight, 'f', 2)); + + // Save break positions + { + auto xml_breaks = document.createElement(QStringLiteral("breakPositions")); + for (int bp : m_plc_master_data.breakPositions) { + auto xml_bp = document.createElement(QStringLiteral("break")); + xml_bp.appendChild(document.createTextNode(QString::number(bp))); + xml_breaks.appendChild(xml_bp); + } + xml_plc.appendChild(xml_breaks); + } + + // Save column widths + auto xml_col_widths = document.createElement(QStringLiteral("columnWidths")); + for (auto it = m_plc_master_data.colWidths.constBegin(); + it != m_plc_master_data.colWidths.constEnd(); ++it) { + auto xml_col = document.createElement(QStringLiteral("column")); + xml_col.setAttribute(QStringLiteral("index"), it.key()); + xml_col.setAttribute(QStringLiteral("width"), QString::number(it.value(), 'f', 2)); + xml_col_widths.appendChild(xml_col); + } + xml_plc.appendChild(xml_col_widths); + + // Save column visibility + auto xml_col_vis = document.createElement(QStringLiteral("columnVisibility")); + for (auto it = m_plc_master_data.colVisible.constBegin(); + it != m_plc_master_data.colVisible.constEnd(); ++it) { + auto xml_col = document.createElement(QStringLiteral("column")); + xml_col.setAttribute(QStringLiteral("index"), it.key()); + xml_col.setAttribute(QStringLiteral("visible"), it.value() ? "true" : "false"); + xml_col_vis.appendChild(xml_col); + } + xml_plc.appendChild(xml_col_vis); + + // Save fonts + if (!m_plc_master_data.headerFont.family().isEmpty()) { + auto xml_hfont = document.createElement(QStringLiteral("headerFont")); + xml_hfont.setAttribute(QStringLiteral("family"), m_plc_master_data.headerFont.family()); + xml_hfont.setAttribute(QStringLiteral("size"), m_plc_master_data.headerFont.pointSize()); + xml_hfont.setAttribute(QStringLiteral("bold"), m_plc_master_data.headerFont.bold() ? "true" : "false"); + xml_plc.appendChild(xml_hfont); + } + if (!m_plc_master_data.cellFont.family().isEmpty()) { + auto xml_cfont = document.createElement(QStringLiteral("cellFont")); + xml_cfont.setAttribute(QStringLiteral("family"), m_plc_master_data.cellFont.family()); + xml_cfont.setAttribute(QStringLiteral("size"), m_plc_master_data.cellFont.pointSize()); + xml_cfont.setAttribute(QStringLiteral("bold"), m_plc_master_data.cellFont.bold() ? "true" : "false"); + xml_plc.appendChild(xml_cfont); + } + + // Save custom column names + if (!m_plc_master_data.columnNames.isEmpty()) { + auto xml_names = document.createElement(QStringLiteral("columnNames")); + for (int i = 0; i < m_plc_master_data.columnNames.size(); ++i) { + auto xml_name = document.createElement(QStringLiteral("column")); + xml_name.setAttribute(QStringLiteral("index"), i); + xml_name.appendChild(document.createTextNode(m_plc_master_data.columnNames.at(i))); + xml_names.appendChild(xml_name); + } + xml_plc.appendChild(xml_names); + } + + // Save column order + if (!m_plc_master_data.columnOrder.isEmpty()) { + auto xml_order = document.createElement(QStringLiteral("columnOrder")); + QString order_str; + for (int i = 0; i < m_plc_master_data.columnOrder.size(); ++i) { + if (i > 0) order_str += QStringLiteral(","); + order_str += QString::number(m_plc_master_data.columnOrder.at(i)); + } + xml_order.appendChild(document.createTextNode(order_str)); + xml_plc.appendChild(xml_order); + } + + // Save showHeaders + { + auto xml_sh = document.createElement(QStringLiteral("showHeaders")); + xml_sh.appendChild(document.createTextNode( + m_plc_master_data.showHeaders ? QStringLiteral("1") : QStringLiteral("0"))); + xml_plc.appendChild(xml_sh); + } + + // Save IO entries + auto xml_ios = document.createElement(QStringLiteral("plcIOs")); + for (const auto &io : m_plc_master_data.ios) { + auto xml_io = document.createElement(QStringLiteral("plcIO")); + xml_io.setAttribute(QStringLiteral("type"), plcIOTypeToString(io.type)); + xml_io.setAttribute(QStringLiteral("address"), io.address); + xml_io.setAttribute(QStringLiteral("functionText"), io.functionText); + xml_io.setAttribute(QStringLiteral("comment"), io.comment); + xml_io.setAttribute(QStringLiteral("crossRef"), io.crossRef); + xml_io.setAttribute(QStringLiteral("terminalCount"), io.terminalCount); + for (const auto &t : io.terminals) { + auto xml_term = document.createElement(QStringLiteral("terminal")); + xml_term.appendChild(document.createTextNode(t)); + xml_io.appendChild(xml_term); + } + xml_ios.appendChild(xml_io); + } + xml_plc.appendChild(xml_ios); + + return xml_plc; +} + +/** + * @brief ElementData::plcMasterDataFromXml + * Deserialize PLC master data from XML + */ +void ElementData::plcMasterDataFromXml(const QDomElement &xml_plc) +{ + if (xml_plc.isNull()) + return; + + // Reset PLC data before loading to avoid appending to existing data + m_plc_master_data = PlcMasterData(); + + m_plc_master_data.rowHeight = xml_plc.attribute( + QStringLiteral("rowHeight"), QStringLiteral("8.0")).toDouble(); + + // Load break positions + auto xml_breaks = xml_plc.firstChildElement(QStringLiteral("breakPositions")); + for (const auto &xml_bp : QETXML::findInDomElement(xml_breaks, QStringLiteral("break"))) { + m_plc_master_data.breakPositions.append(xml_bp.text().toInt()); + } + + // Load column widths + auto xml_col_widths = xml_plc.firstChildElement(QStringLiteral("columnWidths")); + for (const auto &xml_col : QETXML::findInDomElement(xml_col_widths, QStringLiteral("column"))) { + int idx = xml_col.attribute(QStringLiteral("index")).toInt(); + qreal w = xml_col.attribute(QStringLiteral("width")).toDouble(); + m_plc_master_data.colWidths.insert(idx, w); + } + + // Load column visibility + auto xml_col_vis = xml_plc.firstChildElement(QStringLiteral("columnVisibility")); + for (const auto &xml_col : QETXML::findInDomElement(xml_col_vis, QStringLiteral("column"))) { + int idx = xml_col.attribute(QStringLiteral("index")).toInt(); + bool vis = xml_col.attribute(QStringLiteral("visible")) == QLatin1String("true"); + m_plc_master_data.colVisible.insert(idx, vis); + } + + // Load fonts + auto xml_hfont = xml_plc.firstChildElement(QStringLiteral("headerFont")); + if (!xml_hfont.isNull()) { + m_plc_master_data.headerFont.setFamily(xml_hfont.attribute(QStringLiteral("family"))); + m_plc_master_data.headerFont.setPointSize(xml_hfont.attribute(QStringLiteral("size")).toInt()); + m_plc_master_data.headerFont.setBold(xml_hfont.attribute(QStringLiteral("bold")) == QLatin1String("true")); + } + auto xml_cfont = xml_plc.firstChildElement(QStringLiteral("cellFont")); + if (!xml_cfont.isNull()) { + m_plc_master_data.cellFont.setFamily(xml_cfont.attribute(QStringLiteral("family"))); + m_plc_master_data.cellFont.setPointSize(xml_cfont.attribute(QStringLiteral("size")).toInt()); + m_plc_master_data.cellFont.setBold(xml_cfont.attribute(QStringLiteral("bold")) == QLatin1String("true")); + } + + // Load custom column names + auto xml_names = xml_plc.firstChildElement(QStringLiteral("columnNames")); + for (const auto &xml_col : QETXML::findInDomElement(xml_names, QStringLiteral("column"))) { + int idx = xml_col.attribute(QStringLiteral("index")).toInt(); + while (m_plc_master_data.columnNames.size() <= idx) + m_plc_master_data.columnNames.append(QString()); + m_plc_master_data.columnNames.replace(idx, xml_col.text()); + } + + // Load column order + auto xml_order = xml_plc.firstChildElement(QStringLiteral("columnOrder")); + if (!xml_order.isNull()) { + QStringList order_str_list = xml_order.text().split(','); + for (const auto &s : order_str_list) { + m_plc_master_data.columnOrder.append(s.trimmed().toInt()); + } + } + + // Load showHeaders + auto xml_sh = xml_plc.firstChildElement(QStringLiteral("showHeaders")); + if (!xml_sh.isNull()) { + m_plc_master_data.showHeaders = xml_sh.text() == QLatin1String("1"); + } + + // Load IO entries + auto xml_ios = xml_plc.firstChildElement(QStringLiteral("plcIOs")); + for (const auto &xml_io : QETXML::findInDomElement(xml_ios, QStringLiteral("plcIO"))) { + PlcIO io; + io.type = plcIOTypeFromString(xml_io.attribute(QStringLiteral("type"))); + io.address = xml_io.attribute(QStringLiteral("address")); + io.functionText = xml_io.attribute(QStringLiteral("functionText")); + io.comment = xml_io.attribute(QStringLiteral("comment")); + io.crossRef = xml_io.attribute(QStringLiteral("crossRef")); + io.terminalCount = xml_io.attribute(QStringLiteral("terminalCount")).toInt(); + for (const auto &xml_term : QETXML::findInDomElement(xml_io, QStringLiteral("terminal"))) { + io.terminals.append(xml_term.text()); + } + m_plc_master_data.ios.append(io); + } +} + /** * @brief ElementData::setTerminalType * Override the terminal type by \p t_type diff --git a/sources/properties/elementdata.h b/sources/properties/elementdata.h index 6a66f387a..952d9d484 100644 --- a/sources/properties/elementdata.h +++ b/sources/properties/elementdata.h @@ -130,6 +130,11 @@ class ElementData : public PropertiesInterface QList columnOrder; ///< Column display order (logical indices) bool showHeaders = true; ///< Show column headers on sheet + PlcMasterData() { + headerFont.setFamily(QString()); + cellFont.setFamily(QString()); + } + bool operator==(const PlcMasterData &other) const { return ios == other.ios && breakPositions == other.breakPositions @@ -201,6 +206,8 @@ class ElementData : public PropertiesInterface QDomElement toXml(QDomDocument &xml_element) const override; bool fromXml(const QDomElement &xml_element) override; QDomElement kindInfoToXml(QDomDocument &document); + QDomElement plcMasterDataToXml(QDomDocument &document) const; + void plcMasterDataFromXml(const QDomElement &xml_plc); void setTerminalType(ElementData::TerminalType t_type); ElementData::TerminalType terminalType() const; diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index d6d12e312..d9f82ba06 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -16,6 +16,7 @@ along with QElectroTech. If not, see . */ #include "element.h" +#include "../qetapp.h" #include "../qetproject.h" #include "../PropertiesEditor/propertieseditordialog.h" #include "../autoNum/assignvariables.h" @@ -860,6 +861,15 @@ bool Element::fromXml(QDomElement &e, } } + //Load PLC master data override from diagram XML + if (m_data.m_type == ElementData::Master && + m_data.m_master_type == ElementData::PLC) + { + auto xml_plc = e.firstChildElement(QStringLiteral("plcMasterData")); + if (!xml_plc.isNull()) + m_data.plcMasterDataFromXml(xml_plc); + } + //We must block the update of the alignment when loading the information //otherwise the pos of the text will not be the same as it was at save time. for(DynamicElementTextItem *deti : m_dynamic_text_list) @@ -993,6 +1003,15 @@ QDomElement Element::toXml( element.appendChild(properties); } + //Save PLC master data override for elements on diagram + if (m_data.m_type == ElementData::Master && + m_data.m_master_type == ElementData::PLC) + { + auto xml_plc = m_data.plcMasterDataToXml(document); + if (!xml_plc.isNull()) + element.appendChild(xml_plc); + } + //Dynamic texts QDomElement dyn_text = document.createElement(QStringLiteral("dynamic_texts")); for (DynamicElementTextItem *deti : m_dynamic_text_list) @@ -1876,12 +1895,12 @@ void Element::drawPlcTable(QPainter *painter) // Fonts QFont header_font = plc_data.headerFont; if (header_font.family().isEmpty()) { - header_font = painter->font(); + header_font = QETApp::diagramTextsFont(); header_font.setBold(true); } QFont cell_font = plc_data.cellFont; if (cell_font.family().isEmpty()) { - cell_font = painter->font(); + cell_font = QETApp::diagramTextsFont(); } for (const QPointF &pos : positions) { diff --git a/sources/ui/masterpropertieswidget.cpp b/sources/ui/masterpropertieswidget.cpp index e5952a5e5..2a059230c 100644 --- a/sources/ui/masterpropertieswidget.cpp +++ b/sources/ui/masterpropertieswidget.cpp @@ -535,7 +535,7 @@ void MasterPropertiesWidget::updateUi() tr("Commentaire"), tr("Réf. croisée") }); m_plc_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - m_plc_table->setSelectionBehavior(QAbstractItemView::SelectRows); + m_plc_table->setSelectionBehavior(QAbstractItemView::SelectItems); m_plc_table->setSelectionMode(QAbstractItemView::ExtendedSelection); m_plc_table->setMinimumHeight(200);