#include "runtime_monitor_widget.h" #include "free_monitor_widget.h" #include "hmi_editor_widget.h" #include "logic_editor_widget.h" #include "services/hmi_navigation_service.h" #include "services/alarm_service.h" #include "services/project_service.h" #include "toolbar_icon_factory.h" #include "ui_runtime_monitor_widget.h" #include #include #include #include #include #include namespace { QString fromUtf8(const std::string &value) { return QString::fromUtf8(value.data(), static_cast(value.size())); } std::string toUtf8(const QString &value) { const QByteArray bytes = value.toUtf8(); return std::string(bytes.constData(), static_cast(bytes.size())); } } // namespace RuntimeMonitorWidget::RuntimeMonitorWidget( HmiEditorService &hmi_editor_service, HmiRuntimeService &hmi_runtime_service, LogicEditorService &logic_editor_service, ProjectService &project_service, HmiNavigationService &hmi_navigation_service, AlarmService &alarm_service, RegisterMonitorService ®ister_monitor_service, QWidget *parent) : QWidget(parent), ui_(std::make_unique()), project_service_(project_service), hmi_navigation_service_(hmi_navigation_service) { ui_->setupUi(this); ui_->exitRuntimeButton->setIcon(makeUiIcon(UiIcon::Exit)); hmi_view_ = new HmiEditorWidget( hmi_editor_service, hmi_runtime_service, alarm_service, ui_->hmiViewContainer); hmi_view_->setObjectName(QStringLiteral("runtimeHmiView")); hmi_view_->setEditingEnabled(false); hmi_view_->setRuntimeActive(true); ui_->hmiViewLayout->addWidget(hmi_view_); logic_view_ = new LogicEditorWidget(logic_editor_service, ui_->logicViewContainer); logic_view_->setObjectName(QStringLiteral("runtimeLogicView")); logic_view_->setEditingEnabled(false); ui_->logicViewLayout->addWidget(logic_view_); free_monitor_widget_ = new FreeMonitorWidget( register_monitor_service, ui_->monitorContainer); free_monitor_widget_->setObjectName(QStringLiteral("freeMonitorWidget")); ui_->monitorContainerLayout->addWidget(free_monitor_widget_); ui_->logicNoticeLabel->setVisible(false); ui_->runtimeModeComboBox->setVisible(false); ui_->runtimePlcButton->setVisible(false); ui_->runtimeDisconnectPlcButton->setVisible(false); ui_->upperSplitter->setSizes({600, 600}); ui_->verticalSplitter->setSizes({440, 260}); connect(hmi_view_, &HmiEditorWidget::pageNavigationRequested, this, [this](const QString &target_page_id) { const HmiNavigationResult result = hmi_navigation_service_.navigateTo(toUtf8(target_page_id)); if (!result.succeeded) { emit navigationFailed(fromUtf8(result.message)); return; } showRuntimePage(result.pageId); }); connect(ui_->exitRuntimeButton, &QToolButton::clicked, this, &RuntimeMonitorWidget::exitRequested); connect(ui_->runtimeLogicComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { if (index >= 0) { selectRuntimeLogic(toUtf8( ui_->runtimeLogicComboBox->itemData(index).toString())); } }); connect(ui_->runtimeModeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { if (user_runtime_mode_ && index >= 0) { emit modeChangeRequested(index == 0 ? static_cast(ApplicationMode::OfflineRunning) : static_cast(ApplicationMode::OnlineRunning)); } }); connect(ui_->runtimePlcButton, &QPushButton::clicked, this, &RuntimeMonitorWidget::plcConfigurationRequested); connect(ui_->runtimeDisconnectPlcButton, &QPushButton::clicked, this, &RuntimeMonitorWidget::plcDisconnectRequested); } RuntimeMonitorWidget::~RuntimeMonitorWidget() = default; void RuntimeMonitorWidget::setProjectObjects( const std::string &page_id, const std::string &logic_id) { setRuntimePage(page_id); const QSignalBlocker blocker(ui_->runtimeLogicComboBox); ui_->runtimeLogicComboBox->clear(); for (const ControlLogic &logic : project_service_.project().controlLogics) { if (logic.enabled) { ui_->runtimeLogicComboBox->addItem( fromUtf8(logic.name), fromUtf8(logic.id)); } } int selected_index = ui_->runtimeLogicComboBox->findData(fromUtf8(logic_id)); if (selected_index < 0 && ui_->runtimeLogicComboBox->count() > 0) { selected_index = 0; } ui_->runtimeLogicComboBox->setCurrentIndex(selected_index); selectRuntimeLogic(selected_index >= 0 ? toUtf8(ui_->runtimeLogicComboBox->itemData(selected_index).toString()) : std::string{}); } void RuntimeMonitorWidget::setRuntimePage(const std::string &page_id) { showRuntimePage(page_id); } void RuntimeMonitorWidget::setMode( ApplicationMode mode, PlcConnectionState plc_state) { const bool offline = mode == ApplicationMode::OfflineRunning; const bool online = mode == ApplicationMode::OnlineRunning; ui_->logicFrame->setVisible(offline || online); hmi_view_->setRuntimeActive(offline || online); if (!offline && !online) { setHmiWriteEnabled(false); } setFreeMonitorWriteEnabled(offline || (online && plc_state == PlcConnectionState::Connected)); if (!offline && !online) { logic_view_->clearRuntimeTrace(); latest_trace_.clear(); latest_fault_node_id_.clear(); has_logic_trace_ = false; } ui_->logicLabel->setText( online ? tr("本地推算轨迹") : tr("梯形图运行状态")); ui_->logicNoticeLabel->setVisible(online); ui_->modeLabel->setText( offline ? tr("离线仿真 · 虚拟 M/D") : online ? tr("真机运行 · PLC 缓存 · 本地推算轨迹") : tr("当前未运行")); if (user_runtime_mode_) { const QSignalBlocker blocker(ui_->runtimeModeComboBox); ui_->runtimeModeComboBox->setCurrentIndex( offline ? 0 : online ? 1 : -1); const bool plc_configurable = plc_state == PlcConnectionState::Disconnected || plc_state == PlcConnectionState::Faulted; ui_->runtimePlcButton->setEnabled(plc_configurable); ui_->runtimeDisconnectPlcButton->setEnabled( plc_state != PlcConnectionState::Disconnected); } free_monitor_widget_->refreshValues(mode, plc_state); } void RuntimeMonitorWidget::setUserRuntimeMode(bool enabled) { user_runtime_mode_ = enabled; ui_->runtimeModeComboBox->setVisible(enabled); ui_->runtimePlcButton->setVisible(enabled); ui_->runtimeDisconnectPlcButton->setVisible(enabled); ui_->exitRuntimeButton->setToolTip( enabled ? tr("退出运行程序") : tr("返回编辑态")); ui_->exitRuntimeButton->setAccessibleName( enabled ? tr("退出运行程序") : tr("返回编辑态")); if (enabled) { setMode(ApplicationMode::Editing, PlcConnectionState::Disconnected); } } void RuntimeMonitorWidget::setHmiWriteEnabled(bool enabled) { hmi_view_->setRuntimeWriteEnabled(enabled); } void RuntimeMonitorWidget::setFreeMonitorWriteEnabled(bool enabled) { free_monitor_widget_->setWriteEnabled(enabled); } void RuntimeMonitorWidget::refreshValues( ApplicationMode mode, PlcConnectionState plc_state) { // HMI、报警和自由监控共享同一个活动寄存器仓库 hmi_view_->refreshRuntimeValues(); free_monitor_widget_->refreshValues(mode, plc_state); } void RuntimeMonitorWidget::setLogicTrace( const LogicTraceSnapshot &trace, const std::string &fault_node_id) { latest_trace_ = trace; latest_fault_node_id_ = fault_node_id; has_logic_trace_ = true; logic_view_->setRuntimeTrace( trace.forLogic(selected_logic_id_), fault_node_id); } FreeMonitorWidget *RuntimeMonitorWidget::freeMonitorWidget() const { return free_monitor_widget_; } std::string RuntimeMonitorWidget::selectedLogicId() const { return selected_logic_id_; } void RuntimeMonitorWidget::showRuntimePage(const std::string &page_id) { hmi_view_->setPageId(page_id); hmi_view_->reloadPage(); const auto page = std::find_if( project_service_.project().hmiPages.cbegin(), project_service_.project().hmiPages.cend(), [&page_id](const HmiPage &candidate) { return candidate.id == page_id; }); ui_->runtimePageLabel->setText( page == project_service_.project().hmiPages.cend() ? tr("未选择页面") : fromUtf8(page->name)); } void RuntimeMonitorWidget::selectRuntimeLogic(const std::string &logic_id) { selected_logic_id_ = logic_id; logic_view_->setLogicId(logic_id); logic_view_->reloadLogic(); if (has_logic_trace_) { logic_view_->setRuntimeTrace( latest_trace_.forLogic(logic_id), latest_fault_node_id_); } }