综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

272 lines
9.2 KiB

  1. #include "runtime_monitor_widget.h"
  2. #include "free_monitor_widget.h"
  3. #include "hmi_editor_widget.h"
  4. #include "logic_editor_widget.h"
  5. #include "services/hmi_navigation_service.h"
  6. #include "services/alarm_service.h"
  7. #include "services/project_service.h"
  8. #include "toolbar_icon_factory.h"
  9. #include "ui_runtime_monitor_widget.h"
  10. #include <QSplitter>
  11. #include <QComboBox>
  12. #include <QPushButton>
  13. #include <QSignalBlocker>
  14. #include <QToolButton>
  15. #include <algorithm>
  16. namespace {
  17. QString fromUtf8(const std::string &value)
  18. {
  19. return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
  20. }
  21. std::string toUtf8(const QString &value)
  22. {
  23. const QByteArray bytes = value.toUtf8();
  24. return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));
  25. }
  26. } // namespace
  27. RuntimeMonitorWidget::RuntimeMonitorWidget(
  28. HmiEditorService &hmi_editor_service,
  29. HmiRuntimeService &hmi_runtime_service,
  30. LogicEditorService &logic_editor_service,
  31. ProjectService &project_service,
  32. HmiNavigationService &hmi_navigation_service,
  33. AlarmService &alarm_service,
  34. RegisterMonitorService &register_monitor_service,
  35. QWidget *parent)
  36. : QWidget(parent),
  37. ui_(std::make_unique<Ui::RuntimeMonitorWidget>()),
  38. project_service_(project_service),
  39. hmi_navigation_service_(hmi_navigation_service)
  40. {
  41. ui_->setupUi(this);
  42. ui_->exitRuntimeButton->setIcon(makeUiIcon(UiIcon::Exit));
  43. hmi_view_ = new HmiEditorWidget(
  44. hmi_editor_service,
  45. hmi_runtime_service,
  46. alarm_service,
  47. ui_->hmiViewContainer);
  48. hmi_view_->setObjectName(QStringLiteral("runtimeHmiView"));
  49. hmi_view_->setEditingEnabled(false);
  50. hmi_view_->setRuntimeActive(true);
  51. ui_->hmiViewLayout->addWidget(hmi_view_);
  52. logic_view_ = new LogicEditorWidget(logic_editor_service, ui_->logicViewContainer);
  53. logic_view_->setObjectName(QStringLiteral("runtimeLogicView"));
  54. logic_view_->setEditingEnabled(false);
  55. ui_->logicViewLayout->addWidget(logic_view_);
  56. free_monitor_widget_ = new FreeMonitorWidget(
  57. register_monitor_service, ui_->monitorContainer);
  58. free_monitor_widget_->setObjectName(QStringLiteral("freeMonitorWidget"));
  59. ui_->monitorContainerLayout->addWidget(free_monitor_widget_);
  60. ui_->logicNoticeLabel->setVisible(false);
  61. ui_->runtimeModeComboBox->setVisible(false);
  62. ui_->runtimePlcButton->setVisible(false);
  63. ui_->runtimeDisconnectPlcButton->setVisible(false);
  64. ui_->upperSplitter->setSizes({600, 600});
  65. ui_->verticalSplitter->setSizes({440, 260});
  66. connect(hmi_view_, &HmiEditorWidget::pageNavigationRequested,
  67. this,
  68. [this](const QString &target_page_id)
  69. {
  70. const HmiNavigationResult result =
  71. hmi_navigation_service_.navigateTo(toUtf8(target_page_id));
  72. if (!result.succeeded)
  73. {
  74. emit navigationFailed(fromUtf8(result.message));
  75. return;
  76. }
  77. showRuntimePage(result.pageId);
  78. });
  79. connect(ui_->exitRuntimeButton, &QToolButton::clicked,
  80. this, &RuntimeMonitorWidget::exitRequested);
  81. connect(ui_->runtimeLogicComboBox,
  82. QOverload<int>::of(&QComboBox::currentIndexChanged),
  83. this,
  84. [this](int index)
  85. {
  86. if (index >= 0)
  87. {
  88. selectRuntimeLogic(toUtf8(
  89. ui_->runtimeLogicComboBox->itemData(index).toString()));
  90. }
  91. });
  92. connect(ui_->runtimeModeComboBox,
  93. QOverload<int>::of(&QComboBox::currentIndexChanged),
  94. this,
  95. [this](int index)
  96. {
  97. if (user_runtime_mode_ && index >= 0)
  98. {
  99. emit modeChangeRequested(index == 0
  100. ? static_cast<int>(ApplicationMode::OfflineRunning)
  101. : static_cast<int>(ApplicationMode::OnlineRunning));
  102. }
  103. });
  104. connect(ui_->runtimePlcButton, &QPushButton::clicked,
  105. this, &RuntimeMonitorWidget::plcConfigurationRequested);
  106. connect(ui_->runtimeDisconnectPlcButton, &QPushButton::clicked,
  107. this, &RuntimeMonitorWidget::plcDisconnectRequested);
  108. }
  109. RuntimeMonitorWidget::~RuntimeMonitorWidget() = default;
  110. void RuntimeMonitorWidget::setProjectObjects(
  111. const std::string &page_id, const std::string &logic_id)
  112. {
  113. setRuntimePage(page_id);
  114. const QSignalBlocker blocker(ui_->runtimeLogicComboBox);
  115. ui_->runtimeLogicComboBox->clear();
  116. for (const ControlLogic &logic : project_service_.project().controlLogics)
  117. {
  118. if (logic.enabled)
  119. {
  120. ui_->runtimeLogicComboBox->addItem(
  121. fromUtf8(logic.name), fromUtf8(logic.id));
  122. }
  123. }
  124. int selected_index = ui_->runtimeLogicComboBox->findData(fromUtf8(logic_id));
  125. if (selected_index < 0 && ui_->runtimeLogicComboBox->count() > 0)
  126. {
  127. selected_index = 0;
  128. }
  129. ui_->runtimeLogicComboBox->setCurrentIndex(selected_index);
  130. selectRuntimeLogic(selected_index >= 0
  131. ? toUtf8(ui_->runtimeLogicComboBox->itemData(selected_index).toString())
  132. : std::string{});
  133. }
  134. void RuntimeMonitorWidget::setRuntimePage(const std::string &page_id)
  135. {
  136. showRuntimePage(page_id);
  137. }
  138. void RuntimeMonitorWidget::setMode(
  139. ApplicationMode mode, PlcConnectionState plc_state)
  140. {
  141. const bool offline = mode == ApplicationMode::OfflineRunning;
  142. const bool online = mode == ApplicationMode::OnlineRunning;
  143. ui_->logicFrame->setVisible(offline || online);
  144. hmi_view_->setRuntimeActive(offline || online);
  145. if (!offline && !online)
  146. {
  147. setHmiWriteEnabled(false);
  148. }
  149. setFreeMonitorWriteEnabled(offline
  150. || (online && plc_state == PlcConnectionState::Connected));
  151. if (!offline && !online)
  152. {
  153. logic_view_->clearRuntimeTrace();
  154. latest_trace_.clear();
  155. latest_fault_node_id_.clear();
  156. has_logic_trace_ = false;
  157. }
  158. ui_->logicLabel->setText(
  159. online ? tr("本地推算轨迹") : tr("梯形图运行状态"));
  160. ui_->logicNoticeLabel->setVisible(online);
  161. ui_->modeLabel->setText(
  162. offline ? tr("离线仿真 · 虚拟 M/D")
  163. : online ? tr("真机运行 · PLC 缓存 · 本地推算轨迹")
  164. : tr("当前未运行"));
  165. if (user_runtime_mode_)
  166. {
  167. const QSignalBlocker blocker(ui_->runtimeModeComboBox);
  168. ui_->runtimeModeComboBox->setCurrentIndex(
  169. offline ? 0 : online ? 1 : -1);
  170. const bool plc_configurable = plc_state == PlcConnectionState::Disconnected
  171. || plc_state == PlcConnectionState::Faulted;
  172. ui_->runtimePlcButton->setEnabled(plc_configurable);
  173. ui_->runtimeDisconnectPlcButton->setEnabled(
  174. plc_state != PlcConnectionState::Disconnected);
  175. }
  176. free_monitor_widget_->refreshValues(mode, plc_state);
  177. }
  178. void RuntimeMonitorWidget::setUserRuntimeMode(bool enabled)
  179. {
  180. user_runtime_mode_ = enabled;
  181. ui_->runtimeModeComboBox->setVisible(enabled);
  182. ui_->runtimePlcButton->setVisible(enabled);
  183. ui_->runtimeDisconnectPlcButton->setVisible(enabled);
  184. ui_->exitRuntimeButton->setToolTip(
  185. enabled ? tr("退出运行程序") : tr("返回编辑态"));
  186. ui_->exitRuntimeButton->setAccessibleName(
  187. enabled ? tr("退出运行程序") : tr("返回编辑态"));
  188. if (enabled)
  189. {
  190. setMode(ApplicationMode::Editing, PlcConnectionState::Disconnected);
  191. }
  192. }
  193. void RuntimeMonitorWidget::setHmiWriteEnabled(bool enabled)
  194. {
  195. hmi_view_->setRuntimeWriteEnabled(enabled);
  196. }
  197. void RuntimeMonitorWidget::setFreeMonitorWriteEnabled(bool enabled)
  198. {
  199. free_monitor_widget_->setWriteEnabled(enabled);
  200. }
  201. void RuntimeMonitorWidget::refreshValues(
  202. ApplicationMode mode, PlcConnectionState plc_state)
  203. {
  204. // HMI、报警和自由监控共享同一个活动寄存器仓库
  205. hmi_view_->refreshRuntimeValues();
  206. free_monitor_widget_->refreshValues(mode, plc_state);
  207. }
  208. void RuntimeMonitorWidget::setLogicTrace(
  209. const LogicTraceSnapshot &trace, const std::string &fault_node_id)
  210. {
  211. latest_trace_ = trace;
  212. latest_fault_node_id_ = fault_node_id;
  213. has_logic_trace_ = true;
  214. logic_view_->setRuntimeTrace(
  215. trace.forLogic(selected_logic_id_), fault_node_id);
  216. }
  217. FreeMonitorWidget *RuntimeMonitorWidget::freeMonitorWidget() const
  218. {
  219. return free_monitor_widget_;
  220. }
  221. std::string RuntimeMonitorWidget::selectedLogicId() const
  222. {
  223. return selected_logic_id_;
  224. }
  225. void RuntimeMonitorWidget::showRuntimePage(const std::string &page_id)
  226. {
  227. hmi_view_->setPageId(page_id);
  228. hmi_view_->reloadPage();
  229. const auto page = std::find_if(
  230. project_service_.project().hmiPages.cbegin(),
  231. project_service_.project().hmiPages.cend(),
  232. [&page_id](const HmiPage &candidate) { return candidate.id == page_id; });
  233. ui_->runtimePageLabel->setText(
  234. page == project_service_.project().hmiPages.cend()
  235. ? tr("未选择页面") : fromUtf8(page->name));
  236. }
  237. void RuntimeMonitorWidget::selectRuntimeLogic(const std::string &logic_id)
  238. {
  239. selected_logic_id_ = logic_id;
  240. logic_view_->setLogicId(logic_id);
  241. logic_view_->reloadLogic();
  242. if (has_logic_trace_)
  243. {
  244. logic_view_->setRuntimeTrace(
  245. latest_trace_.forLogic(logic_id), latest_fault_node_id_);
  246. }
  247. }