综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

622 строки
26 KiB

  1. #include "property_panel_controller.h"
  2. #include "domain/hmi_control_registry.h"
  3. #include "hmi_editor_widget.h"
  4. #include "logic_editor_widget.h"
  5. #include "logic_instruction_dialog.h"
  6. #include "services/hmi_editor_service.h"
  7. #include "services/logic_editor_service.h"
  8. #include "services/project_service.h"
  9. #include "ui_main_window.h"
  10. #include <QCheckBox>
  11. #include <QComboBox>
  12. #include <QLabel>
  13. #include <QPushButton>
  14. #include <QDialog>
  15. #include <QObject>
  16. #include <QSpinBox>
  17. #include <QStackedWidget>
  18. #include <QWidget>
  19. #include <cstdint>
  20. #include <utility>
  21. #include <vector>
  22. namespace {
  23. QString fromUtf8(const std::string &value)
  24. {
  25. return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
  26. }
  27. std::string toUtf8(const QString &value)
  28. {
  29. const QByteArray bytes = value.toUtf8();
  30. return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));
  31. }
  32. } // namespace
  33. PropertyPanelController::PropertyPanelController(
  34. QWidget &parent,
  35. Ui::MainWindow &ui,
  36. ProjectService &project_service,
  37. HmiEditorService &hmi_editor_service,
  38. LogicEditorService &logic_editor_service,
  39. std::function<std::string()> current_page_id,
  40. std::function<std::string()> current_logic_id,
  41. std::string &selected_control_id,
  42. std::string &selected_logic_node_id,
  43. std::function<void()> refresh_project_ui,
  44. ResultReporter result_reporter,
  45. StatusReporter status_reporter)
  46. : parent_(parent),
  47. ui_(ui),
  48. project_service_(project_service),
  49. hmi_editor_service_(hmi_editor_service),
  50. logic_editor_service_(logic_editor_service),
  51. current_page_id_(std::move(current_page_id)),
  52. current_logic_id_(std::move(current_logic_id)),
  53. selected_control_id_(selected_control_id),
  54. selected_logic_node_id_(selected_logic_node_id),
  55. refresh_project_ui_(std::move(refresh_project_ui)),
  56. result_reporter_(std::move(result_reporter)),
  57. status_reporter_(std::move(status_reporter))
  58. {
  59. }
  60. void PropertyPanelController::configure()
  61. {
  62. ui_.bindingAreaComboBox->setItemData(0, -1);
  63. ui_.bindingAreaComboBox->setItemData(1, 0);
  64. ui_.bindingAreaComboBox->setItemData(2, 1);
  65. ui_.buttonOperationComboBox->setItemData(
  66. 0, static_cast<int>(HmiButtonOperation::SetOn));
  67. ui_.buttonOperationComboBox->setItemData(
  68. 1, static_cast<int>(HmiButtonOperation::SetOff));
  69. ui_.buttonOperationComboBox->setItemData(
  70. 2, static_cast<int>(HmiButtonOperation::Toggle));
  71. ui_.buttonOperationComboBox->setItemData(
  72. 3, static_cast<int>(HmiButtonOperation::MomentaryOn));
  73. for (int index = 0; index < ui_.logicComparisonComboBox->count(); ++index)
  74. {
  75. ui_.logicComparisonComboBox->setItemData(index, index);
  76. }
  77. QObject::connect(ui_.applyPropertiesButton, &QPushButton::clicked,
  78. &parent_, [this] { applySelectedControlProperties(); });
  79. QObject::connect(ui_.applyLogicPropertiesButton, &QPushButton::clicked,
  80. &parent_, [this] { applySelectedLogicNodeProperties(); });
  81. ui_.targetPageLabel->setVisible(false);
  82. ui_.targetPageComboBox->setVisible(false);
  83. showControlProperties({});
  84. }
  85. void PropertyPanelController::bindEditorWidgets(
  86. HmiEditorWidget &hmi_editor_widget,
  87. LogicEditorWidget &logic_editor_widget)
  88. {
  89. hmi_editor_widget_ = &hmi_editor_widget;
  90. logic_editor_widget_ = &logic_editor_widget;
  91. QObject::connect(&hmi_editor_widget, &HmiEditorWidget::controlSelected,
  92. &parent_, [this](const QString &id)
  93. {
  94. showControlProperties(toUtf8(id));
  95. });
  96. QObject::connect(&hmi_editor_widget, &HmiEditorWidget::controlChanged,
  97. &parent_, [this](const QString &id)
  98. {
  99. showControlProperties(toUtf8(id));
  100. refresh_project_ui_();
  101. });
  102. QObject::connect(&hmi_editor_widget, &HmiEditorWidget::editorError,
  103. &parent_, [this](const QString &message)
  104. {
  105. handleHmiEditorError(message);
  106. });
  107. QObject::connect(&logic_editor_widget, &LogicEditorWidget::nodeSelected,
  108. &parent_, [this](const QString &id)
  109. {
  110. showLogicNodeProperties(toUtf8(id));
  111. });
  112. QObject::connect(&logic_editor_widget, &LogicEditorWidget::graphChanged,
  113. &parent_, [this]
  114. {
  115. refresh_project_ui_();
  116. });
  117. QObject::connect(&logic_editor_widget, &LogicEditorWidget::editorError,
  118. &parent_, [this](const QString &message)
  119. {
  120. handleLogicEditorError(message);
  121. });
  122. }
  123. void PropertyPanelController::showControlProperties(const std::string &control_id)
  124. {
  125. ui_.propertyStack->setCurrentWidget(ui_.hmiPropertiesPage);
  126. selected_control_id_ = control_id;
  127. const HmiControl *control = hmi_editor_service_.findControl(
  128. current_page_id_(), control_id);
  129. const bool has_control = control != nullptr;
  130. const HmiControlDescriptor *descriptor = has_control
  131. ? findHmiControlDescriptor(control->type) : nullptr;
  132. ui_.selectionValueLabel->setText(
  133. has_control ? fromUtf8(control->id)
  134. + (control->isConfigured() ? QString{}
  135. : control->type == HmiControlType::PageJump
  136. ? QObject::tr("(未配置)") : QObject::tr("(未绑定)"))
  137. : QObject::tr("未选择"));
  138. for (QWidget *widget : {static_cast<QWidget *>(ui_.controlIdEdit),
  139. static_cast<QWidget *>(ui_.controlTextEdit),
  140. static_cast<QWidget *>(ui_.controlXSpinBox),
  141. static_cast<QWidget *>(ui_.controlYSpinBox),
  142. static_cast<QWidget *>(ui_.controlWidthSpinBox),
  143. static_cast<QWidget *>(ui_.controlHeightSpinBox),
  144. static_cast<QWidget *>(ui_.bindingAreaComboBox),
  145. static_cast<QWidget *>(ui_.bindingIndexSpinBox),
  146. static_cast<QWidget *>(ui_.targetPageComboBox),
  147. static_cast<QWidget *>(ui_.buttonOperationComboBox),
  148. static_cast<QWidget *>(ui_.progressMinimumSpinBox),
  149. static_cast<QWidget *>(ui_.progressMaximumSpinBox),
  150. static_cast<QWidget *>(ui_.progressShowValueCheckBox),
  151. static_cast<QWidget *>(ui_.applyPropertiesButton)})
  152. {
  153. widget->setEnabled(has_control);
  154. }
  155. if (!has_control)
  156. {
  157. ui_.bindingAreaLabel->setVisible(false);
  158. ui_.bindingAreaComboBox->setVisible(false);
  159. ui_.bindingIndexLabel->setVisible(false);
  160. ui_.bindingIndexSpinBox->setVisible(false);
  161. ui_.targetPageLabel->setVisible(false);
  162. ui_.targetPageComboBox->setVisible(false);
  163. ui_.buttonOperationLabel->setVisible(false);
  164. ui_.buttonOperationComboBox->setVisible(false);
  165. ui_.progressMinimumLabel->setVisible(false);
  166. ui_.progressMinimumSpinBox->setVisible(false);
  167. ui_.progressMaximumLabel->setVisible(false);
  168. ui_.progressMaximumSpinBox->setVisible(false);
  169. ui_.progressShowValueLabel->setVisible(false);
  170. ui_.progressShowValueCheckBox->setVisible(false);
  171. return;
  172. }
  173. ui_.controlIdEdit->setText(fromUtf8(control->id));
  174. ui_.controlTextEdit->setText(fromUtf8(control->text));
  175. ui_.controlXSpinBox->setValue(control->bounds.x);
  176. ui_.controlYSpinBox->setValue(control->bounds.y);
  177. ui_.controlWidthSpinBox->setValue(control->bounds.width);
  178. ui_.controlHeightSpinBox->setValue(control->bounds.height);
  179. ui_.bindingAreaComboBox->setCurrentIndex(!control->binding.has_value() ? 0
  180. : control->binding->area() == RegisterArea::M ? 1 : 2);
  181. ui_.bindingIndexSpinBox->setValue(
  182. control->binding.has_value() ? control->binding->index() : 0);
  183. const bool has_binding = descriptor != nullptr
  184. && descriptor->bindingKind != HmiBindingKind::None;
  185. ui_.bindingAreaLabel->setVisible(has_binding);
  186. ui_.bindingAreaComboBox->setVisible(has_binding);
  187. ui_.bindingIndexLabel->setVisible(has_binding);
  188. ui_.bindingIndexSpinBox->setVisible(has_binding);
  189. const bool is_button = control->type == HmiControlType::Button;
  190. ui_.buttonOperationLabel->setVisible(is_button);
  191. ui_.buttonOperationComboBox->setVisible(is_button);
  192. ui_.buttonOperationComboBox->setEnabled(is_button);
  193. ui_.buttonOperationComboBox->setCurrentIndex(
  194. ui_.buttonOperationComboBox->findData(
  195. static_cast<int>(control->buttonOperation)));
  196. const bool is_page_jump = control->type == HmiControlType::PageJump;
  197. ui_.targetPageLabel->setVisible(is_page_jump);
  198. ui_.targetPageComboBox->setVisible(is_page_jump);
  199. ui_.targetPageComboBox->setEnabled(is_page_jump);
  200. ui_.targetPageComboBox->clear();
  201. if (is_page_jump)
  202. {
  203. for (const HmiPage &page : project_service_.project().hmiPages)
  204. {
  205. ui_.targetPageComboBox->addItem(
  206. fromUtf8(page.name), fromUtf8(page.id));
  207. }
  208. const std::string target_id = control->pageJump.has_value()
  209. ? control->pageJump->targetPageId : std::string{};
  210. ui_.targetPageComboBox->setCurrentIndex(
  211. ui_.targetPageComboBox->findData(fromUtf8(target_id)));
  212. }
  213. const bool is_progress_bar = control->type == HmiControlType::ProgressBar;
  214. ui_.progressMinimumLabel->setVisible(is_progress_bar);
  215. ui_.progressMinimumSpinBox->setVisible(is_progress_bar);
  216. ui_.progressMaximumLabel->setVisible(is_progress_bar);
  217. ui_.progressMaximumSpinBox->setVisible(is_progress_bar);
  218. ui_.progressShowValueLabel->setVisible(is_progress_bar);
  219. ui_.progressShowValueCheckBox->setVisible(is_progress_bar);
  220. ui_.progressMinimumSpinBox->setEnabled(is_progress_bar);
  221. ui_.progressMaximumSpinBox->setEnabled(is_progress_bar);
  222. ui_.progressShowValueCheckBox->setEnabled(is_progress_bar);
  223. const HmiProgressBarConfig progress_config = control->progressBar.value_or(
  224. HmiProgressBarConfig{});
  225. ui_.progressMinimumSpinBox->setValue(progress_config.minimumValue);
  226. ui_.progressMaximumSpinBox->setValue(progress_config.maximumValue);
  227. ui_.progressShowValueCheckBox->setChecked(progress_config.showValue);
  228. }
  229. void PropertyPanelController::showLogicNodeProperties(const std::string &node_id)
  230. {
  231. ui_.propertyStack->setCurrentWidget(ui_.logicPropertiesPage);
  232. selected_logic_node_id_ = node_id;
  233. const LogicNode *node = logic_editor_service_.findNode(
  234. current_logic_id_(), node_id);
  235. const bool has_node = node != nullptr;
  236. ui_.selectionValueLabel->setText(
  237. has_node ? fromUtf8(node->id) : QObject::tr("未选择"));
  238. for (QWidget *widget : {static_cast<QWidget *>(ui_.logicNodeIdEdit),
  239. static_cast<QWidget *>(ui_.logicAddressSpinBox),
  240. static_cast<QWidget *>(ui_.logicModeComboBox),
  241. static_cast<QWidget *>(ui_.logicComparisonComboBox),
  242. static_cast<QWidget *>(ui_.logicValueSpinBox),
  243. static_cast<QWidget *>(ui_.logicPresetSpinBox),
  244. static_cast<QWidget *>(ui_.applyLogicPropertiesButton)})
  245. {
  246. widget->setEnabled(has_node);
  247. }
  248. ui_.logicNodeTypeLabel->setEnabled(has_node);
  249. ui_.logicAddressAreaLabel->setEnabled(has_node);
  250. if (!has_node)
  251. {
  252. ui_.logicNodeIdEdit->clear();
  253. ui_.logicNodeTypeLabel->clear();
  254. ui_.logicAddressAreaLabel->clear();
  255. ui_.logicModeComboBox->clear();
  256. ui_.logicPresetSpinBox->setValue(TonNodeConfig::kMinimumPresetMs);
  257. return;
  258. }
  259. ui_.logicNodeIdEdit->setText(fromUtf8(node->id));
  260. ui_.logicModeComboBox->clear();
  261. ui_.logicComparisonComboBox->setEnabled(false);
  262. ui_.logicValueSpinBox->setEnabled(false);
  263. ui_.logicPresetSpinBox->setEnabled(false);
  264. if (const auto *contact = std::get_if<ContactNodeConfig>(&node->config))
  265. {
  266. ui_.logicNodeTypeLabel->setText(QObject::tr("触点"));
  267. ui_.logicAddressAreaLabel->setText(QStringLiteral("M"));
  268. ui_.logicAddressSpinBox->setValue(contact->address.index());
  269. ui_.logicModeComboBox->addItem(
  270. QObject::tr("常开"), static_cast<int>(ContactMode::NormallyOpen));
  271. ui_.logicModeComboBox->addItem(
  272. QObject::tr("常闭"), static_cast<int>(ContactMode::NormallyClosed));
  273. ui_.logicModeComboBox->setCurrentIndex(
  274. ui_.logicModeComboBox->findData(static_cast<int>(contact->mode)));
  275. ui_.logicModeComboBox->setEnabled(true);
  276. }
  277. else if (const auto *edge = std::get_if<EdgeContactNodeConfig>(&node->config))
  278. {
  279. ui_.logicNodeTypeLabel->setText(QObject::tr("边沿触点"));
  280. ui_.logicAddressAreaLabel->setText(QStringLiteral("M"));
  281. ui_.logicAddressSpinBox->setValue(edge->address.index());
  282. ui_.logicModeComboBox->addItem(
  283. QObject::tr("上升沿"), static_cast<int>(EdgeMode::Rising));
  284. ui_.logicModeComboBox->addItem(
  285. QObject::tr("下降沿"), static_cast<int>(EdgeMode::Falling));
  286. ui_.logicModeComboBox->setCurrentIndex(
  287. ui_.logicModeComboBox->findData(static_cast<int>(edge->mode)));
  288. ui_.logicModeComboBox->setEnabled(true);
  289. }
  290. else if (const auto *timer = std::get_if<TimerContactNodeConfig>(&node->config))
  291. {
  292. ui_.logicNodeTypeLabel->setText(QObject::tr("T 触点"));
  293. ui_.logicAddressAreaLabel->setText(QStringLiteral("T"));
  294. ui_.logicAddressSpinBox->setValue(timer->address.index());
  295. ui_.logicModeComboBox->addItem(
  296. QObject::tr("常开"), static_cast<int>(ContactMode::NormallyOpen));
  297. ui_.logicModeComboBox->addItem(
  298. QObject::tr("常闭"), static_cast<int>(ContactMode::NormallyClosed));
  299. ui_.logicModeComboBox->setCurrentIndex(
  300. ui_.logicModeComboBox->findData(static_cast<int>(timer->mode)));
  301. ui_.logicModeComboBox->setEnabled(true);
  302. }
  303. else if (const auto *counter_contact =
  304. std::get_if<CounterContactNodeConfig>(&node->config))
  305. {
  306. ui_.logicNodeTypeLabel->setText(QObject::tr("C 触点"));
  307. ui_.logicAddressAreaLabel->setText(QStringLiteral("C"));
  308. ui_.logicAddressSpinBox->setValue(counter_contact->address.index());
  309. ui_.logicModeComboBox->addItem(
  310. QObject::tr("常开"), static_cast<int>(ContactMode::NormallyOpen));
  311. ui_.logicModeComboBox->addItem(
  312. QObject::tr("常闭"), static_cast<int>(ContactMode::NormallyClosed));
  313. ui_.logicModeComboBox->setCurrentIndex(ui_.logicModeComboBox->findData(
  314. static_cast<int>(counter_contact->mode)));
  315. ui_.logicModeComboBox->setEnabled(true);
  316. }
  317. else if (const auto *coil = std::get_if<CoilNodeConfig>(&node->config))
  318. {
  319. ui_.logicNodeTypeLabel->setText(QObject::tr("线圈"));
  320. ui_.logicAddressAreaLabel->setText(QStringLiteral("M"));
  321. ui_.logicAddressSpinBox->setValue(coil->address.index());
  322. ui_.logicModeComboBox->addItem(
  323. QObject::tr("普通"), static_cast<int>(CoilMode::Normal));
  324. ui_.logicModeComboBox->addItem(
  325. QObject::tr("置位"), static_cast<int>(CoilMode::Set));
  326. ui_.logicModeComboBox->addItem(
  327. QObject::tr("复位"), static_cast<int>(CoilMode::Reset));
  328. ui_.logicModeComboBox->setCurrentIndex(
  329. ui_.logicModeComboBox->findData(static_cast<int>(coil->mode)));
  330. ui_.logicModeComboBox->setEnabled(true);
  331. }
  332. else if (const auto *compare = std::get_if<CompareNodeConfig>(&node->config))
  333. {
  334. ui_.logicNodeTypeLabel->setText(QObject::tr("D 值比较"));
  335. ui_.logicAddressAreaLabel->setText(QStringLiteral("D"));
  336. ui_.logicAddressSpinBox->setValue(compare->address.index());
  337. ui_.logicModeComboBox->addItem(QObject::tr("不适用"));
  338. ui_.logicModeComboBox->setEnabled(false);
  339. ui_.logicComparisonComboBox->setEnabled(true);
  340. ui_.logicComparisonComboBox->setCurrentIndex(
  341. ui_.logicComparisonComboBox->findData(
  342. static_cast<int>(compare->comparison)));
  343. ui_.logicValueSpinBox->setEnabled(true);
  344. ui_.logicValueSpinBox->setValue(compare->value);
  345. }
  346. else if (const auto *ton = std::get_if<TonNodeConfig>(&node->config))
  347. {
  348. ui_.logicNodeTypeLabel->setText(QObject::tr("TON"));
  349. ui_.logicAddressAreaLabel->setText(QStringLiteral("T"));
  350. ui_.logicAddressSpinBox->setValue(ton->address.index());
  351. ui_.logicModeComboBox->addItem(QObject::tr("非保持接通延时"));
  352. ui_.logicModeComboBox->setEnabled(false);
  353. ui_.logicPresetSpinBox->setEnabled(true);
  354. ui_.logicPresetSpinBox->setValue(ton->presetMs);
  355. }
  356. else if (const auto *counter = std::get_if<CounterNodeConfig>(&node->config))
  357. {
  358. ui_.logicNodeTypeLabel->setText(
  359. counter->mode == CounterMode::Up ? QStringLiteral("CTU")
  360. : QStringLiteral("CTD"));
  361. ui_.logicAddressAreaLabel->setText(QStringLiteral("C"));
  362. ui_.logicAddressSpinBox->setValue(counter->address.index());
  363. ui_.logicAddressSpinBox->setEnabled(false);
  364. ui_.logicModeComboBox->addItem(QObject::tr("使用配置对话框编辑"));
  365. ui_.logicModeComboBox->setEnabled(false);
  366. }
  367. else if (const auto *move = std::get_if<MoveNodeConfig>(&node->config))
  368. {
  369. ui_.logicNodeTypeLabel->setText(QStringLiteral("MOVE"));
  370. ui_.logicAddressAreaLabel->setText(QStringLiteral("D"));
  371. ui_.logicAddressSpinBox->setValue(move->destination.index());
  372. ui_.logicAddressSpinBox->setEnabled(false);
  373. ui_.logicModeComboBox->addItem(QObject::tr("使用配置对话框编辑"));
  374. ui_.logicModeComboBox->setEnabled(false);
  375. }
  376. else
  377. {
  378. const auto &arithmetic = std::get<ArithmeticNodeConfig>(node->config);
  379. ui_.logicNodeTypeLabel->setText(
  380. arithmetic.operation == ArithmeticOperation::Add
  381. ? QStringLiteral("ADD") : QStringLiteral("SUB"));
  382. ui_.logicAddressAreaLabel->setText(QStringLiteral("D"));
  383. ui_.logicAddressSpinBox->setValue(arithmetic.destination.index());
  384. ui_.logicAddressSpinBox->setEnabled(false);
  385. ui_.logicModeComboBox->addItem(QObject::tr("使用配置对话框编辑"));
  386. ui_.logicModeComboBox->setEnabled(false);
  387. }
  388. if (!node->configured)
  389. {
  390. ui_.logicNodeTypeLabel->setText(QObject::tr("待配置:%1").arg(
  391. ui_.logicNodeTypeLabel->text()));
  392. }
  393. }
  394. void PropertyPanelController::addHmiControl(HmiControlType type)
  395. {
  396. const HmiEditorResult result = hmi_editor_service_.addControl(
  397. current_page_id_(), type);
  398. if (!result.succeeded)
  399. {
  400. reportFailure(QObject::tr("添加控件"), result.message);
  401. return;
  402. }
  403. hmi_editor_widget_->reloadPage();
  404. hmi_editor_widget_->selectControl(result.id);
  405. showControlProperties(result.id);
  406. refresh_project_ui_();
  407. const HmiControlDescriptor *descriptor = findHmiControlDescriptor(type);
  408. const QString display_name = descriptor == nullptr
  409. ? QObject::tr("未知控件")
  410. : QString::fromUtf8(descriptor->displayName);
  411. status_reporter_(QObject::tr("已添加%1").arg(display_name), 3000);
  412. }
  413. void PropertyPanelController::deleteSelectedControl()
  414. {
  415. if (hmi_editor_widget_ == nullptr)
  416. {
  417. return;
  418. }
  419. const std::vector<std::string> selected_ids =
  420. hmi_editor_widget_->selectedControlIds();
  421. if (selected_ids.empty())
  422. {
  423. return;
  424. }
  425. const HmiEditorResult result = hmi_editor_service_.removeControls(
  426. current_page_id_(), selected_ids);
  427. if (!result.succeeded)
  428. {
  429. reportFailure(QObject::tr("删除控件"), result.message);
  430. return;
  431. }
  432. selected_control_id_.clear();
  433. hmi_editor_widget_->reloadPage();
  434. showControlProperties({});
  435. refresh_project_ui_();
  436. }
  437. void PropertyPanelController::applySelectedControlProperties()
  438. {
  439. const HmiControl *old_control = hmi_editor_service_.findControl(
  440. current_page_id_(), selected_control_id_);
  441. if (old_control == nullptr)
  442. {
  443. return;
  444. }
  445. HmiControl control = *old_control;
  446. control.id = toUtf8(ui_.controlIdEdit->text());
  447. control.text = toUtf8(ui_.controlTextEdit->text());
  448. control.bounds.x = ui_.controlXSpinBox->value();
  449. control.bounds.y = ui_.controlYSpinBox->value();
  450. control.bounds.width = ui_.controlWidthSpinBox->value();
  451. control.bounds.height = ui_.controlHeightSpinBox->value();
  452. const HmiControlDescriptor *descriptor =
  453. findHmiControlDescriptor(control.type);
  454. if (descriptor == nullptr
  455. || descriptor->bindingKind == HmiBindingKind::None)
  456. {
  457. control.binding.reset();
  458. }
  459. else
  460. {
  461. const int binding_area = ui_.bindingAreaComboBox->currentData().toInt();
  462. if (binding_area < 0)
  463. {
  464. control.binding.reset();
  465. }
  466. else
  467. {
  468. const RegisterArea area = binding_area == 0
  469. ? RegisterArea::M : RegisterArea::D;
  470. control.binding = RegisterAddress{
  471. area, ui_.bindingIndexSpinBox->value()};
  472. }
  473. }
  474. if (control.type == HmiControlType::Button)
  475. {
  476. control.buttonOperation = static_cast<HmiButtonOperation>(
  477. ui_.buttonOperationComboBox->currentData().toInt());
  478. }
  479. if (control.type == HmiControlType::PageJump)
  480. {
  481. control.pageJump = HmiPageJumpConfig{
  482. toUtf8(ui_.targetPageComboBox->currentData().toString())};
  483. }
  484. if (control.type == HmiControlType::ProgressBar)
  485. {
  486. control.progressBar = HmiProgressBarConfig{
  487. static_cast<std::int16_t>(ui_.progressMinimumSpinBox->value()),
  488. static_cast<std::int16_t>(ui_.progressMaximumSpinBox->value()),
  489. ui_.progressShowValueCheckBox->isChecked()};
  490. }
  491. const HmiEditorResult result = hmi_editor_service_.updateControl(
  492. current_page_id_(), selected_control_id_, control);
  493. if (!result.succeeded)
  494. {
  495. reportFailure(QObject::tr("应用属性"), result.message);
  496. return;
  497. }
  498. const std::string updated_control_id = result.id;
  499. hmi_editor_widget_->reloadPage();
  500. selected_control_id_ = updated_control_id;
  501. hmi_editor_widget_->selectControl(updated_control_id);
  502. showControlProperties(updated_control_id);
  503. refresh_project_ui_();
  504. status_reporter_(QObject::tr("控件属性已更新"), 3000);
  505. }
  506. void PropertyPanelController::applySelectedLogicNodeProperties()
  507. {
  508. const LogicNode *node = logic_editor_service_.findNode(
  509. current_logic_id_(), selected_logic_node_id_);
  510. if (node == nullptr)
  511. {
  512. return;
  513. }
  514. LogicNodeConfig config = node->config;
  515. if (std::holds_alternative<ContactNodeConfig>(config))
  516. {
  517. config = ContactNodeConfig{
  518. RegisterAddress{RegisterArea::M, ui_.logicAddressSpinBox->value()},
  519. static_cast<ContactMode>(ui_.logicModeComboBox->currentData().toInt())};
  520. }
  521. else if (std::holds_alternative<EdgeContactNodeConfig>(config))
  522. {
  523. config = EdgeContactNodeConfig{
  524. RegisterAddress{RegisterArea::M, ui_.logicAddressSpinBox->value()},
  525. static_cast<EdgeMode>(ui_.logicModeComboBox->currentData().toInt())};
  526. }
  527. else if (std::holds_alternative<TimerContactNodeConfig>(config))
  528. {
  529. config = TimerContactNodeConfig{
  530. TimerAddress{ui_.logicAddressSpinBox->value()},
  531. static_cast<ContactMode>(ui_.logicModeComboBox->currentData().toInt())};
  532. }
  533. else if (std::holds_alternative<CounterContactNodeConfig>(config))
  534. {
  535. config = CounterContactNodeConfig{
  536. CounterAddress{ui_.logicAddressSpinBox->value()},
  537. static_cast<ContactMode>(ui_.logicModeComboBox->currentData().toInt())};
  538. }
  539. else if (std::holds_alternative<CoilNodeConfig>(config))
  540. {
  541. config = CoilNodeConfig{
  542. RegisterAddress{RegisterArea::M, ui_.logicAddressSpinBox->value()},
  543. static_cast<CoilMode>(ui_.logicModeComboBox->currentData().toInt())};
  544. }
  545. else if (std::holds_alternative<CompareNodeConfig>(config))
  546. {
  547. config = CompareNodeConfig{
  548. RegisterAddress{RegisterArea::D, ui_.logicAddressSpinBox->value()},
  549. static_cast<ComparisonOperator>(
  550. ui_.logicComparisonComboBox->currentData().toInt()),
  551. static_cast<std::int16_t>(ui_.logicValueSpinBox->value())};
  552. }
  553. else if (std::holds_alternative<TonNodeConfig>(config))
  554. {
  555. config = TonNodeConfig{
  556. TimerAddress{ui_.logicAddressSpinBox->value()},
  557. ui_.logicPresetSpinBox->value()};
  558. }
  559. else
  560. {
  561. LogicInstructionDialog dialog(node->config, &parent_);
  562. if (dialog.exec() != QDialog::Accepted)
  563. {
  564. return;
  565. }
  566. config = dialog.config();
  567. }
  568. const LogicEditorResult result = logic_editor_service_.updateNodeConfig(
  569. current_logic_id_(), selected_logic_node_id_, config);
  570. if (!result.succeeded)
  571. {
  572. reportFailure(QObject::tr("应用逻辑属性"), result.message);
  573. return;
  574. }
  575. logic_editor_widget_->reloadLogic();
  576. logic_editor_widget_->selectNode(selected_logic_node_id_);
  577. showLogicNodeProperties(selected_logic_node_id_);
  578. refresh_project_ui_();
  579. status_reporter_(QObject::tr("逻辑节点属性已更新,节点已配置"), 3000);
  580. }
  581. void PropertyPanelController::handleHmiEditorError(const QString &message) const
  582. {
  583. status_reporter_(message, 5000);
  584. }
  585. void PropertyPanelController::handleLogicEditorError(const QString &message) const
  586. {
  587. status_reporter_(message, 5000);
  588. }
  589. void PropertyPanelController::reportFailure(
  590. const QString &action, const std::string &message) const
  591. {
  592. result_reporter_(action, fromUtf8(message), false);
  593. }