|
- #include "free_monitor_widget.h"
-
- #include "services/register_monitor_service.h"
- #include "toolbar_icon_factory.h"
- #include "ui_free_monitor_widget.h"
-
- #include <QComboBox>
- #include <QHeaderView>
- #include <QIntValidator>
- #include <QLineEdit>
- #include <QMessageBox>
- #include <QPushButton>
- #include <QTableWidgetItem>
-
- #include <cstdint>
- #include <set>
-
- namespace {
-
- QString fromUtf8(const std::string &value)
- {
- return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
- }
-
- QString addressText(const RegisterAddress &address)
- {
- return QString::fromStdString(address.toString());
- }
-
- } // namespace
-
- FreeMonitorWidget::FreeMonitorWidget(
- RegisterMonitorService &service,
- QWidget *parent)
- : QWidget(parent),
- ui_(std::make_unique<Ui::FreeMonitorWidget>()),
- service_(service)
- {
- ui_->setupUi(this);
- ui_->removeButton->setIcon(makeUiIcon(UiIcon::Delete));
- ui_->clearButton->setIcon(makeUiIcon(UiIcon::ClearList));
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
- ui_->monitorTable->horizontalHeader()->setSectionResizeMode(5, QHeaderView::Stretch);
- ui_->monitorTable->verticalHeader()->setVisible(false);
- connect(ui_->addButton, &QPushButton::clicked, this, &FreeMonitorWidget::addAddresses);
- connect(ui_->addressEdit, &QLineEdit::returnPressed,
- this, &FreeMonitorWidget::addAddresses);
- connect(ui_->removeButton, &QToolButton::clicked,
- this, &FreeMonitorWidget::removeSelectedAddresses);
- connect(ui_->clearButton, &QToolButton::clicked,
- this, &FreeMonitorWidget::clearAddresses);
- reloadAddresses();
- }
-
- FreeMonitorWidget::~FreeMonitorWidget() = default;
-
- void FreeMonitorWidget::setWriteEnabled(bool enabled)
- {
- write_enabled_ = enabled;
- updateWriteControls();
- }
-
- void FreeMonitorWidget::refreshValues(
- ApplicationMode mode, PlcConnectionState plc_state)
- {
- QString source = tr("数据源:未启用");
- bool values_available = false;
- bool communication_fault = false;
- if (mode == ApplicationMode::OfflineRunning)
- {
- source = tr("数据源:虚拟 M/D");
- values_available = true;
- }
- else if (mode == ApplicationMode::OnlineRunning)
- {
- source = tr("数据源:PLC 缓存");
- values_available = true;
- communication_fault = plc_state == PlcConnectionState::Faulted;
- }
- ui_->sourceLabel->setText(source);
-
- const std::vector<MonitorValue> values = values_available
- ? service_.values(communication_fault) : std::vector<MonitorValue>{};
- for (int row = 0; row < ui_->monitorTable->rowCount(); ++row)
- {
- QTableWidgetItem *value_item = ui_->monitorTable->item(row, 2);
- QTableWidgetItem *state_item = ui_->monitorTable->item(row, 5);
- if (!values_available || static_cast<std::size_t>(row) >= values.size())
- {
- value_item->setText(QStringLiteral("--"));
- state_item->setText(tr("未运行"));
- continue;
- }
- const MonitorValue &value = values.at(static_cast<std::size_t>(row));
- if (value.state == MonitorValueState::Unavailable)
- {
- value_item->setText(QStringLiteral("--"));
- state_item->setText(mode == ApplicationMode::OnlineRunning
- ? tr("等待读取") : tr("不可用"));
- continue;
- }
- value_item->setText(value.address.area() == RegisterArea::M
- ? (value.bitValue ? QStringLiteral("ON")
- : QStringLiteral("OFF"))
- : QString::number(value.wordValue));
- state_item->setText(value.state == MonitorValueState::CommunicationFault
- ? tr("通信故障,最后有效值") : tr("有效"));
- }
- updateWriteControls();
- }
-
- void FreeMonitorWidget::reloadAddresses()
- {
- const std::vector<RegisterAddress> &addresses = service_.addresses();
- ui_->monitorTable->setRowCount(static_cast<int>(addresses.size()));
- for (std::size_t index = 0; index < addresses.size(); ++index)
- {
- const RegisterAddress &address = addresses[index];
- const int row = static_cast<int>(index);
- ui_->monitorTable->setItem(row, 0, new QTableWidgetItem(addressText(address)));
- ui_->monitorTable->setItem(
- row, 1, new QTableWidgetItem(address.area() == RegisterArea::M
- ? tr("位") : tr("16 位整数")));
- ui_->monitorTable->setItem(row, 2, new QTableWidgetItem(QStringLiteral("--")));
- if (address.area() == RegisterArea::M)
- {
- auto *target = new QComboBox(ui_->monitorTable);
- target->addItem(tr("OFF"), false);
- target->addItem(tr("ON"), true);
- ui_->monitorTable->setCellWidget(row, 3, target);
- }
- else
- {
- auto *target = new QLineEdit(ui_->monitorTable);
- target->setValidator(new QIntValidator(-32768, 32767, target));
- target->setText(QStringLiteral("0"));
- target->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
- ui_->monitorTable->setCellWidget(row, 3, target);
- }
- auto *write_button = new QPushButton(tr("写入"), ui_->monitorTable);
- write_button->setProperty("monitorRow", row);
- connect(write_button, &QPushButton::clicked, this,
- [this, write_button]
- {
- writeRow(write_button->property("monitorRow").toInt());
- });
- ui_->monitorTable->setCellWidget(row, 4, write_button);
- ui_->monitorTable->setItem(row, 5, new QTableWidgetItem(tr("未运行")));
- }
- updateWriteControls();
- }
-
- void FreeMonitorWidget::writeRow(int row)
- {
- if (!write_enabled_ || row < 0
- || static_cast<std::size_t>(row) >= service_.addresses().size())
- {
- return;
- }
-
- const RegisterAddress address = service_.addresses().at(static_cast<std::size_t>(row));
- RegisterMonitorWriteResult result;
- if (address.area() == RegisterArea::M)
- {
- auto *target = qobject_cast<QComboBox *>(ui_->monitorTable->cellWidget(row, 3));
- if (target == nullptr)
- {
- return;
- }
- result = service_.writeBit(address, target->currentData().toBool());
- }
- else
- {
- auto *target = qobject_cast<QLineEdit *>(ui_->monitorTable->cellWidget(row, 3));
- if (target == nullptr)
- {
- return;
- }
- bool converted = false;
- const int value = target->text().toInt(&converted);
- if (!converted || value < -32768 || value > 32767)
- {
- ui_->monitorTable->item(row, 5)->setText(tr("目标值无效"));
- emit operationMessage(tr("写入 D 区地址失败:请输入 -32768~32767 的整数"));
- return;
- }
- result = service_.writeWord(address, static_cast<std::int16_t>(value));
- }
-
- QTableWidgetItem *state_item = ui_->monitorTable->item(row, 5);
- if (result.succeeded)
- {
- state_item->setText(tr("写入请求已发送"));
- emit operationMessage(tr("%1 写入请求已发送,等待当前值刷新")
- .arg(addressText(address)));
- return;
- }
- state_item->setText(tr("写入失败"));
- handleResult(tr("写入 %1").arg(addressText(address)), false, result.message);
- }
-
- void FreeMonitorWidget::updateWriteControls()
- {
- for (int row = 0; row < ui_->monitorTable->rowCount(); ++row)
- {
- QWidget *target = ui_->monitorTable->cellWidget(row, 3);
- if (target != nullptr)
- {
- target->setEnabled(write_enabled_);
- }
- QWidget *write_button = ui_->monitorTable->cellWidget(row, 4);
- if (write_button != nullptr)
- {
- write_button->setEnabled(write_enabled_);
- }
- }
- }
-
- void FreeMonitorWidget::addAddresses()
- {
- const QByteArray address = ui_->addressEdit->text().toUtf8();
- const RegisterMonitorResult result = service_.addRange(
- std::string(address.constData(), static_cast<std::size_t>(address.size())),
- ui_->countSpinBox->value());
- if (result.succeeded)
- {
- reloadAddresses();
- ui_->addressEdit->selectAll();
- emit monitorAddressesChanged();
- emit operationMessage(tr("已添加 %1 个监控地址").arg(result.affectedCount));
- return;
- }
- handleResult(tr("添加监控地址"), false, result.message);
- }
-
- void FreeMonitorWidget::removeSelectedAddresses()
- {
- std::set<int> rows;
- for (const QModelIndex &index : ui_->monitorTable->selectionModel()->selectedRows())
- {
- rows.insert(index.row());
- }
- std::vector<RegisterAddress> addresses;
- const std::vector<RegisterAddress> &all_addresses = service_.addresses();
- for (int row : rows)
- {
- if (row >= 0 && static_cast<std::size_t>(row) < all_addresses.size())
- {
- addresses.push_back(all_addresses.at(static_cast<std::size_t>(row)));
- }
- }
- const RegisterMonitorResult result = service_.remove(addresses);
- if (result.succeeded)
- {
- reloadAddresses();
- emit monitorAddressesChanged();
- emit operationMessage(tr("已删除 %1 个监控地址").arg(result.affectedCount));
- return;
- }
- handleResult(tr("删除监控地址"), false, result.message);
- }
-
- void FreeMonitorWidget::clearAddresses()
- {
- if (service_.addresses().empty())
- {
- return;
- }
- if (QMessageBox::question(
- this, tr("清空自由监控"), tr("确定清空当前监控表吗?"))
- != QMessageBox::Yes)
- {
- return;
- }
- const RegisterMonitorResult result = service_.clear();
- if (result.succeeded)
- {
- reloadAddresses();
- emit monitorAddressesChanged();
- emit operationMessage(tr("自由监控已清空"));
- return;
- }
- handleResult(tr("清空自由监控"), false, result.message);
- }
-
- void FreeMonitorWidget::handleResult(
- const QString &action, bool succeeded, const std::string &message)
- {
- if (!succeeded)
- {
- emit operationMessage(action + QStringLiteral(":") + fromUtf8(message));
- }
- }
|