DiagramDesigner/diagramCavas/source/diagramCavas_p.cpp

1217 lines
34 KiB
C++
Raw Normal View History

2026-04-15 17:54:09 +08:00
// 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;
}