1217 lines
34 KiB
C++
1217 lines
34 KiB
C++
// 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;
|
||
}
|