#include "tablewidgetfactory.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include TableWidgetFactory::TableWidgetFactory(QObject *parent) : QObject(parent) { } QWidget *TableWidgetFactory::createTableWidget(const TableDefinition &tableDef) { QWidget *widget = nullptr; if (tableDef.tableType == "grid") { widget = createGridTable(tableDef); } else if (tableDef.tableType == "form") { widget = createFormTable(tableDef); } else if (tableDef.tableType == "series") { widget = createSeriesTable(tableDef); } else { qWarning() << "Unknown table type:" << tableDef.tableType; widget = new QWidget(); } if (widget) { tableData[widget].definition = tableDef; qDebug() << "Created table widget for:" << tableDef.id << "name:" << tableDef.name; } return widget; } QWidget *TableWidgetFactory::createGridTable(const TableDefinition &tableDef) { QWidget *container = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(container); layout->setContentsMargins(12, 12, 12, 12); // 標題 - Material Design 風格 if (!tableDef.name.isEmpty()) { QLabel *titleLabel = new QLabel(tableDef.name, container); titleLabel->setStyleSheet("font-weight: 500; font-size: 14px; color: #212121; margin-bottom: 4px;"); layout->addWidget(titleLabel); } // 描述 if (!tableDef.description.isEmpty()) { QLabel *descLabel = new QLabel(tableDef.description, container); descLabel->setWordWrap(true); descLabel->setStyleSheet("color: #757575; font-size: 13px; margin-bottom: 8px;"); layout->addWidget(descLabel); } // 創建表格 QTableWidget *table = new QTableWidget(container); table->setRowCount(tableDef.rowHeaders.size()); table->setColumnCount(tableDef.columnHeaders.size()); // Material Design 樣式 table->setStyleSheet( "QTableWidget {" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " gridline-color: #EEEEEE;" " background-color: white;" "}" "QTableWidget::item {" " padding: 8px 12px;" " color: #212121;" "}" "QTableWidget::item:selected {" " background-color: #E3F2FD;" " color: #1976D2;" "}" "QHeaderView::section {" " background-color: #2196F3;" " color: white;" " padding: 10px 12px;" " border: none;" " font-weight: 500;" " font-size: 13px;" "}"); // 列標題 QStringList columnLabels; for (const FieldDefinition &colDef : tableDef.columnHeaders) { QString label = colDef.name; if (!colDef.unit.isEmpty()) { label += QString("\n(%1)").arg(colDef.unit); } if (colDef.isRequired) { label += " *"; } columnLabels << label; } table->setHorizontalHeaderLabels(columnLabels); // 行標題 QStringList rowLabels; for (const auto &rowHeader : tableDef.rowHeaders) { rowLabels << rowHeader.second; } table->setVerticalHeaderLabels(rowLabels); // 調整列寬 table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); table->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); // 初始化單元格 for (int row = 0; row < table->rowCount(); ++row) { for (int col = 0; col < table->columnCount(); ++col) { QTableWidgetItem *item = new QTableWidgetItem(""); table->setItem(row, col, item); // 設置只讀(計算字段) if (col < tableDef.columnHeaders.size()) { const FieldDefinition &colDef = tableDef.columnHeaders[col]; if (colDef.isReadOnly || colDef.type == "calculated") { item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setBackground(QColor("#FAFAFA")); } } } } // 連接信號 connect(table, &QTableWidget::itemChanged, this, [this, container, tableDef](QTableWidgetItem *item) { if (!item) return; int row = item->row(); int col = item->column(); if (row < tableDef.rowHeaders.size() && col < tableDef.columnHeaders.size()) { QString rowId = tableDef.rowHeaders[row].first; QString colId = tableDef.columnHeaders[col].id; emit cellValueChanged(container, rowId, colId, item->text()); } }); layout->addWidget(table); // 存儲 grid widget tableData[container].gridWidget = table; // 應用靜態單元格 applyStaticCells(container, tableDef); return container; } QWidget *TableWidgetFactory::createSeriesTable(const TableDefinition &tableDef) { QWidget *container = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(container); layout->setContentsMargins(12, 12, 12, 12); // 標題 - Material Design 風格 if (!tableDef.name.isEmpty()) { QLabel *titleLabel = new QLabel(tableDef.name, container); titleLabel->setStyleSheet("font-weight: 500; font-size: 14px; color: #212121; margin-bottom: 4px;"); layout->addWidget(titleLabel); } // 描述 if (!tableDef.description.isEmpty()) { QLabel *descLabel = new QLabel(tableDef.description, container); descLabel->setWordWrap(true); descLabel->setStyleSheet("color: #757575; font-size: 13px; margin-bottom: 8px;"); layout->addWidget(descLabel); } // 創建時序數據表格 QTableWidget *table = new QTableWidget(container); // 設置列:時間戳 + 字段 int columnCount = 1 + tableDef.fields.size(); table->setColumnCount(columnCount); // 列標題 QStringList columnLabels; columnLabels << "時間戳"; for (const FieldDefinition &fieldDef : tableDef.fields) { QString label = fieldDef.name; if (!fieldDef.unit.isEmpty()) { label += QString(" (%1)").arg(fieldDef.unit); } columnLabels << label; } table->setHorizontalHeaderLabels(columnLabels); // Material Design 樣式 - 使用綠色強調時序數據 table->setStyleSheet( "QTableWidget {" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " gridline-color: #EEEEEE;" " background-color: white;" "}" "QTableWidget::item {" " padding: 8px 12px;" " color: #212121;" "}" "QTableWidget::item:selected {" " background-color: #E8F5E9;" " color: #388E3C;" "}" "QHeaderView::section {" " background-color: #4CAF50;" " color: white;" " padding: 10px 12px;" " border: none;" " font-weight: 500;" " font-size: 13px;" "}"); // 配置表格 table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); table->verticalHeader()->setVisible(false); table->setAlternatingRowColors(true); table->setSelectionBehavior(QAbstractItemView::SelectRows); table->setSortingEnabled(true); layout->addWidget(table); // 存儲 series widget tableData[container].seriesWidget = table; // 應用靜態單元格 applyStaticCells(container, tableDef); return container; } QWidget *TableWidgetFactory::createFormTable(const TableDefinition &tableDef) { QWidget *container = new QWidget(); QVBoxLayout *mainLayout = new QVBoxLayout(container); mainLayout->setContentsMargins(12, 12, 12, 12); // 標題 - Material Design 風格 if (!tableDef.name.isEmpty()) { QLabel *titleLabel = new QLabel(tableDef.name, container); titleLabel->setStyleSheet("font-weight: 500; font-size: 14px; color: #212121; margin-bottom: 4px;"); mainLayout->addWidget(titleLabel); } // 描述 if (!tableDef.description.isEmpty()) { QLabel *descLabel = new QLabel(tableDef.description, container); descLabel->setWordWrap(true); descLabel->setStyleSheet("color: #757575; font-size: 13px; margin-bottom: 12px;"); mainLayout->addWidget(descLabel); } // 創建網格佈局(12列系統) int totalColumns = 12; if (tableDef.layoutConfig.contains("totalColumns")) { totalColumns = tableDef.layoutConfig["totalColumns"].toInt(); } Q_UNUSED(totalColumns); QGridLayout *gridLayout = new QGridLayout(); gridLayout->setSpacing(10); // 按順序排序字段 QList sortedFields = tableDef.fields; std::sort(sortedFields.begin(), sortedFields.end(), [](const FieldDefinition &a, const FieldDefinition &b) { int orderA = a.layoutConfig.value("order", 999).toInt(); int orderB = b.layoutConfig.value("order", 999).toInt(); return orderA < orderB; }); // 創建字段組件 int currentRow = 0; QMap fields; for (const FieldDefinition &fieldDef : sortedFields) { // 獲取佈局配置 int labelSpan = fieldDef.layoutConfig.value("labelSpan", 4).toInt(); int valueSpan = fieldDef.layoutConfig.value("valueSpan", 8).toInt(); int rowSpan = fieldDef.layoutConfig.value("rowSpan", 1).toInt(); // 創建標籤 QString labelText = fieldDef.name; if (!fieldDef.unit.isEmpty()) { labelText += QString(" (%1)").arg(fieldDef.unit); } if (fieldDef.isRequired) { labelText += " *"; } QLabel *label = new QLabel(labelText, container); label->setTextFormat(Qt::RichText); label->setStyleSheet("font-weight: 500; color: #455A64; font-size: 14px;"); label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); // 創建字段組件 QWidget *fieldWidget = createFieldWidget(fieldDef, container); if (fieldWidget) { // 添加到網格 gridLayout->addWidget(label, currentRow, 0, rowSpan, labelSpan); gridLayout->addWidget(fieldWidget, currentRow, labelSpan, rowSpan, valueSpan); fields[fieldDef.id] = fieldWidget; connectFieldSignals(fieldWidget, fieldDef.id, container); } currentRow += rowSpan; } mainLayout->addLayout(gridLayout); mainLayout->addStretch(); // 存儲字段組件 tableData[container].fieldWidgets = fields; // 應用靜態單元格 applyStaticCells(container, tableDef); return container; } QWidget *TableWidgetFactory::createFieldWidget(const FieldDefinition &fieldDef, QWidget *parent) { QWidget *widget = nullptr; if (fieldDef.type == "numeric") { widget = createNumericField(fieldDef, parent); } else if (fieldDef.type == "text") { widget = createTextField(fieldDef, parent); } else if (fieldDef.type == "selection") { widget = createSelectionField(fieldDef, parent); } else if (fieldDef.type == "boolean") { widget = createBooleanField(fieldDef, parent); } else if (fieldDef.type == "datetime") { widget = createDateTimeField(fieldDef, parent); } else if (fieldDef.type == "calculated") { widget = createCalculatedField(fieldDef, parent); } if (widget) { widget->setEnabled(!fieldDef.isReadOnly); } return widget; } QWidget *TableWidgetFactory::createNumericField(const FieldDefinition &fieldDef, QWidget *parent) { QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent); // 範圍 double minVal = -999999.0; double maxVal = 999999.0; if (fieldDef.validationRules.contains("min")) { minVal = fieldDef.validationRules["min"].toDouble(); } if (fieldDef.validationRules.contains("max")) { maxVal = fieldDef.validationRules["max"].toDouble(); } spinBox->setRange(minVal, maxVal); // 精度 int decimals = 3; if (fieldDef.validationRules.contains("precision")) { decimals = fieldDef.validationRules["precision"].toInt(); } spinBox->setDecimals(decimals); // 默認值 if (fieldDef.defaultValue.isValid()) { spinBox->setValue(fieldDef.defaultValue.toDouble()); } // Material Design 樣式 spinBox->setStyleSheet( "QDoubleSpinBox {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: white;" " font-size: 14px;" " color: #212121;" "}" "QDoubleSpinBox:focus {" " border: 2px solid #2196F3;" "}" "QDoubleSpinBox:disabled {" " background-color: #FAFAFA;" " color: #9E9E9E;" "}"); return spinBox; } QWidget *TableWidgetFactory::createTextField(const FieldDefinition &fieldDef, QWidget *parent) { QLineEdit *lineEdit = new QLineEdit(parent); // 默認值 if (fieldDef.defaultValue.isValid()) { lineEdit->setText(fieldDef.defaultValue.toString()); } // 最大長度 if (fieldDef.validationRules.contains("maxLength")) { lineEdit->setMaxLength(fieldDef.validationRules["maxLength"].toInt()); } // 正則驗證 if (fieldDef.validationRules.contains("pattern")) { QString pattern = fieldDef.validationRules["pattern"].toString(); QRegularExpression regex(pattern); QRegularExpressionValidator *validator = new QRegularExpressionValidator(regex, lineEdit); lineEdit->setValidator(validator); } // Material Design 樣式 lineEdit->setStyleSheet( "QLineEdit {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: white;" " font-size: 14px;" " color: #212121;" "}" "QLineEdit:focus {" " border: 2px solid #2196F3;" "}" "QLineEdit:disabled {" " background-color: #FAFAFA;" " color: #9E9E9E;" "}"); return lineEdit; } QWidget *TableWidgetFactory::createSelectionField(const FieldDefinition &fieldDef, QWidget *parent) { QComboBox *comboBox = new QComboBox(parent); // 添加選項 for (const QString &option : fieldDef.options) { comboBox->addItem(option); } // 默認值 if (fieldDef.defaultValue.isValid()) { int index = comboBox->findText(fieldDef.defaultValue.toString()); if (index >= 0) { comboBox->setCurrentIndex(index); } } // Material Design 樣式 comboBox->setStyleSheet( "QComboBox {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: white;" " font-size: 14px;" " color: #212121;" "}" "QComboBox:hover {" " border-color: #BDBDBD;" "}" "QComboBox:focus {" " border: 2px solid #2196F3;" "}"); return comboBox; } QWidget *TableWidgetFactory::createBooleanField(const FieldDefinition &fieldDef, QWidget *parent) { QCheckBox *checkBox = new QCheckBox(parent); // 默認值 if (fieldDef.defaultValue.isValid()) { checkBox->setChecked(fieldDef.defaultValue.toBool()); } // Material Design 樣式 checkBox->setStyleSheet( "QCheckBox { font-size: 14px; color: #455A64; spacing: 8px; }" "QCheckBox::indicator { width: 22px; height: 22px; border: 2px solid #BDBDBD; border-radius: 4px; background: white; }" "QCheckBox::indicator:checked { background: #2196F3; border-color: #2196F3; }" "QCheckBox::indicator:hover { border-color: #2196F3; }"); return checkBox; } QWidget *TableWidgetFactory::createDateTimeField(const FieldDefinition &fieldDef, QWidget *parent) { QDateTimeEdit *dateTimeEdit = new QDateTimeEdit(parent); dateTimeEdit->setCalendarPopup(true); dateTimeEdit->setDisplayFormat("yyyy-MM-dd HH:mm:ss"); // 默認值 if (fieldDef.defaultValue.isValid()) { dateTimeEdit->setDateTime(fieldDef.defaultValue.toDateTime()); } else { dateTimeEdit->setDateTime(QDateTime::currentDateTime()); } // Material Design 樣式 dateTimeEdit->setStyleSheet( "QDateTimeEdit {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: white;" " font-size: 14px;" " color: #212121;" "}" "QDateTimeEdit:focus {" " border: 2px solid #2196F3;" "}"); return dateTimeEdit; } QWidget *TableWidgetFactory::createCalculatedField(const FieldDefinition &fieldDef, QWidget *parent) { Q_UNUSED(fieldDef); QLineEdit *lineEdit = new QLineEdit(parent); lineEdit->setReadOnly(true); lineEdit->setPlaceholderText("計算字段"); // Material Design 只讀樣式 lineEdit->setStyleSheet( "QLineEdit {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: #FAFAFA;" " color: #9E9E9E;" " font-size: 14px;" "}"); return lineEdit; } void TableWidgetFactory::connectFieldSignals(QWidget *fieldWidget, const QString &fieldId, QWidget *tableWidget) { if (QDoubleSpinBox *spinBox = qobject_cast(fieldWidget)) { connect(spinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this, fieldId, tableWidget](double value) { emit fieldValueChanged(tableWidget, fieldId, value); }); } else if (QLineEdit *lineEdit = qobject_cast(fieldWidget)) { connect(lineEdit, &QLineEdit::textChanged, this, [this, fieldId, tableWidget](const QString &text) { emit fieldValueChanged(tableWidget, fieldId, text); }); } else if (QComboBox *comboBox = qobject_cast(fieldWidget)) { connect(comboBox, &QComboBox::currentTextChanged, this, [this, fieldId, tableWidget](const QString &text) { emit fieldValueChanged(tableWidget, fieldId, text); }); } else if (QCheckBox *checkBox = qobject_cast(fieldWidget)) { connect(checkBox, &QCheckBox::toggled, this, [this, fieldId, tableWidget](bool checked) { emit fieldValueChanged(tableWidget, fieldId, checked); }); } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(fieldWidget)) { connect(dateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, [this, fieldId, tableWidget](const QDateTime &dateTime) { emit fieldValueChanged(tableWidget, fieldId, dateTime); }); } } void TableWidgetFactory::applyStaticCells(QWidget *tableWidget, const TableDefinition &tableDef) { if (!tableData.contains(tableWidget) || tableDef.staticCells.isEmpty()) { return; } const TableWidgetData &data = tableData[tableWidget]; for (const StaticCell &staticCell : tableDef.staticCells) { if (tableDef.tableType == "form" || tableDef.tableType == "series") { // 處理 form/series 類型表格 if (!staticCell.field.isEmpty() && data.fieldWidgets.contains(staticCell.field)) { QWidget *fieldWidget = data.fieldWidgets[staticCell.field]; // 設置靜態內容並設為只讀 - Material Design 風格 if (QLineEdit *lineEdit = qobject_cast(fieldWidget)) { lineEdit->setText(staticCell.content); lineEdit->setReadOnly(true); lineEdit->setStyleSheet( "QLineEdit {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: #FAFAFA;" " color: #616161;" " font-size: 14px;" "}"); } else if (QDoubleSpinBox *spinBox = qobject_cast(fieldWidget)) { spinBox->setValue(staticCell.content.toDouble()); spinBox->setReadOnly(true); spinBox->setStyleSheet( "QDoubleSpinBox {" " padding: 10px 12px;" " border: 1px solid #E0E0E0;" " border-radius: 8px;" " background-color: #FAFAFA;" " color: #616161;" " font-size: 14px;" "}"); } else if (QComboBox *comboBox = qobject_cast(fieldWidget)) { int index = comboBox->findText(staticCell.content); if (index >= 0) { comboBox->setCurrentIndex(index); } comboBox->setEnabled(false); } else if (QCheckBox *checkBox = qobject_cast(fieldWidget)) { checkBox->setChecked(staticCell.content.toLower() == "true"); checkBox->setEnabled(false); } } } else if (tableDef.tableType == "grid") { // 處理 grid 類型表格 if (data.gridWidget) { QTableWidget *table = data.gridWidget; int rowIndex = staticCell.row; int colIndex = staticCell.column; if (rowIndex >= 0 && colIndex >= 0 && rowIndex < table->rowCount() && colIndex < table->columnCount()) { QTableWidgetItem *item = table->item(rowIndex, colIndex); if (!item) { item = new QTableWidgetItem(); table->setItem(rowIndex, colIndex, item); } // 設置靜態內容並設為只讀 - Material Design 風格 item->setText(staticCell.content); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setBackground(QColor("#FAFAFA")); item->setForeground(QColor("#616161")); } } } } } // ===================================================== // Form 表格數據訪問 // ===================================================== bool TableWidgetFactory::setFieldValue(QWidget *tableWidget, const QString &fieldId, const QVariant &value) { if (!tableData.contains(tableWidget)) { return false; } const TableWidgetData &data = tableData[tableWidget]; if (!data.fieldWidgets.contains(fieldId)) { return false; } QWidget *fieldWidget = data.fieldWidgets[fieldId]; if (QDoubleSpinBox *spinBox = qobject_cast(fieldWidget)) { spinBox->setValue(value.toDouble()); } else if (QLineEdit *lineEdit = qobject_cast(fieldWidget)) { lineEdit->setText(value.toString()); } else if (QComboBox *comboBox = qobject_cast(fieldWidget)) { int index = comboBox->findText(value.toString()); if (index >= 0) { comboBox->setCurrentIndex(index); } } else if (QCheckBox *checkBox = qobject_cast(fieldWidget)) { checkBox->setChecked(value.toBool()); } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(fieldWidget)) { dateTimeEdit->setDateTime(value.toDateTime()); } else { return false; } return true; } QVariant TableWidgetFactory::getFieldValue(QWidget *tableWidget, const QString &fieldId) const { if (!tableData.contains(tableWidget)) { return QVariant(); } const TableWidgetData &data = tableData[tableWidget]; if (!data.fieldWidgets.contains(fieldId)) { return QVariant(); } QWidget *fieldWidget = data.fieldWidgets[fieldId]; if (QDoubleSpinBox *spinBox = qobject_cast(fieldWidget)) { return spinBox->value(); } else if (QLineEdit *lineEdit = qobject_cast(fieldWidget)) { return lineEdit->text(); } else if (QComboBox *comboBox = qobject_cast(fieldWidget)) { return comboBox->currentText(); } else if (QCheckBox *checkBox = qobject_cast(fieldWidget)) { return checkBox->isChecked(); } else if (QDateTimeEdit *dateTimeEdit = qobject_cast(fieldWidget)) { return dateTimeEdit->dateTime(); } return QVariant(); } // ===================================================== // Grid 表格數據訪問 // ===================================================== bool TableWidgetFactory::setCellValue(QWidget *tableWidget, const QString &rowId, const QString &columnId, const QVariant &value) { if (!tableData.contains(tableWidget)) { qWarning() << "setCellValue: tableWidget not found in tableData"; return false; } const TableWidgetData &data = tableData[tableWidget]; if (!data.gridWidget) { qWarning() << "setCellValue: gridWidget is null"; return false; } QTableWidget *table = data.gridWidget; const TableDefinition &tableDef = data.definition; // 查找行索引 int rowIndex = -1; for (int i = 0; i < tableDef.rowHeaders.size(); ++i) { if (tableDef.rowHeaders[i].first == rowId) { rowIndex = i; break; } } // 查找列索引 int colIndex = -1; for (int i = 0; i < tableDef.columnHeaders.size(); ++i) { if (tableDef.columnHeaders[i].id == columnId) { colIndex = i; break; } } if (rowIndex >= 0 && colIndex >= 0 && rowIndex < table->rowCount() && colIndex < table->columnCount()) { QTableWidgetItem *item = table->item(rowIndex, colIndex); if (!item) { item = new QTableWidgetItem(); table->setItem(rowIndex, colIndex, item); } item->setText(value.toString()); return true; } qWarning() << "setCellValue: Invalid row/column index or out of bounds"; return false; } QVariant TableWidgetFactory::getCellValue(QWidget *tableWidget, const QString &rowId, const QString &columnId) const { if (!tableData.contains(tableWidget)) { return QVariant(); } const TableWidgetData &data = tableData[tableWidget]; if (!data.gridWidget) { return QVariant(); } QTableWidget *table = data.gridWidget; const TableDefinition &tableDef = data.definition; // 查找索引 int rowIndex = -1; for (int i = 0; i < tableDef.rowHeaders.size(); ++i) { if (tableDef.rowHeaders[i].first == rowId) { rowIndex = i; break; } } int colIndex = -1; for (int i = 0; i < tableDef.columnHeaders.size(); ++i) { if (tableDef.columnHeaders[i].id == columnId) { colIndex = i; break; } } if (rowIndex >= 0 && colIndex >= 0) { QTableWidgetItem *item = table->item(rowIndex, colIndex); if (item) { return item->text(); } } return QVariant(); } // ===================================================== // 通用方法 // ===================================================== TableDefinition TableWidgetFactory::getTableDefinition(QWidget *tableWidget) const { if (tableData.contains(tableWidget)) { return tableData[tableWidget].definition; } return TableDefinition(); } bool TableWidgetFactory::loadDataFromEngine(QWidget *tableWidget, const QString &tableRef, const QVariantMap &engineData) { if (!tableData.contains(tableWidget)) { qWarning() << "loadDataFromEngine: tableWidget not found in tableData"; return false; } const TableWidgetData &data = tableData[tableWidget]; const TableDefinition &tableDef = data.definition; qDebug() << "Loading engine data into table widget - tableRef:" << tableRef << "entries:" << engineData.size() << "tableType:" << tableDef.tableType; if (engineData.isEmpty()) { qDebug() << " No data to load"; return true; } // 批量加載時阻斷信號 bool containerSignalsBlocked = tableWidget->signalsBlocked(); tableWidget->blockSignals(true); bool gridSignalsBlocked = false; if (data.gridWidget) { gridSignalsBlocked = data.gridWidget->signalsBlocked(); data.gridWidget->blockSignals(true); } // 阻斷字段組件信號 QList fieldSignalStates; for (auto it = data.fieldWidgets.begin(); it != data.fieldWidgets.end(); ++it) { fieldSignalStates.append(it.value()->signalsBlocked()); it.value()->blockSignals(true); } bool success = true; if (tableDef.tableType == "form") { // 加載表單字段 for (auto it = engineData.begin(); it != engineData.end(); ++it) { qDebug() << " Loading form field:" << it.key() << "=" << it.value(); if (!setFieldValue(tableWidget, it.key(), it.value())) { qWarning() << " Failed to set form field:" << it.key(); success = false; } } } else if (tableDef.tableType == "grid") { // 加載網格單元格 for (auto it = engineData.begin(); it != engineData.end(); ++it) { QStringList parts = it.key().split("_"); if (parts.size() == 2) { QString rowId = parts[0]; QString colId = parts[1]; qDebug() << " Loading grid cell:" << rowId << "," << colId << "=" << it.value(); if (!setCellValue(tableWidget, rowId, colId, it.value())) { qWarning() << " Failed to set grid cell:" << rowId << "," << colId; success = false; } } else { qWarning() << " Invalid cell key format:" << it.key(); } } } else if (tableDef.tableType == "series") { // 時序數據格式:timestamp_fieldId -> value QMap timePoints; for (auto it = engineData.begin(); it != engineData.end(); ++it) { QStringList parts = it.key().split("_", Qt::KeepEmptyParts); if (parts.size() >= 2) { QString timestamp = parts[0]; QString fieldId = parts.mid(1).join("_"); if (!timePoints.contains(timestamp)) { timePoints[timestamp] = QVariantMap(); } timePoints[timestamp][fieldId] = it.value(); } } // 按時間順序添加數據點 QStringList timestamps = timePoints.keys(); timestamps.sort(); for (const QString ×tampStr : timestamps) { QDateTime timestamp = QDateTime::fromString(timestampStr, Qt::ISODate); if (!timestamp.isValid()) { timestamp = QDateTime::fromString(timestampStr, "yyyy-MM-dd hh:mm:ss.zzz"); } if (!timestamp.isValid()) { qWarning() << " Invalid timestamp format:" << timestampStr; continue; } if (!addSeriesDataPoint(tableWidget, timestamp, timePoints[timestampStr])) { qWarning() << " Failed to add series data point for timestamp:" << timestampStr; success = false; } } } // 恢復信號狀態 tableWidget->blockSignals(containerSignalsBlocked); if (data.gridWidget) { data.gridWidget->blockSignals(gridSignalsBlocked); } int i = 0; for (auto it = data.fieldWidgets.begin(); it != data.fieldWidgets.end(); ++it) { if (i < fieldSignalStates.size()) { it.value()->blockSignals(fieldSignalStates[i]); } i++; } qDebug() << "Finished loading engine data - success:" << success; return success; } // ===================================================== // Series 表格特有方法 // ===================================================== bool TableWidgetFactory::addSeriesDataPoint(QWidget *tableWidget, const QDateTime ×tamp, const QVariantMap &fieldValues) { if (!tableData.contains(tableWidget)) { qWarning() << "addSeriesDataPoint: tableWidget not found in tableData"; return false; } const TableWidgetData &data = tableData[tableWidget]; if (!data.seriesWidget || data.definition.tableType != "series") { qWarning() << "addSeriesDataPoint: not a series table or seriesWidget is null"; return false; } QTableWidget *table = data.seriesWidget; const TableDefinition &tableDef = data.definition; // 添加新行 int newRow = table->rowCount(); table->insertRow(newRow); // 設置時間戳(第一列)- Material Design 風格 QTableWidgetItem *timestampItem = new QTableWidgetItem(timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz")); timestampItem->setFlags(timestampItem->flags() & ~Qt::ItemIsEditable); timestampItem->setBackground(QColor("#FAFAFA")); table->setItem(newRow, 0, timestampItem); // 設置字段值 for (int i = 0; i < tableDef.fields.size(); ++i) { const FieldDefinition &fieldDef = tableDef.fields[i]; QVariant value = fieldValues.value(fieldDef.id); QTableWidgetItem *item = new QTableWidgetItem(); if (value.isValid()) { if (fieldDef.type == "numeric") { item->setText(QString::number(value.toDouble(), 'f', 3)); item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); } else { item->setText(value.toString()); } } // 設為只讀 item->setFlags(item->flags() & ~Qt::ItemIsEditable); table->setItem(newRow, i + 1, item); } // 自動滾動到底部 table->scrollToBottom(); return true; } void TableWidgetFactory::clearSeriesData(QWidget *tableWidget) { if (!tableData.contains(tableWidget)) { return; } const TableWidgetData &data = tableData[tableWidget]; if (!data.seriesWidget || data.definition.tableType != "series") { return; } data.seriesWidget->setRowCount(0); } // ===================================================== // 驗證與控制 // ===================================================== bool TableWidgetFactory::validateField(QWidget *tableWidget, const QString &fieldId) const { if (!tableData.contains(tableWidget)) { return false; } const TableWidgetData &data = tableData[tableWidget]; const TableDefinition &tableDef = data.definition; // 查找字段定義 FieldDefinition fieldDef; bool found = false; if (tableDef.tableType == "form") { for (const FieldDefinition &def : tableDef.fields) { if (def.id == fieldId) { fieldDef = def; found = true; break; } } } else if (tableDef.tableType == "grid") { for (const FieldDefinition &def : tableDef.columnHeaders) { if (def.id == fieldId) { fieldDef = def; found = true; break; } } } if (!found) { return false; } // 獲取當前值 QVariant value; if (tableDef.tableType == "form") { value = getFieldValue(tableWidget, fieldId); } else { return true; // Grid 驗證需要更多上下文 } // 基本驗證規則 if (fieldDef.isRequired && (!value.isValid() || value.toString().isEmpty())) { return false; } // 類型特定驗證 if (fieldDef.type == "numeric") { bool ok; double numValue = value.toDouble(&ok); if (!ok) { return false; } // 範圍驗證 if (fieldDef.validationRules.contains("min")) { double minVal = fieldDef.validationRules["min"].toDouble(); if (numValue < minVal) { return false; } } if (fieldDef.validationRules.contains("max")) { double maxVal = fieldDef.validationRules["max"].toDouble(); if (numValue > maxVal) { return false; } } } else if (fieldDef.type == "text") { QString textValue = value.toString(); // 最大長度驗證 if (fieldDef.validationRules.contains("maxLength")) { int maxLen = fieldDef.validationRules["maxLength"].toInt(); if (textValue.length() > maxLen) { return false; } } // 正則驗證 if (fieldDef.validationRules.contains("pattern")) { QString pattern = fieldDef.validationRules["pattern"].toString(); QRegularExpression regex(pattern); if (!regex.match(textValue).hasMatch()) { return false; } } } return true; } void TableWidgetFactory::enableManualInput(QWidget *tableWidget, bool enabled) { if (!tableData.contains(tableWidget)) { return; } const TableWidgetData &data = tableData[tableWidget]; const TableDefinition &tableDef = data.definition; if (tableDef.tableType == "form") { // 啟用/禁用所有字段組件 for (auto it = data.fieldWidgets.begin(); it != data.fieldWidgets.end(); ++it) { QWidget *fieldWidget = it.value(); if (fieldWidget) { QString fieldId = it.key(); bool isReadOnly = false; for (const FieldDefinition &fieldDef : tableDef.fields) { if (fieldDef.id == fieldId) { isReadOnly = fieldDef.isReadOnly || fieldDef.type == "calculated"; break; } } // 只對非只讀字段操作 if (!isReadOnly) { fieldWidget->setEnabled(enabled); } } } } else if (tableDef.tableType == "grid" && data.gridWidget) { QTableWidget *table = data.gridWidget; // 啟用/禁用非只讀單元格 for (int row = 0; row < table->rowCount(); ++row) { for (int col = 0; col < table->columnCount(); ++col) { QTableWidgetItem *item = table->item(row, col); if (item) { bool isReadOnly = false; if (col < tableDef.columnHeaders.size()) { const FieldDefinition &colDef = tableDef.columnHeaders[col]; isReadOnly = colDef.isReadOnly || colDef.type == "calculated"; } if (enabled && !isReadOnly) { item->setFlags(item->flags() | Qt::ItemIsEditable); } else { item->setFlags(item->flags() & ~Qt::ItemIsEditable); } } } } } else if (tableDef.tableType == "series" && data.seriesWidget) { // Series 表格通常是只讀的 data.seriesWidget->setEnabled(enabled); } }