|
- #include "project_workspace_controller.h"
-
- #include "hmi_editor_widget.h"
- #include "logic_editor_widget.h"
- #include "runtime_monitor_widget.h"
- #include "services/hmi_editor_service.h"
- #include "services/hmi_navigation_service.h"
- #include "services/logic_editor_service.h"
- #include "services/project_service.h"
- #include "services/runtime_mode_service.h"
- #include "ui_main_window.h"
-
- #include <QAction>
- #include <QDialogButtonBox>
- #include <QInputDialog>
- #include <QObject>
- #include <QPushButton>
- #include <QSignalBlocker>
- #include <QTabWidget>
- #include <QTreeWidget>
- #include <QTreeWidgetItem>
- #include <QWidget>
-
- #include <utility>
-
- namespace {
-
- constexpr int kProjectTreeKindRole = Qt::UserRole;
- constexpr int kProjectTreeIdRole = Qt::UserRole + 1;
-
- QString fromUtf8(const std::string &value)
- {
- return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
- }
-
- std::string toUtf8(const QString &value)
- {
- const QByteArray bytes = value.toUtf8();
- return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));
- }
-
- bool requestRequiredName(
- QWidget &parent,
- const QString &title,
- const QString &label,
- const QString &initial_value,
- QString *name)
- {
- QInputDialog dialog(&parent);
- dialog.setWindowTitle(title);
- dialog.setLabelText(label);
- dialog.setInputMode(QInputDialog::TextInput);
- dialog.setTextValue(initial_value);
-
- QDialogButtonBox *button_box = dialog.findChild<QDialogButtonBox *>();
- QPushButton *ok_button = button_box != nullptr
- ? button_box->button(QDialogButtonBox::Ok)
- : nullptr;
- if (ok_button != nullptr)
- {
- ok_button->setEnabled(!initial_value.trimmed().isEmpty());
- QObject::connect(
- &dialog,
- &QInputDialog::textValueChanged,
- &dialog,
- [ok_button](const QString &text) {
- ok_button->setEnabled(!text.trimmed().isEmpty());
- });
- }
-
- if (dialog.exec() != QDialog::Accepted)
- {
- return false;
- }
- *name = dialog.textValue().trimmed();
- return true;
- }
-
- } // namespace
-
- ProjectWorkspaceController::ProjectWorkspaceController(
- QWidget &parent,
- Ui::MainWindow &ui,
- ProjectService &project_service,
- HmiEditorService &hmi_editor_service,
- LogicEditorService &logic_editor_service,
- RuntimeModeService &runtime_mode_service,
- HmiNavigationService &hmi_navigation_service,
- HmiEditorWidget &hmi_editor_widget,
- LogicEditorWidget &logic_editor_widget,
- RuntimeMonitorWidget &runtime_monitor_widget,
- std::string ¤t_hmi_page_id,
- std::string ¤t_logic_id,
- std::function<void(const std::string &)> show_control_properties,
- std::function<void(const std::string &)> show_logic_properties,
- ResultReporter result_reporter,
- StatusReporter status_reporter,
- EditStateChanged edit_state_changed)
- : parent_(parent),
- ui_(ui),
- project_service_(project_service),
- hmi_editor_service_(hmi_editor_service),
- logic_editor_service_(logic_editor_service),
- runtime_mode_service_(runtime_mode_service),
- hmi_navigation_service_(hmi_navigation_service),
- hmi_editor_widget_(hmi_editor_widget),
- logic_editor_widget_(logic_editor_widget),
- runtime_monitor_widget_(runtime_monitor_widget),
- current_hmi_page_id_(current_hmi_page_id),
- current_logic_id_(current_logic_id),
- show_control_properties_(std::move(show_control_properties)),
- show_logic_properties_(std::move(show_logic_properties)),
- result_reporter_(std::move(result_reporter)),
- status_reporter_(std::move(status_reporter)),
- edit_state_changed_(std::move(edit_state_changed))
- {
- }
-
- void ProjectWorkspaceController::configure()
- {
- ui_.projectTree->setContextMenuPolicy(Qt::ActionsContextMenu);
-
- add_page_action_ = new QAction(QObject::tr("新建页面"), &parent_);
- add_page_action_->setObjectName(QStringLiteral("addPageAction"));
- add_logic_action_ = new QAction(QObject::tr("新建控制逻辑"), &parent_);
- add_logic_action_->setObjectName(QStringLiteral("addLogicAction"));
- rename_item_action_ = new QAction(QObject::tr("重命名"), &parent_);
- rename_item_action_->setObjectName(QStringLiteral("renameProjectItemAction"));
- delete_item_action_ = new QAction(QObject::tr("删除"), &parent_);
- delete_item_action_->setObjectName(QStringLiteral("deleteProjectItemAction"));
- move_item_up_action_ = new QAction(QObject::tr("上移"), &parent_);
- move_item_up_action_->setObjectName(QStringLiteral("moveProjectItemUpAction"));
- move_item_down_action_ = new QAction(QObject::tr("下移"), &parent_);
- move_item_down_action_->setObjectName(
- QStringLiteral("moveProjectItemDownAction"));
- set_initial_page_action_ = new QAction(QObject::tr("设为初始页面"), &parent_);
- set_initial_page_action_->setObjectName(QStringLiteral("setInitialPageAction"));
- toggle_logic_enabled_action_ = new QAction(
- QObject::tr("禁用控制逻辑"), &parent_);
- toggle_logic_enabled_action_->setObjectName(
- QStringLiteral("toggleLogicEnabledAction"));
-
- ui_.projectTree->addActions({
- add_page_action_,
- add_logic_action_,
- rename_item_action_,
- delete_item_action_,
- move_item_up_action_,
- move_item_down_action_,
- set_initial_page_action_,
- toggle_logic_enabled_action_});
-
- QObject::connect(add_page_action_, &QAction::triggered,
- &parent_, [this] { addPage(); });
- QObject::connect(add_logic_action_, &QAction::triggered,
- &parent_, [this] { addLogic(); });
- QObject::connect(rename_item_action_, &QAction::triggered,
- &parent_, [this] { renameSelectedItem(); });
- QObject::connect(delete_item_action_, &QAction::triggered,
- &parent_, [this] { deleteSelectedItem(); });
- QObject::connect(move_item_up_action_, &QAction::triggered,
- &parent_, [this] { moveSelectedItem(-1); });
- QObject::connect(move_item_down_action_, &QAction::triggered,
- &parent_, [this] { moveSelectedItem(1); });
- QObject::connect(set_initial_page_action_, &QAction::triggered,
- &parent_, [this] { setSelectedPageAsInitial(); });
- QObject::connect(toggle_logic_enabled_action_, &QAction::triggered,
- &parent_, [this] { toggleSelectedLogicEnabled(); });
- QObject::connect(ui_.projectTree, &QTreeWidget::currentItemChanged,
- &parent_, [this](QTreeWidgetItem *, QTreeWidgetItem *)
- {
- handleSelectionChanged();
- });
- updateActions();
- }
-
- void ProjectWorkspaceController::refresh()
- {
- if (hmi_editor_service_.findPage(current_hmi_page_id_) == nullptr)
- {
- const std::string &initial_id = project_service_.project().initialHmiPageId;
- current_hmi_page_id_ = hmi_editor_service_.findPage(initial_id) != nullptr
- ? initial_id : hmi_editor_service_.firstPageId();
- show_control_properties_({});
- }
- if (logic_editor_service_.findLogic(current_logic_id_) == nullptr)
- {
- current_logic_id_ = logic_editor_service_.firstLogicId();
- show_logic_properties_({});
- }
-
- hmi_editor_widget_.setPageId(current_hmi_page_id_);
- logic_editor_widget_.setLogicId(current_logic_id_);
- if (runtime_mode_service_.mode() != ApplicationMode::Editing)
- {
- runtime_monitor_widget_.setProjectObjects(
- hmi_navigation_service_.currentPageId(), current_logic_id_);
- }
- runtime_mode_service_.refreshPlcPollAddresses();
-
- const QSignalBlocker blocker(ui_.projectTree);
- ui_.projectTree->clear();
- auto *hmi_root = new QTreeWidgetItem(ui_.projectTree, {QObject::tr("HMI 页面")});
- hmi_root->setData(0, kProjectTreeKindRole, static_cast<int>(ItemKind::Root));
- QTreeWidgetItem *selected_item = nullptr;
- for (const HmiPage &page : project_service_.project().hmiPages)
- {
- const QString suffix = page.id == project_service_.project().initialHmiPageId
- ? QObject::tr("(初始)") : QString{};
- auto *item = new QTreeWidgetItem(
- hmi_root, {fromUtf8(page.name) + suffix});
- item->setData(0, kProjectTreeKindRole, static_cast<int>(ItemKind::HmiPage));
- item->setData(0, kProjectTreeIdRole, fromUtf8(page.id));
- if (page.id == current_hmi_page_id_
- && ui_.editorTabWidget->currentIndex() == 0)
- {
- selected_item = item;
- }
- }
-
- const HmiPage *current_page = hmi_editor_service_.findPage(current_hmi_page_id_);
- if (current_page != nullptr)
- {
- ui_.hmiPageTitleLabel->setText(fromUtf8(current_page->name));
- ui_.hmiPageSizeLabel->setText(
- QObject::tr("%1 x %2").arg(current_page->width).arg(current_page->height));
- }
- else
- {
- ui_.hmiPageTitleLabel->setText(QObject::tr("尚未创建 HMI 页面"));
- ui_.hmiPageSizeLabel->clear();
- }
-
- auto *logic_root = new QTreeWidgetItem(
- ui_.projectTree, {QObject::tr("控制逻辑")});
- logic_root->setData(0, kProjectTreeKindRole, static_cast<int>(ItemKind::Root));
- for (const ControlLogic &logic : project_service_.project().controlLogics)
- {
- const QString suffix = logic.enabled ? QString{} : QObject::tr("(已禁用)");
- auto *item = new QTreeWidgetItem(
- logic_root, {fromUtf8(logic.name) + suffix});
- item->setData(
- 0, kProjectTreeKindRole, static_cast<int>(ItemKind::ControlLogic));
- item->setData(0, kProjectTreeIdRole, fromUtf8(logic.id));
- if (logic.id == current_logic_id_
- && ui_.editorTabWidget->currentIndex() == 1)
- {
- selected_item = item;
- }
- }
- ui_.projectTree->expandAll();
- if (selected_item != nullptr)
- {
- ui_.projectTree->setCurrentItem(selected_item);
- }
- updateActions();
- }
-
- void ProjectWorkspaceController::handleSelectionChanged()
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr)
- {
- updateActions();
- return;
- }
- const auto kind = static_cast<ItemKind>(
- item->data(0, kProjectTreeKindRole).toInt());
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- if (kind == ItemKind::HmiPage && hmi_editor_service_.findPage(id) != nullptr)
- {
- current_hmi_page_id_ = id;
- hmi_editor_widget_.setPageId(id);
- hmi_editor_widget_.reloadPage();
- ui_.editorTabWidget->setCurrentWidget(ui_.hmiEditorTab);
- show_control_properties_({});
- const HmiPage *page = hmi_editor_service_.findPage(id);
- ui_.hmiPageTitleLabel->setText(fromUtf8(page->name));
- ui_.hmiPageSizeLabel->setText(
- QObject::tr("%1 x %2").arg(page->width).arg(page->height));
- }
- else if (kind == ItemKind::ControlLogic
- && logic_editor_service_.findLogic(id) != nullptr)
- {
- current_logic_id_ = id;
- logic_editor_widget_.setLogicId(id);
- logic_editor_widget_.reloadLogic();
- ui_.editorTabWidget->setCurrentWidget(ui_.logicEditorTab);
- show_logic_properties_({});
- }
- updateActions();
- }
-
- void ProjectWorkspaceController::updateActions()
- {
- if (add_page_action_ == nullptr)
- {
- return;
- }
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- const auto kind = item == nullptr ? ItemKind::Root
- : static_cast<ItemKind>(item->data(0, kProjectTreeKindRole).toInt());
- const bool page_selected = kind == ItemKind::HmiPage;
- const bool logic_selected = kind == ItemKind::ControlLogic;
- const bool editable = runtime_mode_service_.policy().allowsProjectEditing;
- add_page_action_->setEnabled(editable);
- add_logic_action_->setEnabled(editable);
- rename_item_action_->setEnabled(editable && (page_selected || logic_selected));
- delete_item_action_->setEnabled(editable && (page_selected || logic_selected));
- move_item_up_action_->setEnabled(editable && (page_selected || logic_selected));
- move_item_down_action_->setEnabled(editable && (page_selected || logic_selected));
- set_initial_page_action_->setEnabled(editable && page_selected);
- toggle_logic_enabled_action_->setEnabled(editable && logic_selected);
- if (logic_selected)
- {
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- const ControlLogic *logic = logic_editor_service_.findLogic(id);
- toggle_logic_enabled_action_->setText(
- logic != nullptr && logic->enabled
- ? QObject::tr("禁用控制逻辑") : QObject::tr("启用控制逻辑"));
- }
- }
-
- void ProjectWorkspaceController::addPage()
- {
- QString name;
- if (!requestRequiredName(
- parent_, QObject::tr("新建页面"), QObject::tr("页面名称"), {}, &name))
- {
- return;
- }
- const HmiEditorResult result = hmi_editor_service_.addPage(toUtf8(name));
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("新建页面"), result.message);
- return;
- }
- current_hmi_page_id_ = result.id;
- show_control_properties_({});
- ui_.editorTabWidget->setCurrentWidget(ui_.hmiEditorTab);
- refresh();
- hmi_editor_widget_.reloadPage();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::addLogic()
- {
- QString name;
- if (!requestRequiredName(
- parent_, QObject::tr("新建控制逻辑"), QObject::tr("逻辑名称"), {}, &name))
- {
- return;
- }
- const LogicEditorResult result = logic_editor_service_.addLogic(toUtf8(name));
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("新建控制逻辑"), result.message);
- return;
- }
- current_logic_id_ = result.id;
- show_logic_properties_({});
- ui_.editorTabWidget->setCurrentWidget(ui_.logicEditorTab);
- refresh();
- logic_editor_widget_.reloadLogic();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::renameSelectedItem()
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr)
- {
- return;
- }
- const auto kind = static_cast<ItemKind>(
- item->data(0, kProjectTreeKindRole).toInt());
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- QString current_name;
- if (kind == ItemKind::HmiPage)
- {
- const HmiPage *page = hmi_editor_service_.findPage(id);
- current_name = page == nullptr ? QString{} : fromUtf8(page->name);
- }
- else if (kind == ItemKind::ControlLogic)
- {
- const ControlLogic *logic = logic_editor_service_.findLogic(id);
- current_name = logic == nullptr ? QString{} : fromUtf8(logic->name);
- }
- else
- {
- return;
- }
- QString name;
- if (!requestRequiredName(
- parent_, QObject::tr("重命名"), QObject::tr("新名称"), current_name, &name))
- {
- return;
- }
- if (kind == ItemKind::HmiPage)
- {
- const HmiEditorResult result = hmi_editor_service_.renamePage(id, toUtf8(name));
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("重命名页面"), result.message);
- return;
- }
- }
- else
- {
- const LogicEditorResult result = logic_editor_service_.renameLogic(
- id, toUtf8(name));
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("重命名控制逻辑"), result.message);
- return;
- }
- }
- refresh();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::deleteSelectedItem()
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr)
- {
- return;
- }
- const auto kind = static_cast<ItemKind>(
- item->data(0, kProjectTreeKindRole).toInt());
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- if (kind == ItemKind::HmiPage)
- {
- const HmiEditorResult result = hmi_editor_service_.removePage(id);
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("删除页面"), result.message);
- return;
- }
- }
- else if (kind == ItemKind::ControlLogic)
- {
- const LogicEditorResult result = logic_editor_service_.removeLogic(id);
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("删除控制逻辑"), result.message);
- return;
- }
- }
- else
- {
- return;
- }
- refresh();
- show_control_properties_({});
- show_logic_properties_({});
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::moveSelectedItem(int offset)
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr)
- {
- return;
- }
- const auto kind = static_cast<ItemKind>(
- item->data(0, kProjectTreeKindRole).toInt());
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- if (kind == ItemKind::HmiPage)
- {
- const HmiEditorResult result = hmi_editor_service_.movePage(id, offset);
- if (!result.succeeded)
- {
- status_reporter_(fromUtf8(result.message), 4000);
- return;
- }
- }
- else if (kind == ItemKind::ControlLogic)
- {
- const LogicEditorResult result = logic_editor_service_.moveLogic(id, offset);
- if (!result.succeeded)
- {
- status_reporter_(fromUtf8(result.message), 4000);
- return;
- }
- }
- else
- {
- return;
- }
- refresh();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::setSelectedPageAsInitial()
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr
- || static_cast<ItemKind>(item->data(0, kProjectTreeKindRole).toInt())
- != ItemKind::HmiPage)
- {
- return;
- }
- const HmiEditorResult result = hmi_editor_service_.setInitialPage(
- toUtf8(item->data(0, kProjectTreeIdRole).toString()));
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("设置初始页面"), result.message);
- return;
- }
- refresh();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::toggleSelectedLogicEnabled()
- {
- QTreeWidgetItem *item = ui_.projectTree->currentItem();
- if (item == nullptr
- || static_cast<ItemKind>(item->data(0, kProjectTreeKindRole).toInt())
- != ItemKind::ControlLogic)
- {
- return;
- }
- const std::string id = toUtf8(item->data(0, kProjectTreeIdRole).toString());
- const ControlLogic *logic = logic_editor_service_.findLogic(id);
- if (logic == nullptr)
- {
- return;
- }
- const LogicEditorResult result = logic_editor_service_.setLogicEnabled(
- id, !logic->enabled);
- if (!result.succeeded)
- {
- reportFailure(QObject::tr("启停控制逻辑"), result.message);
- return;
- }
- refresh();
- edit_state_changed_();
- }
-
- void ProjectWorkspaceController::reportFailure(
- const QString &action, const std::string &message) const
- {
- result_reporter_(action, fromUtf8(message), false);
- }
|