DiagramDesigner/diagramCavas/source/diagramCavas_p.cpp

1217 lines
34 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// diagramcavas_p.cpp
#include "diagramCavas_p.h"
#include "diagramCavas.h"
#include "dataBase.h"
#include "projectModelManager.h"
#include "diagramCommunication/include/communicationManager.h"
#include "diagramCommunication/include/configManager.h"
#include "uiCommunicationBus.h"
#include "itemPropertyDlg.h"
#include "QQuickDetailsViewMananger.h"
#include "propertyType/propertyTypeCustomization_DataSourceType.h"
#include "propertyType/propertyTypeCustomization_ConfigEventData.h"
#include "propertyType/dataSourceType.h"
#include <QMessageBox>
#include <QJsonObject>
#include <QStandardItem>
#include <QLibrary>
#include <QMetaMethod>
#include <QApplication>
#include <QShortcut>
#include "graphicsItem/graphicsBaseItem.h"
#include "topologyManager.h"
#include "powerEntity.h"
#include "cornerMonitorLauncher.h"
#include "loadMonitorPageDlg.h"
#include "diagramConnectSetting.h"
#include "instance/dataAccessor.h"
#include "monitorConfigDlg.h"
#include "structDataPreviewDlg.h"
#include "extraPropertyManager.h"
#include "createHMIdlg.h"
#include "pluginManager.h"
#include "graphicsItem/pluginItemFactory.h"
#include "QDetailsView.h"
#include "propertyDialog.h"
#include "basePannelPropertyProxy.h"
#include "QDetailsView.h""
#include <QShortcut>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
DiagramCavasPrivate::DiagramCavasPrivate(DiagramCavas* q)
: q_ptr(q)
, _pageIndex(0)
, _curMode(0)
, _cornerButton(nullptr)
, _loadMonitorPageDlg(nullptr)
, _connectSetting(nullptr)
, _dataAccessor(nullptr)
, _structDataPreviewDlg(nullptr)
, _extraPropertyManager(nullptr)
, _createHMIDlg(nullptr)
, _pPropertyPage(nullptr)
, _pPropertyDlg(nullptr)
, m_pluginManager(nullptr)
, m_itemFactory(nullptr)
{
// 初始化代码
}
DiagramCavasPrivate::~DiagramCavasPrivate()
{
// 清理代码
if (_cornerButton) delete _cornerButton;
if (_loadMonitorPageDlg) delete _loadMonitorPageDlg;
if (_connectSetting) delete _connectSetting;
if (_dataAccessor) delete _dataAccessor;
if (_structDataPreviewDlg) delete _structDataPreviewDlg;
if (_extraPropertyManager) delete _extraPropertyManager;
if (_createHMIDlg) delete _createHMIDlg;
}
void DiagramCavasPrivate::initialImpl()
{
Q_Q(DiagramCavas);
// 1. 读取数据并初始化页面
QList<PageInfo> lst = DataBase::GetInstance()->getAllPage();
for (auto &info : lst) {
TopologyManager::instance().createDiagram(QString::number(info.id), info.name);
}
// 2. 初始化角落监控启动器
_cornerButton = new CornerMonitorLauncher(q);
_cornerButton->showDlg();
// 3. 初始化加载监控页面对话框
_loadMonitorPageDlg = new LoadMonitorPageDlg(q);
QObject::connect(_cornerButton, &CornerMonitorLauncher::openLoadMonitorDlg, q, [this, q]() {
if (_loadMonitorPageDlg) {
q->updateMonitorListFromDB(1);
_loadMonitorPageDlg->show();
}
});
QObject::connect(_loadMonitorPageDlg, &LoadMonitorPageDlg::monitorSelected, q, &DiagramCavas::onSignal_monitorSelected);
// 4. 初始化连接设置
_connectSetting = new DiagramConnectSetting(q);
// 5. 初始化通信管理器
CommunicationManager* comm = CommunicationManager::instance();
comm->initialize();
// 6. 加载配置
ConfigManager* config = ConfigManager::instance();
config->loadConfig("config.json");
// 7. 初始化额外属性管理器
_extraPropertyManager = new ExtraPropertyManager(q);
_extraPropertyManager->initial();
// 8. 应用配置到通信管理器
comm->updateHttpConfig(config->getHttpConfig());
comm->updateWebSocketConfig(config->getWebSocketConfig());
// 9. 初始化数据访问器
_dataAccessor = new DataAccessor(q);
_dataAccessor->setParent(q);
QObject::connect(UiCommunicationBus::instance(),
SIGNAL(httpDataProcessed(QString, QVariant)),
_dataAccessor,
SLOT(onReceiveHttpData(QString, QVariant)),
Qt::AutoConnection);
QObject::connect(UiCommunicationBus::instance(),
SIGNAL(websocketDataProcessed(QVariant)),
_dataAccessor,
SLOT(onReceiveWebsocketData(QVariant)),
Qt::AutoConnection);
// 10. 初始化结构数据预览对话框
_structDataPreviewDlg = new StructDataPreviewDlg(q);
_structDataPreviewDlg->setExtraPropertyManager(_extraPropertyManager);
_structDataPreviewDlg->loadData();
// 11. 注册自定义属性类型
QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<DataSourceType,
PropertyTypeCustomization_DataSourceType>();
QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<EventList,
PropertyTypeCustomization_ConfigEventData>();
// 12. 初始化创建HMI对话框
_createHMIDlg = new CreateHMIdlg(q);
QObject::connect(_createHMIDlg, &CreateHMIdlg::createHMI, q, &DiagramCavas::onSignal_createHMIClicked);
// 13. 从数据库更新HMI列表
q->updateHMIlstFromDB();
// 14. 加载插件配置
QString pluginConfigPath = QCoreApplication::applicationDirPath() + "/pluginConfig.json";
loadPluginConfig(pluginConfigPath);
// 15. 初始化插件管理器
m_pluginManager = PluginManager::instance();
// 16. 创建Canvas项工厂
m_itemFactory = PluginItemFactory::instance();
m_itemFactory->setPluginManager(m_pluginManager);
// 17. 加载插件
QString pluginsDir = QApplication::applicationDirPath() + "/plugins";
m_pluginManager->addPluginDirectory(pluginsDir);
m_pluginManager->loadAllPlugins(pluginsDir);
// 18. 初始化属性对话框
_pPropertyDlg = new PropertyDlg(q->parentWidget());
_pPropertyDlg->hide();
// 19. 添加快捷键
addShortcuts();
// 20. 设置视图模式
// q->setViewMode(QMdiArea::TabbedView);
}
void DiagramCavasPrivate::removePanel(PowerEntity* pEntity)
{
Q_Q(DiagramCavas);
QMap<QString,QPair<MonitorPanel*,QMdiSubWindow*>>::Iterator iter;
for(iter = m_mapMonitorPanel.begin(); iter != m_mapMonitorPanel.end();++iter)
{
if(pEntity->name() == iter.value().first->pageName())
{
MonitorPanel* pPanel = m_mapMonitorPanel.take(iter.key()).first;
QWidget* pWindow = static_cast<QWidget*>(pPanel);
q->setActiveSubWindow(iter->second);
q->closeActiveSubWindow();
//removeSubWindow(pPanel);
//todo记录删除组态图从数据库中删除
delete pPanel;
break;
}
}
}
void DiagramCavasPrivate::calculateLauncherVisible()
{
if(_cornerButton){
if (m_mapMonitorPanel.isEmpty()) {
_cornerButton->setVisible(true);
} else {
_cornerButton->setVisible(false);
}
}
}
bool DiagramCavasPrivate::loadPluginConfig(const QString& path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
file.close();
if (doc.isObject()) {
return parsePluginConfig(doc.object());
}
return false;
}
bool DiagramCavasPrivate::parsePluginConfig(const QJsonObject& root)
{
if (!root.contains("shapes")) {
qWarning() << "Missing 'shapes' key";
return false;
}
QJsonArray items = root["shapes"].toArray();
for (const QJsonValue& itemVal : items) {
QJsonObject itemObj = itemVal.toObject();
int type = itemObj["type"].toInt();
QString shapeName = itemObj["shapeName"].toString();
QString modelName = itemObj["modelName"].toString();
// 解析枚举类型
PluginTypeInfo info;
info.baseType = type;
info.shapeName = shapeName;
info.modelName = modelName;
m_pluginInfo[shapeName] = info;
}
qDebug() << "Loaded" << m_pluginInfo.size() << "shapes types from config";
return true;
}
void DiagramCavasPrivate::addShortcuts()
{
Q_Q(DiagramCavas);
// 添加快捷键
QShortcut* shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), q);
QObject::connect(shortcut, &QShortcut::activated, q, [q]() {
q->onSignal_savePage();
});
QShortcut* toggleProp = new QShortcut(QKeySequence("Ctrl+P"), q);
QObject::connect(toggleProp, &QShortcut::activated, q,[&,q]() {
if(_pPropertyDlg->isVisible()){
q->hidePropertyDlg();
}
else{
if(_curMode == 1)
q->showPropertyDlg();
}
});
}
void DiagramCavasPrivate::updateCornerPos()
{
if(_cornerButton)
_cornerButton->positionAtCorner();
}
void DiagramCavasPrivate::showNewSettingDlg()
{
if(_connectSetting){
_connectSetting->showDlg();
}
}
void DiagramCavasPrivate::showStructDataPreviewDlg()
{
if(_structDataPreviewDlg)
_structDataPreviewDlg->showDlg();
}
void DiagramCavasPrivate::processRecommandData(const HttpRecommandInfo& info)
{
Q_Q(DiagramCavas);
// 1. 生成完整名称列表
QStringList completeNames = info.generateCompleteNames();
// 2. 更新数据预览对话框
if (_structDataPreviewDlg) {
_structDataPreviewDlg->updateRecommandLst(completeNames);
qDebug() << "Updated data preview dialog with" << completeNames.size() << "items";
}
// 3. 获取当前子窗口
QMdiSubWindow* currentSubWindow = q->currentSubWindow();
if (!currentSubWindow) {
qDebug() << "No active window, skipping panel update";
return;
}
// 4. 获取当前面板
QWidget* windowWidget = currentSubWindow->widget();
BaseDrawingPanel* panel = dynamic_cast<BaseDrawingPanel*>(windowWidget);
if (!panel) {
qDebug() << "Current window is not a drawing panel";
return;
}
// 5. 只处理运行模式的面板
if (panel->getMode() == DM_run) {
MonitorPanel* monitorPanel = dynamic_cast<MonitorPanel*>(panel);
if (monitorPanel) {
qDebug() << "Monitor panel found:" << monitorPanel->pageName();
// todo: 推荐列表的使用
// 这里可以根据需要调用监控面板的方法
}
}
qDebug() << "Recommand data processed:"
<< "input =" << info.sInput
<< "offset =" << info.nOffset
<< "items =" << info.lstRecommand.size();
}
void DiagramCavasPrivate::onTargetSelected(QObject* obj)
{
Q_Q(DiagramCavas);
if(obj){
if(_curMode == 0)
emit q->selectTarget(obj);
else
_pPropertyPage->setObject(obj);
}
}
void DiagramCavasPrivate::onCreateHMI()
{
if(_createHMIDlg)
_createHMIDlg->showDlg();
}
void DiagramCavasPrivate::updateHMIFromDB()
{
QList<HMIPageInfo> lstMonitor = DataBase::GetInstance()->getAllHMI();
for(auto &info:lstMonitor)
{
auto p = TopologyManager::instance().findDiagram(info.uid.toString(),ModelFunctionType::RuntimeModel);
if(!p){
TopologyManager::instance().createDiagram(info.uid.toString(),info.name,ModelFunctionType::RuntimeModel);
}
}
}
void DiagramCavasPrivate::initPropertyPage()
{
if (_pPropertyPage == nullptr) {
_pPropertyPage = new QDetailsView();
_pPropertyPage->setObject(new QObject(q_ptr));
// 可以在这里配置属性页的更多设置
_pPropertyPage->setWindowTitle("属性面板");
_pPropertyPage->setMinimumSize(300, 400);
// 连接属性变化的信号
// connect(_pPropertyPage, &QDetailsView::propertyChanged,
// q_ptr, &DiagramCavas::onPropertyChanged);
}
}
void DiagramCavasPrivate::showPropertyDlgImpl()
{
Q_Q(DiagramCavas);
// 确保属性页面已初始化
initPropertyPage();
// 确保属性对话框已创建
if (_pPropertyDlg == nullptr) {
_pPropertyDlg = new PropertyDlg(q->parentWidget());
_pPropertyDlg->setWindowTitle("属性设置");
_pPropertyDlg->setModal(false); // 非模态对话框
// 连接对话框关闭信号
QObject::connect(_pPropertyDlg, &PropertyDlg::finished, q, [this]() {
// 对话框关闭时的处理
qDebug() << "Property dialog closed";
});
}
// 设置内容
_pPropertyDlg->setContent(_pPropertyPage);
_pPropertyDlg->show();
// 居中显示
centerPropertyDialogOnScreen();
// 激活窗口
_pPropertyDlg->raise();
_pPropertyDlg->activateWindow();
}
void DiagramCavasPrivate::hidePropertyDlgImpl()
{
if (_pPropertyDlg) {
_pPropertyDlg->hide();
}
}
void DiagramCavasPrivate::centerPropertyDialogOnScreen()
{
if (!_pPropertyDlg || !_pPropertyDlg->isVisible()) {
return;
}
Q_Q(DiagramCavas);
// 获取屏幕
QScreen* screen = nullptr;
if (q->parentWidget()) {
screen = QGuiApplication::screenAt(q->parentWidget()->geometry().center());
}
if (!screen) {
screen = QGuiApplication::primaryScreen();
}
if (!screen) {
qWarning() << "No screen available for centering dialog";
return;
}
QRect screenGeometry = screen->geometry();
QRect dialogGeometry = _pPropertyDlg->geometry();
// 计算位置:水平靠右,垂直居中
int x = screenGeometry.right() - dialogGeometry.width() - 10; // 留10像素边距
int y = screenGeometry.center().y() - dialogGeometry.height() / 2;
// 确保对话框不超出屏幕
y = qMax(screenGeometry.top(), qMin(y, screenGeometry.bottom() - dialogGeometry.height()));
x = qMax(screenGeometry.left(), qMin(x, screenGeometry.right() - dialogGeometry.width()));
_pPropertyDlg->move(x, y);
// 可选:保存位置到配置
// saveDialogPositionToConfig(x, y);
}
void DiagramCavasPrivate::addDrawingPanelImpl(PowerEntity* pItem, DiagramMode mode, const QString& parent)
{
if (!pItem) {
qWarning() << "Cannot add drawing panel: PowerEntity is null";
return;
}
if (mode == DM_run) {
addMonitorPanel(pItem, parent);
} else {
addEditorPanel(pItem, parent);
}
calculateLauncherVisible();
}
void DiagramCavasPrivate::addMonitorPanel(PowerEntity* pItem, const QString& parent)
{
Q_Q(DiagramCavas);
// 创建监控面板
MonitorPanel* pPanel = new MonitorPanel(pItem, q, DM_run);
// 更新当前页面信息
QString panelName = pItem->name();
updateCurrentPage(panelName);
// 配置面板
pPanel->setPageName(_curPage);
pPanel->setWindowTitle(_curPage);
pPanel->setParentPage(parent);
// 添加到MDI区域
QMdiSubWindow* pSub = q->addSubWindow(pPanel);
m_mapMonitorPanel.insert(_curPage, qMakePair(pPanel, pSub));
// 显示面板
pPanel->show();
// 获取模型控制器并设置连接
FixedPortsModel* pModel = pPanel->getModelController();
if (pModel) {
pModel->setCavas(QPointer<DiagramCavas>(q));
connectMonitorPanelSignals(pPanel, pModel);
} else {
qWarning() << "Failed to get model controller for monitor panel:" << _curPage;
}
qDebug() << "Monitor panel added:" << _curPage << "parent:" << parent;
}
void DiagramCavasPrivate::addEditorPanel(PowerEntity* pItem, const QString& parent)
{
Q_Q(DiagramCavas);
// 编辑器面板的添加
qWarning() << "Editor panel not implemented yet for:" << pItem->name();
// 示例代码:
// DrawingPanel* pPanel = new DrawingPanel(pItem, q, DM_edit);
// pPanel->setPageName(pItem->name());
// pPanel->setWindowTitle(pItem->name());
// pPanel->setParentPage(parent);
//
// QMdiSubWindow* pSub = q->addSubWindow(pPanel);
// pPanel->show();
//
// qDebug() << "Editor panel added:" << pItem->name() << "parent:" << parent;
}
void DiagramCavasPrivate::connectMonitorPanelSignals(MonitorPanel* panel, FixedPortsModel* model)
{
Q_Q(DiagramCavas);
if (!panel || !model) {
return;
}
// 连接面板删除信号
QObject::connect(panel, &MonitorPanel::panelDelete, q,
&DiagramCavas::onSignal_panelDelete);
// 连接模型信号
QObject::connect(model, &FixedPortsModel::activatePage, q,
&DiagramCavas::onSignal_activatePage);
QObject::connect(model, &FixedPortsModel::monitorCreated, q,
&DiagramCavas::onSignal_monitorCreated);
QObject::connect(model, &FixedPortsModel::monitorItems, q,
&DiagramCavas::onSignal_monitorItemCreated);
// 注释掉的连接(根据原始代码)
// connect(model, &FixedPortsModel::notifyUpdateMonitorTopology, q,
// &DiagramCavas::onSignal_updateMonitorTopology);
QObject::connect(model, &FixedPortsModel::updateTopologyItems, q,
&DiagramCavas::onSignal_updateTopology);
QObject::connect(model, &FixedPortsModel::HMIUpdated, q,
&DiagramCavas::onSignal_updateHMI);
// 可选:连接其他信号
// connect(panel, &MonitorPanel::panelActivated, q,
// [this, q](const QString& name) {
// updateCurrentPage(name);
// });
qDebug() << "Monitor panel signals connected for:" << _curPage;
}
void DiagramCavasPrivate::updateCurrentPage(const QString& pageName)
{
_curPage = pageName;
qDebug() << "Current page updated to:" << _curPage;
}
bool DiagramCavasPrivate::hasPanel(const QString& name) const
{
return m_mapMonitorPanel.contains(name);
}
MonitorPanel* DiagramCavasPrivate::getPanel(const QString& name) const
{
if (m_mapMonitorPanel.contains(name)) {
return m_mapMonitorPanel[name].first;
}
return nullptr;
}
QMdiSubWindow* DiagramCavasPrivate::getSubWindow(const QString& name) const
{
if (m_mapMonitorPanel.contains(name)) {
return m_mapMonitorPanel[name].second;
}
return nullptr;
}
void DiagramCavasPrivate::savePageImpl()
{
Q_Q(DiagramCavas);
// 获取当前子窗口
QMdiSubWindow* currentSubWindow = q->currentSubWindow();
if (!currentSubWindow) {
qWarning() << "No active subwindow for saving";
QMessageBox::warning(nullptr, QString("警告"),
QString::fromWCharArray(L"没有活动的页面可以保存"));
return;
}
// 获取面板
BaseDrawingPanel* pPanel = getCurrentDrawingPanel();
if (!pPanel) {
qWarning() << "Cannot cast to BaseDrawingPanel";
return;
}
// 只保存监控面板
if (pPanel->getMode() != DM_run) {
qDebug() << "Only run mode panels can be saved, current mode:" << pPanel->getMode();
return;
}
// 保存监控面板
auto pMonitor = dynamic_cast<MonitorPanel*>(pPanel);
if (!pMonitor) {
qWarning() << "Failed to cast to MonitorPanel";
return;
}
bool success = saveMonitorPanel(pMonitor);
if (success) {
QMessageBox::information(nullptr, QString("提示"),
QString::fromWCharArray(L"保存成功"));
} else {
QMessageBox::warning(nullptr, QString("警告"),
QString::fromWCharArray(L"保存失败"));
}
}
bool DiagramCavasPrivate::saveMonitorPanel(MonitorPanel* monitorPanel)
{
if (!monitorPanel) {
return false;
}
PowerEntity* entity = monitorPanel->getEntity();
if (!entity) {
qWarning() << "MonitorPanel has no entity";
return false;
}
Q_Q(DiagramCavas);
// 1. 保存HMI图片
QMap<QByteArray, HMIImageInfo>& imageMap = ProjectModelManager::instance().getHMIimageMap();
if (!saveHMIImages(imageMap)) {
qWarning() << "Failed to save HMI images";
return false;
}
// 2. 保存图片引用
FixedPortsModel* controller = monitorPanel->getModelController();
if (!controller) {
qWarning() << "MonitorPanel has no model controller";
return false;
}
QList<HMIImageRef> imageRefs = controller->getHMIimageRef();
if (!imageRefs.isEmpty()) {
QUuid hmiId = imageRefs.first().hmiId;
if (!saveImageReferences(imageRefs, hmiId)) {
qWarning() << "Failed to save image references";
return false;
}
}
// 3. 保存自定义图片引用
QList<HMICustomImageRef> customImageRefs = controller->getHMICustomImageRef();
if (!customImageRefs.isEmpty()) {
QUuid hmiId = customImageRefs.first().hmiId;
if (!saveCustomImageReferences(customImageRefs, hmiId)) {
qWarning() << "Failed to save custom image references";
return false;
}
}
// 4. 保存或更新HMI
QJsonObject diagramInfo = monitorPanel->getDiagramInfo();
if (!saveOrUpdateHMI(entity, diagramInfo)) {
qWarning() << "Failed to save/update HMI";
return false;
}
// 5. 发送更新信号
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm");
emit controller->HMIUpdated(entity->name(), QUuid(entity->id()), 1, timestamp);
qDebug() << "HMI saved successfully:" << entity->name() << "at" << timestamp;
return true;
}
bool DiagramCavasPrivate::saveHMIImages(QMap<QByteArray, HMIImageInfo>& imageMap)
{
if (imageMap.isEmpty()) {
qDebug() << "No HMI images to save";
return true;
}
QList<HMIImageInfo> imageList = imageMap.values();
bool success = DataBase::GetInstance()->insertHMIimagesWithCheck(imageList);
if (success) {
qDebug() << "Saved" << imageList.size() << "HMI images";
} else {
qWarning() << "Failed to save HMI images";
}
return success;
}
bool DiagramCavasPrivate::saveImageReferences(const QList<HMIImageRef>& imageRefs, const QUuid& hmiId)
{
if (imageRefs.isEmpty() || hmiId.isNull()) {
return true;
}
DataBase* db = DataBase::GetInstance();
// 检查是否已存在引用
QList<HMIImageRef> existingRefs = db->getHMIRefAll(hmiId);
if (!existingRefs.isEmpty()) {
// 删除旧的引用
bool deleted = db->removeHMIRefAll(hmiId);
if (!deleted) {
qWarning() << "Failed to remove old image references for HMI:" << hmiId;
return false;
}
}
// 插入新的引用
bool inserted = db->insertHMIimageRefBatch(imageRefs);
if (inserted) {
qDebug() << "Saved" << imageRefs.size() << "image references for HMI:" << hmiId;
} else {
qWarning() << "Failed to save image references for HMI:" << hmiId;
}
return inserted;
}
bool DiagramCavasPrivate::saveCustomImageReferences(const QList<HMICustomImageRef>& customImageRefs, const QUuid& hmiId)
{
if (customImageRefs.isEmpty() || hmiId.isNull()) {
return true;
}
DataBase* db = DataBase::GetInstance();
// 检查是否已存在自定义引用
QList<HMICustomImageRef> existingRefs = db->getHMICustomRefAll(hmiId);
if (!existingRefs.isEmpty()) {
// 删除旧的引用
bool deleted = db->removeHMICustomRefAll(hmiId);
if (!deleted) {
qWarning() << "Failed to remove old custom image references for HMI:" << hmiId;
return false;
}
}
// 插入新的自定义引用
bool inserted = db->insertHMICustomRefBatch(customImageRefs);
if (inserted) {
qDebug() << "Saved" << customImageRefs.size() << "custom image references for HMI:" << hmiId;
} else {
qWarning() << "Failed to save custom image references for HMI:" << hmiId;
}
return inserted;
}
bool DiagramCavasPrivate::saveOrUpdateHMI(PowerEntity* entity, QJsonObject diagramInfo)
{
if (!entity) {
return false;
}
QString hmiName = entity->name();
QUuid hmiUuid = QUuid(entity->id());
QString hmiDesc = entity->name(); // 使用名称作为描述
DataBase* db = DataBase::GetInstance();
// 检查HMI是否已存在
QUuid existingHmiId = db->getHMIdByName(hmiName);
if (existingHmiId.isNull()) {
// 创建新的HMI
bool inserted = db->insertHMI(hmiUuid, hmiName, hmiDesc, diagramInfo);
if (inserted) {
qDebug() << "Created new HMI:" << hmiName << "ID:" << hmiUuid;
}
return inserted;
} else {
// 更新现有HMI
bool updated = db->updateHMI(hmiName, diagramInfo);
if (updated) {
qDebug() << "Updated existing HMI:" << hmiName;
}
return updated;
}
}
MonitorPanel* DiagramCavasPrivate::getCurrentMonitorPanel() const
{
BaseDrawingPanel* drawingPanel = getCurrentDrawingPanel();
if (!drawingPanel) {
return nullptr;
}
if (drawingPanel->getMode() == DM_run) {
return dynamic_cast<MonitorPanel*>(drawingPanel);
}
return nullptr;
}
BaseDrawingPanel* DiagramCavasPrivate::getCurrentDrawingPanel() const
{
Q_Q(const DiagramCavas);
QMdiSubWindow* currentSubWindow = q->currentSubWindow();
if (!currentSubWindow) {
return nullptr;
}
QWidget* windowWidget = currentSubWindow->widget();
if (!windowWidget) {
return nullptr;
}
return dynamic_cast<BaseDrawingPanel*>(windowWidget);
}
bool DiagramCavasPrivate::saveAllPages()
{
if (m_mapMonitorPanel.isEmpty()) {
qDebug() << "No pages to save";
return true;
}
int successCount = 0;
int totalCount = 0;
for (auto it = m_mapMonitorPanel.begin(); it != m_mapMonitorPanel.end(); ++it) {
MonitorPanel* panel = it.value().first;
if (panel && panel->getMode() == DM_run) {
totalCount++;
if (saveMonitorPanel(panel)) {
successCount++;
m_modifiedPages.remove(it.key()); // 从修改列表中移除
}
}
}
qDebug() << "Saved" << successCount << "of" << totalCount << "pages";
return successCount == totalCount;
}
bool DiagramCavasPrivate::savePage(const QString& pageName)
{
if (!hasPanel(pageName)) {
qWarning() << "Page not found:" << pageName;
return false;
}
MonitorPanel* panel = getPanel(pageName);
if (!panel || panel->getMode() != DM_run) {
return false;
}
bool success = saveMonitorPanel(panel);
if (success) {
m_modifiedPages.remove(pageName);
}
return success;
}
int DiagramCavasPrivate::saveModifiedPages()
{
if (m_modifiedPages.isEmpty()) {
return 0;
}
int savedCount = 0;
for (const QString& pageName : m_modifiedPages) {
if (savePage(pageName)) {
savedCount++;
}
}
m_modifiedPages.clear();
return savedCount;
}
void DiagramCavasPrivate::markPageModified(const QString& pageName, bool modified)
{
if (modified) {
m_modifiedPages.insert(pageName);
} else {
m_modifiedPages.remove(pageName);
}
}
bool DiagramCavasPrivate::isPageModified(const QString& pageName) const
{
return m_modifiedPages.contains(pageName);
}
QList<QString> DiagramCavasPrivate::getModifiedPages() const
{
return m_modifiedPages.values();
}
void DiagramCavasPrivate::loadMonitorImpl(PowerEntity* p)
{
if (!p) {
qWarning() << "Cannot load monitor: PowerEntity is null";
return;
}
QString monitorName = p->name();
if (!hasPanel(monitorName)) {
// 加载HMI上下文
QJsonObject context = loadHMIContext(monitorName);
if (createAndLoadMonitor(p, context)) {
qDebug() << "Monitor created and loaded:" << monitorName;
} else {
qWarning() << "Failed to create and load monitor:" << monitorName;
}
} else {
// 激活已存在的监控面板
if (loadExistingMonitor(monitorName)) {
qDebug() << "Existing monitor activated:" << monitorName;
} else {
qWarning() << "Failed to activate existing monitor:" << monitorName;
}
}
// 选中目标属性
activateAndSelectMonitor(monitorName);
}
bool DiagramCavasPrivate::createAndLoadMonitor(PowerEntity* p, const QJsonObject& context)
{
Q_Q(DiagramCavas);
// 1. 创建监控面板
q->onSignal_addDrawingPanel(p, DiagramMode::DM_run);
// 获取新创建的面板
QString monitorName = p->name();
if (!hasPanel(monitorName)) {
qWarning() << "Failed to create monitor panel:" << monitorName;
return false;
}
MonitorPanel* panel = getPanel(monitorName);
QMdiSubWindow* subWindow = getSubWindow(monitorName);
if (!panel || !subWindow) {
qWarning() << "Failed to get created monitor components:" << monitorName;
return false;
}
// 2. 加载节点
if (!context.isEmpty()) {
panel->loadNodes(context);
// 3. 应用页面几何属性
if (context.contains("pageAttr") && context["pageAttr"].isObject()) {
QJsonObject pageAttr = context["pageAttr"].toObject();
applyPageGeometry(panel, subWindow, pageAttr);
}
} else {
qDebug() << "No context data for monitor, using default:" << monitorName;
}
return true;
}
bool DiagramCavasPrivate::loadExistingMonitor(const QString& name)
{
if (!hasPanel(name)) {
return false;
}
MonitorPanel* panel = getPanel(name);
QMdiSubWindow* subWindow = getSubWindow(name);
if (!panel || !subWindow) {
return false;
}
// 显示面板
panel->show();
// 设置为活动子窗口
Q_Q(DiagramCavas);
q->setActiveSubWindow(subWindow);
return true;
}
QJsonObject DiagramCavasPrivate::loadHMIContext(const QString& hmiName)
{
if (hmiName.isEmpty()) {
return QJsonObject();
}
DataBase* db = DataBase::GetInstance();
if (!db) {
qWarning() << "Database instance is null";
return QJsonObject();
}
QJsonObject context = db->getHMIContextByTag(hmiName);
if (context.isEmpty()) {
qDebug() << "No HMI context found for:" << hmiName;
} else {
qDebug() << "Loaded HMI context for:" << hmiName
<< "keys:" << context.keys();
}
return context;
}
void DiagramCavasPrivate::applyPageGeometry(MonitorPanel* panel,
QMdiSubWindow* subWindow,
const QJsonObject& pageAttr)
{
if (!panel || !subWindow || pageAttr.isEmpty()) {
return;
}
// 解析几何属性
int x = pageAttr.value("x").toInt();
int y = pageAttr.value("y").toInt();
int width = pageAttr.value("width").toInt();
int height = pageAttr.value("height").toInt();
// 验证几何属性
if (width <= 0 || height <= 0) {
qDebug() << "Invalid geometry, using default:"
<< "width =" << width << "height =" << height;
return;
}
// 确保窗口在屏幕范围内
QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
// 调整坐标和大小
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x + width > screenGeometry.width()) {
width = qMin(width, screenGeometry.width() - x);
}
if (y + height > screenGeometry.height()) {
height = qMin(height, screenGeometry.height() - y);
}
// 应用几何属性
subWindow->setGeometry(x, y, width, height);
qDebug() << "Applied page geometry:"
<< "x =" << x << "y =" << y
<< "width =" << width << "height =" << height;
}
void DiagramCavasPrivate::activateAndSelectMonitor(const QString& name)
{
if (!hasPanel(name)) {
return;
}
MonitorPanel* panel = getPanel(name);
if (!panel) {
return;
}
Q_Q(DiagramCavas);
// 选中目标属性
QObject* propertyProxy = panel->getPropertyProxy();
if (propertyProxy) {
q->onTargetSelected(propertyProxy);
} else {
qWarning() << "No property proxy for monitor:" << name;
}
}
void DiagramCavasPrivate::createHMIClickedImpl(const QString& sHMI, const QString& sStructPage, int modelType)
{
if (sHMI.isEmpty() || sStructPage.isEmpty()) {
qWarning() << "Cannot create HMI: empty HMI name or structure page";
return;
}
Q_Q(DiagramCavas);
// 1. 创建HMI图
QUuid hmiId;
PowerEntity* entity = nullptr;
if (!createHMIDiagram(sHMI, modelType, hmiId, entity)) {
qWarning() << "Failed to create HMI diagram:" << sHMI;
return;
}
// 2. 添加绘图面板
q->onSignal_addDrawingPanel(entity, DiagramMode::DM_run);
// 3. 加载结构到面板
if (!loadStructureToPanel(sHMI, sStructPage)) {
qWarning() << "Failed to load structure to panel:" << sHMI;
return;
}
// 4. 发送创建HMI信号
q->onSignal_createHMI(sHMI, hmiId);
// 5. 选中目标属性
if (hasPanel(sHMI)) {
MonitorPanel* panel = getPanel(sHMI);
if (panel) {
QObject* propertyProxy = panel->getPropertyProxy();
if (propertyProxy) {
q->onTargetSelected(propertyProxy);
}
}
}
qDebug() << "HMI created successfully:"
<< "name =" << sHMI
<< "id =" << hmiId
<< "model type =" << modelType;
}
bool DiagramCavasPrivate::createHMIDiagram(const QString& sHMI, int modelType, QUuid& outId, PowerEntity*& outEntity)
{
// 生成UUID
outId = QUuid::createUuid();
// 创建拓扑图
outEntity = TopologyManager::instance().createDiagram(
outId.toString(),
sHMI,
ModelFunctionType::RuntimeModel
);
if (!outEntity) {
qWarning() << "TopologyManager failed to create diagram:" << sHMI;
return false;
}
qDebug() << "Diagram created:"
<< "name =" << sHMI
<< "id =" << outId.toString();
return true;
}
bool DiagramCavasPrivate::loadStructureToPanel(const QString& panelName, const QString& sStructPage)
{
if (!hasPanel(panelName)) {
qWarning() << "Panel not found:" << panelName;
return false;
}
// 获取监控上下文
QJsonObject context = DataBase::GetInstance()->getMonitorContextByTag(sStructPage);
if (context.isEmpty()) {
qWarning() << "No monitor context found for structure page:" << sStructPage;
return false;
}
// 获取面板
MonitorPanel* panel = getPanel(panelName);
if (!panel) {
qWarning() << "Failed to get monitor panel:" << panelName;
return false;
}
// 加载节点
panel->loadNodes(context);
qDebug() << "Structure loaded to panel:"
<< panelName
<< "context keys:" << context.keys();
return true;
}