From 32c9cdd15217c86f186b18cf41a55a8fe5c99a15 Mon Sep 17 00:00:00 2001 From: baiYue Date: Mon, 2 Mar 2026 20:15:22 +0800 Subject: [PATCH] optimize topology previewer --- CMakeLists.txt | 5 +- .../Qml/ValueEditor/FileSelector.qml | 4 +- .../include}/extraPropertyManager.h | 3 +- common/include/global.h | 24 +- .../include/structDataSource.h | 0 .../source}/extraPropertyManager.cpp | 11 +- .../source/structDataSource.cpp | 0 diagramCavas/CMakeLists.txt | 8 +- diagramCavas/include/baseDrawingPanel.h | 4 +- .../include/basePannelPropertyProxy.h | 6 - diagramCavas/include/dataSourceDlg.h | 2 +- diagramCavas/include/diagramCavas.h | 18 +- .../diagramEditorBayDetailSettingDlg.h | 4 +- .../diagramEditorBayPreviewDlg.h | 1 + .../diagramEditorTransDetailSettingDlg.h | 5 +- .../diagramEditorTransPreviewDlg.h | 1 + .../graphicsDataModel/diagramEditorModel.h | 8 +- .../graphicsDataModel/fixedPortsModel.h | 15 +- .../graphicsItem/electricConnectLineItem.h | 63 +- .../include/graphicsItem/graphicsBaseItem.h | 5 +- diagramCavas/include/monitorPanel.h | 6 +- .../include/monitorSelectedItemsDlg.h | 2 +- diagramCavas/source/baseDrawingPanel.cpp | 8 +- diagramCavas/source/baseInfoDlg.cpp | 5 +- .../source/basePannelPropertyProxy.cpp | 20 - diagramCavas/source/dataSourceDlg.cpp | 2 +- diagramCavas/source/diagramCavas.cpp | 23 +- .../diagramEditorBayDetailAddDlg.cpp | 3 + .../diagramEditorBayDetailSettingDlg.cpp | 42 +- .../diagramEditorBayPreviewDlg.cpp | 11 +- .../diagramEditor/diagramEditorPreviewDlg.cpp | 21 +- .../diagramEditorTransDetailAddDlg.cpp | 3 + .../diagramEditorTransDetailSettingDlg.cpp | 65 +- .../diagramEditorTransPreviewDlg.cpp | 8 +- .../source/diagramEditor/editPanel.cpp | 78 +- diagramCavas/source/drawingPanel.cpp | 18 +- .../graphicsDataModel/diagramEditorModel.cpp | 258 ++++-- .../graphicsDataModel/fixedPortsModel.cpp | 237 ++--- .../graphicsItem/electricConnectLineItem.cpp | 844 ++++++++++++------ .../source/graphicsItem/graphicsBaseItem.cpp | 2 +- diagramCavas/source/monitorPanel.cpp | 14 +- diagramCavas/source/structDataPreviewDlg.cpp | 2 +- diagramCavas/source/util/baseSelector.cpp | 7 +- .../source/util/linkMovingSelector.cpp | 27 +- diagramCavas/source/util/movingSelector.cpp | 6 +- .../ui/diagramEditorBayDetailAddDlg.ui | 4 +- .../ui/diagramEditorBayDetailSettingDlg.ui | 44 +- .../ui/diagramEditorTransDetailSettingDlg.ui | 96 +- include/monitorItemsDlg.h | 13 +- include/topologyView.h | 23 +- source/mainwindow.cpp | 2 + source/monitorItemsDlg.cpp | 101 ++- source/topologyView.cpp | 606 ++++++++----- 53 files changed, 1762 insertions(+), 1026 deletions(-) rename {diagramCavas/include/instance => common/include}/extraPropertyManager.h (89%) rename {diagramCavas => common}/include/structDataSource.h (100%) rename {diagramCavas/source/instance => common/source}/extraPropertyManager.cpp (84%) rename {diagramCavas => common}/source/structDataSource.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0564ba..297e695 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,8 @@ set(H_HEADER_FILES common/include/compiler.hpp common/include/export.hpp common/include/operatingSystem.hpp - + common/include/structDataSource.h + common/include/extraPropertyManager.h ) set(CPP_SOURCE_FILES source/main.cpp @@ -97,6 +98,8 @@ set(CPP_SOURCE_FILES common/source/global.cpp common/source/tools.cpp common/source/baseProperty.cpp + common/source/structDataSource.cpp + common/source/extraPropertyManager.cpp ) set(UI_FILES ui/mainwindow.ui diff --git a/PropertyEditor/resources/Qml/ValueEditor/FileSelector.qml b/PropertyEditor/resources/Qml/ValueEditor/FileSelector.qml index 470e0b4..9e5584d 100644 --- a/PropertyEditor/resources/Qml/ValueEditor/FileSelector.qml +++ b/PropertyEditor/resources/Qml/ValueEditor/FileSelector.qml @@ -10,7 +10,7 @@ Item { // 属性接口 property var value - property string fileFilter: "所有文件 (*.*)" // 文件过滤器 + property string fileFilter: "svg(*.svg)" // 文件过滤器 property bool selectMultiple: false // 是否多选 implicitHeight: fileBox.implicitHeight @@ -55,6 +55,8 @@ Item { FileDialog { id: fileDialog + modality: Qt.WindowModal // 改为窗口模态 + options: FolderDialog.DontUseNativeDialog // 尝试禁用原生对话框 title: control.selectMultiple ? "选择多个文件" : "选择文件" fileMode: control.selectMultiple ? FileDialog.OpenFiles : FileDialog.OpenFile diff --git a/diagramCavas/include/instance/extraPropertyManager.h b/common/include/extraPropertyManager.h similarity index 89% rename from diagramCavas/include/instance/extraPropertyManager.h rename to common/include/extraPropertyManager.h index 907aab0..03a504c 100644 --- a/diagramCavas/include/instance/extraPropertyManager.h +++ b/common/include/extraPropertyManager.h @@ -32,7 +32,8 @@ public: QStringList getGrids() const; QStringList getZones(const QString& grid = "") const; QStringList getStations(const QString& grid = "", const QString& zone = "") const; - +private: + QString removeSuffix(const QString& str); //移除最后一个下划线后的内容 (处理各种tag后缀) private: QMap m_props; // 内存缓存 }; diff --git a/common/include/global.h b/common/include/global.h index c97abdd..0e8225e 100644 --- a/common/include/global.h +++ b/common/include/global.h @@ -1219,9 +1219,9 @@ struct itemPageInfo //page中保存的item信息(大小,位置etc) double dRotate = 0.0; }; -/*********************运行时************************/ -struct monitorRelationSturctItem //监控关系结构item +struct RelationSturctItem //层级关系结构item { + QString sVoltageLevel; int nCategory; //类型 0设备1间隔 int nEquipType; //设备类别 QString sName; //名称 @@ -1229,6 +1229,7 @@ struct monitorRelationSturctItem //监控关系结构item QJsonObject toJson() const { QJsonObject obj; + obj["sVoltageLevel"] = sVoltageLevel; obj["nCategory"] = nCategory; obj["nEquipType"] = nEquipType; obj["sName"] = sName; @@ -1238,6 +1239,7 @@ struct monitorRelationSturctItem //监控关系结构item // 从JSON对象解析 void fromJson(const QJsonObject& json) { + sVoltageLevel = json["sVoltageLevel"].toString(); nCategory = json["nCategory"].toInt(); nEquipType = json["nEquipType"].toInt(); sName = json["sName"].toString(); @@ -1250,18 +1252,18 @@ struct monitorRelationSturctItem //监控关系结构item } // 重载相等运算符 - bool operator==(const monitorRelationSturctItem& other) const { + bool operator==(const RelationSturctItem& other) const { return uid == other.uid && sName == other.sName && nCategory == other.nCategory; } }; -struct monitorRelationItem //监控关系item +struct RelationItem //层级关系item { - monitorRelationSturctItem parent; - monitorRelationSturctItem item; - QList subList; + RelationSturctItem parent; + RelationSturctItem item; + QList subList; QJsonObject toJson() const { QJsonObject obj; @@ -1288,7 +1290,7 @@ struct monitorRelationItem //监控关系item subList.clear(); QJsonArray subArray = json["subList"].toArray(); for (const QJsonValue& subValue : subArray) { - monitorRelationSturctItem sub; + RelationSturctItem sub; sub.fromJson(subValue.toObject()); subList.append(sub); } @@ -1300,7 +1302,7 @@ struct monitorRelationItem //监控关系item } // 添加子项 - void addSubItem(const monitorRelationSturctItem& subItem) { + void addSubItem(const RelationSturctItem& subItem) { subList.append(subItem); } @@ -1316,7 +1318,7 @@ struct monitorRelationItem //监控关系item } // 查找子项 - monitorRelationSturctItem* findSubItem(const QUuid& subUid) { + RelationSturctItem* findSubItem(const QUuid& subUid) { for (auto& sub : subList) { if (sub.uid == subUid) { return ⊂ @@ -1326,6 +1328,8 @@ struct monitorRelationItem //监控关系item } }; +/*********************运行时************************/ + struct monitorItemAttributeInfo //单个监控item属性 { QString sGroup; //所属组别 diff --git a/diagramCavas/include/structDataSource.h b/common/include/structDataSource.h similarity index 100% rename from diagramCavas/include/structDataSource.h rename to common/include/structDataSource.h diff --git a/diagramCavas/source/instance/extraPropertyManager.cpp b/common/source/extraPropertyManager.cpp similarity index 84% rename from diagramCavas/source/instance/extraPropertyManager.cpp rename to common/source/extraPropertyManager.cpp index a71d1b0..cc9d393 100644 --- a/diagramCavas/source/instance/extraPropertyManager.cpp +++ b/common/source/extraPropertyManager.cpp @@ -1,5 +1,5 @@ // extraPropertyManager.cpp -#include "instance/extraPropertyManager.h" +#include "extraPropertyManager.h" #include "dataBase.h" #include @@ -12,6 +12,7 @@ bool ExtraPropertyManager::loadAll() { QList lstPro = DataBase::GetInstance()->getAllExtraProperty(); for(auto& pro:lstPro){ + pro.bay_tag = removeSuffix(pro.bay_tag); m_props[pro.code] = pro; count++; } @@ -66,3 +67,11 @@ QStringList ExtraPropertyManager::getGrids() const { } return QStringList(grids.begin(), grids.end()); } + +QString ExtraPropertyManager::removeSuffix(const QString& str) +{ + int lastUnderscore = str.lastIndexOf('_'); + if (lastUnderscore == -1) return str; // 没有下划线 + + return str.left(lastUnderscore); +} diff --git a/diagramCavas/source/structDataSource.cpp b/common/source/structDataSource.cpp similarity index 100% rename from diagramCavas/source/structDataSource.cpp rename to common/source/structDataSource.cpp diff --git a/diagramCavas/CMakeLists.txt b/diagramCavas/CMakeLists.txt index e7b8c61..1437d25 100644 --- a/diagramCavas/CMakeLists.txt +++ b/diagramCavas/CMakeLists.txt @@ -43,7 +43,6 @@ set(DIAGRAMCAVAS_HEADER_FILES include/diagramConnectSetting.h include/structDataPreviewDlg.h include/titleBar.h - include/structDataSource.h include/structDataMeasurementModel.h include/structDataPropertyModel.h include/structDataMeasurementDelegate.h @@ -127,7 +126,6 @@ set(DIAGRAMCAVAS_HEADER_FILES include/util/selectorManager.h include/util/subMovingSelector.h include/instance/dataAccessor.h - include/instance/extraPropertyManager.h include/propertyType/CustomGadget.h include/propertyType/CustomType.h @@ -142,6 +140,8 @@ set(DIAGRAMCAVAS_HEADER_FILES ../common/include/compiler.hpp ../common/include/export.hpp ../common/include/operatingSystem.hpp + ../common/include/structDataSource.h + ../common/include/extraPropertyManager.h ) set(DIAGRAMCAVAS_SOURCE_FILES @@ -186,7 +186,6 @@ set(DIAGRAMCAVAS_SOURCE_FILES source/diagramConnectSetting.cpp source/structDataPreviewDlg.cpp source/titleBar.cpp - source/structDataSource.cpp source/structDataMeasurementModel.cpp source/structDataPropertyModel.cpp source/structDataMeasurementDelegate.cpp @@ -270,7 +269,6 @@ set(DIAGRAMCAVAS_SOURCE_FILES source/util/selectorManager.cpp source/util/subMovingSelector.cpp source/instance/dataAccessor.cpp - source/instance/extraPropertyManager.cpp source/propertyType/PropertyTypeCustomization_CustomType.cpp source/propertyType/propertyTypeCustomization_DataSourceType.cpp @@ -279,6 +277,8 @@ set(DIAGRAMCAVAS_SOURCE_FILES ../common/source/baseProperty.cpp ../common/source/tools.cpp ../common/source/global.cpp + ../common/source/structDataSource.cpp + ../common/source/extraPropertyManager.cpp ) set(UI_FILES diff --git a/diagramCavas/include/baseDrawingPanel.h b/diagramCavas/include/baseDrawingPanel.h index 90d8094..9f81a9d 100644 --- a/diagramCavas/include/baseDrawingPanel.h +++ b/diagramCavas/include/baseDrawingPanel.h @@ -50,13 +50,13 @@ public: QString getGenerateByPanel() {return _sGenerateByPanel;} PowerEntity* getEntity() {return _pEntity;} - BasePannelPropertyProxy* getPropertyProxy(){return _pPropertyProxy;} + BasePannelPropertyProxy* getPropertyProxy(); signals: void panelDelete(const QString&,int); protected: virtual void closeEvent(QCloseEvent *closeEvent) {}; protected: - BasePannelPropertyProxy* _pPropertyProxy; //属性页代理 + QPointer _pPropertyProxy; //属性页代理 protected: DesignerView* m_pGraphicsView; DesignerScene* m_pGraphicsScene; diff --git a/diagramCavas/include/basePannelPropertyProxy.h b/diagramCavas/include/basePannelPropertyProxy.h index 86d66f0..9961740 100644 --- a/diagramCavas/include/basePannelPropertyProxy.h +++ b/diagramCavas/include/basePannelPropertyProxy.h @@ -14,8 +14,6 @@ public: Q_PROPERTY(QString Name READ getName WRITE setName) Q_PROPERTY(QSize Size READ getSize WRITE setSize) Q_PROPERTY(PannelColorGadget* Color READ getColorGadgetPtr WRITE setColorGadgetPtr) - //Q_PROPERTY(QColor BackColor READ getBackColor WRITE setBackColor) - //Q_PROPERTY(QColor GridColor READ getGridColor WRITE setGridColor) public: BasePannelPropertyProxy(BaseDrawingPanel*); ~BasePannelPropertyProxy(); @@ -26,10 +24,6 @@ public: virtual void setSize(QSize); PannelColorGadget* getColorGadgetPtr(){return _pColorGadget;} void setColorGadgetPtr(PannelColorGadget* p){_pColorGadget = p;} - // virtual QColor getBackColor() const; - // virtual void setBackColor(QColor); - // virtual QColor getGridColor() const; - // virtual void setGridColor(QColor); protected: BaseDrawingPanel* _pPanel; PannelColorGadget* _pColorGadget; diff --git a/diagramCavas/include/dataSourceDlg.h b/diagramCavas/include/dataSourceDlg.h index ccdb28a..d6a089c 100644 --- a/diagramCavas/include/dataSourceDlg.h +++ b/diagramCavas/include/dataSourceDlg.h @@ -58,7 +58,7 @@ private: Ui::dataSourceDlg *ui; QStandardItemModel* _treeModel; QStandardItem* m_currentCategoryItem; //当前操作对象 - ExtraPropertyManager* _pExtraProManager; //使用外部的manager + ExtraPropertyManager* _pExtraProManager; StructDataSource* m_dataSource; QListWidgetItem* _curProperty; //当前属性 QString m_targetPropertyCode; //打开的目标code diff --git a/diagramCavas/include/diagramCavas.h b/diagramCavas/include/diagramCavas.h index 9f044f5..a2747b9 100644 --- a/diagramCavas/include/diagramCavas.h +++ b/diagramCavas/include/diagramCavas.h @@ -45,11 +45,12 @@ public: public: void initial(); signals: - void prepareUpdateItems(QList,bool refresh); - void prepareSelectItems(QList); + void prepareUpdateItems(QList,bool refresh); + void prepareSelectItems(QList); void updateMonitorList(QString,QPair,int nMode = 0); //0新增1删除 - void createdMonitorItems(QList); //创建的监控中item个数 + void createdMonitorItems(QList); //创建的监控中item个数 void selectTarget(QObject*); + void prepareUpdateTopology(QList,bool refresh); //更新层级数 public slots: void onSignal_addDrawingPanel(PowerEntity* p,DiagramMode = DM_edit,QString parent = QString()); //parent:派生运行时的page void onSignal_addGraphicsItem(modelStateInfo&); @@ -79,6 +80,9 @@ public slots: void onSignal_openStructDataPreview(); //打开结构数据界面 void onCreateTestBaseModelDiagram(); //生成测试基模图 + + /****************************拓扑关系(层级关系)******************************/ + void onSignal_updateTopology(QList,bool); //更新拓扑列表 /******************************生成组态***********************************/ void onSignal_createEditPanel(QString,QUuid); void onSignal_prepareOpenSetting(QString); @@ -91,11 +95,11 @@ public slots: /*********************************间隔**************************************/ void onSignl_openCurrentBay(); /********************************运行时**********************************/ - void onSignal_updateCurItems(QList,bool); //更新当前设备列表 - void onSignal_selectedItems(QList); //当前选中设备 - void onSignal_generate(QString,QList); //使用选中设备生成监控 (监控名,设备) + void onSignal_updateCurItems(QList,bool); //更新当前设备列表 + void onSignal_selectedItems(QList); //当前选中设备 + void onSignal_generate(QString,QList); //使用选中设备生成监控 (监控名,设备) void onSignal_monitorCreated(QString,QPair); //监控已创建 - void onSignal_monitorItemCreated(QList); //监控中创建的对象 + void onSignal_monitorItemCreated(QList); //监控中创建的对象 void onSignal_monitorSelected(DiagramInfo); //监控选中 void onSignal_saveMonitor(QList>); //保存选中的监控 diff --git a/diagramCavas/include/diagramEditor/diagramEditorBayDetailSettingDlg.h b/diagramCavas/include/diagramEditor/diagramEditorBayDetailSettingDlg.h index 294a7f4..38a3acb 100644 --- a/diagramCavas/include/diagramEditor/diagramEditorBayDetailSettingDlg.h +++ b/diagramCavas/include/diagramEditor/diagramEditorBayDetailSettingDlg.h @@ -18,7 +18,7 @@ class DiagramEditorBayDetailSettingDlg : public QDialog { Q_OBJECT public: - DiagramEditorBayDetailSettingDlg(QWidget *parent = nullptr); + DiagramEditorBayDetailSettingDlg(QWidget *parent = nullptr,DiagramEditorModel* p = nullptr); ~DiagramEditorBayDetailSettingDlg(); void initial(); @@ -33,6 +33,7 @@ public: DiagramEditorModel* getModel() {return _pModel;} DiagramEditorBayBlock* getCurBlock(){return _curOperateObj;} DiagramEditorWizard* getWizard() {return _pWizard;} + void showPreview(); //预览间隔 public slots: void onAddClicked(); void onOkClicked(); @@ -41,7 +42,6 @@ public slots: void onRouteDeleteClicked(); void onRouteRbtnClicked(const QPoint &pos); //线路右键菜单 void onRouteEditClicked(); - void onPreviewClicked(); //预览间隔 private: Ui::diagramEditorBayDetailSettingDlg *ui; DiagramEditorBayDetailAddDlg* _pAddDlg; diff --git a/diagramCavas/include/diagramEditor/diagramEditorBayPreviewDlg.h b/diagramCavas/include/diagramEditor/diagramEditorBayPreviewDlg.h index b91cfa8..46f0895 100644 --- a/diagramCavas/include/diagramEditor/diagramEditorBayPreviewDlg.h +++ b/diagramCavas/include/diagramEditor/diagramEditorBayPreviewDlg.h @@ -20,6 +20,7 @@ public: void initial(); void showDlg(int nLayout); //0纵向1横向 void setParent(DiagramEditorBayDetailSettingDlg* p) {_pParent = p;} + void setSceneRect(const QRect); //void updateModelData(); //根据设置更新data中布局、方向 private: EditView* _pView; diff --git a/diagramCavas/include/diagramEditor/diagramEditorTransDetailSettingDlg.h b/diagramCavas/include/diagramEditor/diagramEditorTransDetailSettingDlg.h index fee6a9f..addb6f7 100644 --- a/diagramCavas/include/diagramEditor/diagramEditorTransDetailSettingDlg.h +++ b/diagramCavas/include/diagramEditor/diagramEditorTransDetailSettingDlg.h @@ -19,7 +19,7 @@ class DiagramEditorTransDetailSettingDlg : public QDialog { Q_OBJECT public: - DiagramEditorTransDetailSettingDlg(QWidget *parent = nullptr); + DiagramEditorTransDetailSettingDlg(QWidget *parent = nullptr,DiagramEditorModel* p = nullptr); ~DiagramEditorTransDetailSettingDlg(); void initial(); @@ -36,6 +36,7 @@ public: DiagramEditorModel* getModel() {return _pModel;} DiagramEditorTransformerBlock* getCurBlock(){return _curOperateObj;} DiagramEditorWizard* getWizard() {return _pWizard;} + void showPreview(); public slots: void onAddClicked(); void onOkClicked(); @@ -44,8 +45,6 @@ public slots: void onRouteDeleteClicked(); void onRouteRbtnClicked(const QPoint &pos); //线路右键菜单 void onRouteEditClicked(); - void onPreviewNeutralClicked(); //中性点成套装置预览 - void onPreviewTransClicked(); //预览变压器 private: Ui::diagramEditorTransDetailSettingDlg *ui; DiagramEditorTransDetailAddDlg* _pAddDlg; diff --git a/diagramCavas/include/diagramEditor/diagramEditorTransPreviewDlg.h b/diagramCavas/include/diagramEditor/diagramEditorTransPreviewDlg.h index efad416..1fb1915 100644 --- a/diagramCavas/include/diagramEditor/diagramEditorTransPreviewDlg.h +++ b/diagramCavas/include/diagramEditor/diagramEditorTransPreviewDlg.h @@ -21,6 +21,7 @@ public: void showDlg(int nType); //显示模式,0高压侧1中压侧2低压侧3变压器 void setParent(DiagramEditorTransDetailSettingDlg* p) {_pParent = p;} void updateModelData(int showType); //根据设置更新data中布局、方向,0变压器,1高压侧2中压侧3低压侧 + void setSceneRect(const QRect rec); private: EditView* _pView; EditPreviewScene* _pScene; diff --git a/diagramCavas/include/graphicsDataModel/diagramEditorModel.h b/diagramCavas/include/graphicsDataModel/diagramEditorModel.h index 9ccd5b7..fcd133b 100644 --- a/diagramCavas/include/graphicsDataModel/diagramEditorModel.h +++ b/diagramCavas/include/graphicsDataModel/diagramEditorModel.h @@ -39,9 +39,9 @@ public: EditPanel* getPanel(){return _pPanel;} void setWizard(QPointer p){_pWizard = p;} QMap getPreviewItem(){return _previewItem;}; - void clearItems(){_previewItem.clear();} + void clearItems(); - void generatePreview(); //生成预览 + void generatePreview(bool bVisible = true); //生成预览 void calculateBlockPos(); //重新计算block位置 void setItemInBlockPos(); //设置block中的item位置 void refreshConnection(); //刷新连接线 @@ -56,6 +56,7 @@ public: void setCurTransComponentModel(QStandardItemModel* p) {_pCurTransComponent = p;} QStandardItemModel* setCurTransComponentModel() {return _pCurTransComponent;} void setCurPreviewScene(EditBaseScene* p) {_pCurPreviewScene = p;} + EditBaseScene* getCurPreviewScene(){return _pCurPreviewScene;} QStandardItem* getNameItem(const QString&,int nFrom = 0); //获取返回当前设备模型中的name项 nFrom,0间隔1变压器 void generateItemByModel(QStandardItemModel* pModel,DiagramEditorBaseBlock* pBlock,int nFrom = 0,QPoint delta = QPoint(0,0)); //0间隔1变压器 @@ -68,7 +69,8 @@ public: QByteArray getWizardInfo(); //返回二进制wizard设置 void setWizardInfo(const QByteArray&); //二进制设置wizard - +signals: + void updateTopologyItems(QList,bool); //更新当前拓扑列表 <连接关系,是否刷新> private: void bulidAndLinkComponent(QList,QMap,DiagramEditorBaseBlock* pParent = nullptr); //生成并连接线路上的设备 lst,mapComponents(从map中获取正确数据) QByteArray serializeWizardData(const DiagramEditorProjectInfo &data); //序列化eidtor向导设置数据 diff --git a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h index 656a8d2..441cf2d 100644 --- a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h +++ b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h @@ -105,12 +105,12 @@ public: QJsonObject turnListToJson(QList lst,QString sInerTag,QString sOutTag); //将list转换为QJsonObject, QList turnJsonArrToList(QJsonObject obj,QString sInner,QString sOut); /*************************监控(运行时)**************************/ - void generateMonitor(QString,QList); //生成监控 (监控名,选中的设备列表) + void generateMonitor(QString,QList); //生成监控 (监控名,选中的设备列表) void generateMonitorConfig(MonitorPanel*); //生成监控配置参数结构 void setMonitorPara(QMap> map){m_monitorPara = map;} QMap>& getMonitorPara() {return m_monitorPara;} - void setMonitorRelation(QList lst){m_lstMonitorRelation = lst;} - QList getMonitorRelation() {return m_lstMonitorRelation;} + void setMonitorRelation(QList lst){m_lstMonitorRelation = lst;} + QList getMonitorRelation() {return m_lstMonitorRelation;} void monitorItemSelected(QUuid); //运行时item选中事件 void monitorItemDetailAttr(QUuid); //显示属性详情 @@ -130,11 +130,12 @@ public: ItemPropertyDlg* getCurItemPropertyDlg() {return m_curPropertyDlg;} Q_SIGNALS: void activatePage(const QString&); //激活当前model所在page - void updateCurrentItems(QList,bool); //更新当前组态元件列表 <名称,uid> - void itemSelected(QList); //发送选中的元件 + void updateCurrentItems(QList,bool); //更新当前组态元件列表 <连接关系,是否刷新> + void itemSelected(QList); //发送选中的元件 void monitorCreated(QString,QPair); //监控创建信号 <工程page,<监控page,page_uid>> - void monitorItems(QList); //发送创建成功的Items + void monitorItems(QList); //发送创建成功的Items void dataUpdated(); //数据更新通知 + void updateTopologyItems(QList,bool); //更新当前拓扑列表 <连接关系,是否刷新> public: void setPageName(QString s) {_pageName = s;} //设置表名称 QString pageName() const {return _pageName;} @@ -186,7 +187,7 @@ private: QMap> m_monitorPara; //监控参数 QMap>> m_monitorStateMap; //元件状态对照表 > QMap> m_monitorDisplaySetting; //元件设置 - QList m_lstMonitorRelation; //监控item层级关系 + QList m_lstMonitorRelation; //监控item层级关系 ItemPropertyDlg* m_curPropertyDlg; QTimer* m_dataTimer; //获取数据的定时器 diff --git a/diagramCavas/include/graphicsItem/electricConnectLineItem.h b/diagramCavas/include/graphicsItem/electricConnectLineItem.h index 9642b52..5bd1431 100644 --- a/diagramCavas/include/graphicsItem/electricConnectLineItem.h +++ b/diagramCavas/include/graphicsItem/electricConnectLineItem.h @@ -7,6 +7,14 @@ class ElectricConnectLineItem : public GraphicsProjectModelItem { +public: + enum UShapeType { + UShape_Unknown, + UShape_TopOpen, // 开口向上 + UShape_BottomOpen, // 开口向下 + UShape_LeftOpen, // 开口向左 + UShape_RightOpen // 开口向右 + }; public: ElectricConnectLineItem(QGraphicsItem *parent = 0); ElectricConnectLineItem(const ElectricConnectLineItem&); //暂不拷贝位置关系,由线自己计算 @@ -17,12 +25,27 @@ public: void setEndPoint(const QPointF& p); QPainterPath getPoints(void) const { return m_points; } - void moveLine(QPointF); //鼠标点击拖动 + void startDrag(const QPointF& scenePos); + void updateDrag(const QPointF& scenePos); + void endDrag(); + void setLastPoint(const QPointF& point); + void setPath(const QPainterPath& path); + QPainterPath path() const; + void resetCurLine(){_curLine = QPoint();} void calculatePath(); + + virtual QPainterPath shape() const override; + virtual QRectF boundingRect() const override; + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + +protected: + void initial(); +private: + //路径计算相关 void generateAvoidancePath(const QPointF& start, const QPointF& end,const QList& obstacleShapes); // 使用形状进行避障 double calculatePathLength(const QList& path); - bool lineIntersectsRect(const QLineF& line, const QRectF& rect); + bool lineIntersectsRect(const QLineF& line, const QRectF& rect) const; bool isSegmentSafe(const QPointF& p1, const QPointF& p2,const QList& components); bool isPathSafe(const QList& path,const QList& components); bool segmentPenetratesComponent(const QLineF& segment,const QRectF& component); @@ -33,18 +56,42 @@ public: void generateForcedRectilinearBypass(const QPointF& start, const QPointF& end,const QList& components); QRectF findFirstBlockingComponent(const QPointF& start, const QPointF& end,const QList& components); - virtual QPainterPath shape() const override; - virtual QRectF boundingRect() const override; - virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + //线段拖拽相关 + double distancePointToLine(const QLineF& line, const QPointF& point) const; + void ensureEnoughPointsForDrag(); + void debugPathState(const QString& context) const; + + QVector extractSegmentsFromPainterPath() const; + void collectBoundaryBypassPaths(const QPointF& start, const QPointF& end,const QList& obstacles,QMultiMap>& paths); + void collectBoundaryPath(const QPointF& start, const QPointF& end,const QList& obstacles,QMultiMap>& paths,const QRectF& bounds, bool useTop); + QRectF getSceneBounds() const; + QList generateForcedBypass(const QPointF& start, const QPointF& end,const QList& components); + + // 拖拽实现 + int findSegmentAt(const QList& points,const QPointF& itemPos) const; + double distanceToSegment(const QLineF& segment, const QPointF& point) const; + void fixConnections(int segmentIndex, bool isVertical); + QList extractPointsFromPath() const; + QList extractPointsFromPath(const QPainterPath& path) const; + void applyPointsToPath(const QList& points); + void fixConnections(QList& points, int segmentIndex, bool isVertical); + void validateAndFixPath(); + void updateBoundingRect(); -protected: - void initial(); private: QPainterPath m_points; - QPainterPath m_pointsBoundingRect; //包裹点的矩形集合 QList m_lstPoints; QPoint _curLine; //参数1用点序号表示的当前线段起始点,参数2表示线段方向 + struct DragState { + bool isActive = false; + int segmentIndex = -1; + bool isVertical = false; + QPointF startScenePos; + QPainterPath originalPath; + }; + + DragState m_dragData; }; #endif diff --git a/diagramCavas/include/graphicsItem/graphicsBaseItem.h b/diagramCavas/include/graphicsItem/graphicsBaseItem.h index ae56152..e3a68f6 100644 --- a/diagramCavas/include/graphicsItem/graphicsBaseItem.h +++ b/diagramCavas/include/graphicsItem/graphicsBaseItem.h @@ -184,7 +184,7 @@ public: Q_ENUM(RotateAngle); Q_PROPERTY(QString Name READ getName WRITE setName) - Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition) + Q_PROPERTY(QPointF Position READ getPosition WRITE setPosition NOTIFY posChanged) Q_PROPERTY(QRectF Size READ getSize WRITE setSize) Q_PROPERTY(RotateAngle Rotation READ getRotateAngle WRITE setRotateAngle) Q_PROPERTY(QFileInfo Image READ getImage_1 WRITE setImage_1) @@ -195,6 +195,7 @@ public: virtual GraphicsBaseItem* clone() const = 0; signals: void itemRotated(GraphicsBaseItem*); + void posChanged(); public: virtual QString getName() const; virtual void setName(QString); @@ -522,7 +523,7 @@ public slots: void onUpdateData(); //data发送的更新通知 protected: void rearrangeDynamicText(); //重新设置动态数据的布局 - QList getComponentCollisionRects() const; //获取图所有碰撞矩形 + QList getAllComponentRects() const; //获取图所有碰撞矩形 QList getObstacleShapes() const; //获取所有碰撞shape protected: FixedPortsModel* _pHandle; diff --git a/diagramCavas/include/monitorPanel.h b/diagramCavas/include/monitorPanel.h index 9b22130..d0731db 100644 --- a/diagramCavas/include/monitorPanel.h +++ b/diagramCavas/include/monitorPanel.h @@ -26,7 +26,7 @@ public: void setParentPage(const QString& str) {_sParentPage = str;} QString getParentPage() {return _sParentPage;} - void updateSelectedItems(QList,bool); + void updateSelectedItems(QList,bool); QStandardItemModel* getLstModel() {return _itemListmodel;} void initMonitorConfig(); //初始化参数设置(每个运行时可能不同) @@ -39,8 +39,8 @@ public: MonitorConfigDlg* getMonitorConfigDlg() {return _pConfigDlg;} public: //对层级关系的序列化与反序列化 - QJsonArray serializeRelationToJsonArray(const QList& data) const; - bool deserializeRelationFromJsonArray(const QJsonArray& jsonArray, QList& result); + QJsonArray serializeRelationToJsonArray(const QList& data) const; + bool deserializeRelationFromJsonArray(const QJsonArray& jsonArray, QList& result); //对para的序列化与反序列化 QJsonArray serializeParaToJsonArray(const QMap>& data) const; bool deserializeParaFromJsonArray(const QJsonArray& jsonArray,QMap>& result); diff --git a/diagramCavas/include/monitorSelectedItemsDlg.h b/diagramCavas/include/monitorSelectedItemsDlg.h index b03109d..34591df 100644 --- a/diagramCavas/include/monitorSelectedItemsDlg.h +++ b/diagramCavas/include/monitorSelectedItemsDlg.h @@ -5,7 +5,7 @@ #include #include -struct monitorRelationItem; +struct RelationItem; class MonitorSideBarDlg; class QVBoxLayout; diff --git a/diagramCavas/source/baseDrawingPanel.cpp b/diagramCavas/source/baseDrawingPanel.cpp index f029383..a7577ac 100644 --- a/diagramCavas/source/baseDrawingPanel.cpp +++ b/diagramCavas/source/baseDrawingPanel.cpp @@ -20,7 +20,6 @@ BaseDrawingPanel::BaseDrawingPanel(PowerEntity* pEntity,QWidget *parent,DiagramM ,_verticalLayout(nullptr) ,_horizontalLayout(nullptr) ,_hSplitter(nullptr) - ,_pPropertyProxy(nullptr) { _pEntity = pEntity; _pModel = new FixedPortsModel(pEntity); @@ -66,8 +65,6 @@ BaseDrawingPanel::~BaseDrawingPanel() { //if(_pModel) // delete _pModel; - if(_pPropertyProxy) - delete _pPropertyProxy; } QGraphicsScene* BaseDrawingPanel::getQGraphicsScene() @@ -80,6 +77,11 @@ DesignerScene* BaseDrawingPanel::getDesignerScene() return m_pGraphicsScene; } +BasePannelPropertyProxy* BaseDrawingPanel::getPropertyProxy() +{ + return _pPropertyProxy.data(); +} + SelectorManager* BaseDrawingPanel::selectorManager() const { if(m_pSelectorManager) diff --git a/diagramCavas/source/baseInfoDlg.cpp b/diagramCavas/source/baseInfoDlg.cpp index 409e739..823e71e 100644 --- a/diagramCavas/source/baseInfoDlg.cpp +++ b/diagramCavas/source/baseInfoDlg.cpp @@ -61,7 +61,8 @@ QMap BaseInfoDlg::getPropertyValue(BaseProperty* pPro if(pPro) { pPro->setTag(ui->le_tag->text()); - pPro->setPath(ui->le_nameSpace->text()); + if(!ui->le_nameSpace->text().isEmpty()) + pPro->setPath(ui->le_nameSpace->text()); pPro->setName(ui->le_name->text()); pPro->setLabel(QJsonObject()); pPro->setDescription(ui->le_description->text()); @@ -91,7 +92,7 @@ void BaseInfoDlg::setPropertyValue(QVariant var) { ui->le_uuid->setText(pPro->uuid().toString()); ui->le_tag->setText(pPro->tag()); - ui->le_nameSpace->setText(pPro->path()); + ui->le_nameSpace->setText(pPro->getBay()); ui->le_name->setText(pPro->name()); ui->le_label->setText(""); //label josn格式暂不解析 ui->le_description->setText(pPro->description()); diff --git a/diagramCavas/source/basePannelPropertyProxy.cpp b/diagramCavas/source/basePannelPropertyProxy.cpp index 8ebed5d..82639a4 100644 --- a/diagramCavas/source/basePannelPropertyProxy.cpp +++ b/diagramCavas/source/basePannelPropertyProxy.cpp @@ -36,23 +36,3 @@ void BasePannelPropertyProxy::setSize(QSize size) { _pPanel->resize(size); } - -/*QColor BasePannelPropertyProxy::getBackColor() const -{ - return _pPanel->getScene()->getBackGoundColor(); -} - -void BasePannelPropertyProxy::setBackColor(QColor color) -{ - _pPanel->getScene()->setBackGoundColor(color); -} - -QColor BasePannelPropertyProxy::getGridColor() const -{ - return _pPanel->getScene()->getGridColor(); -} - -void BasePannelPropertyProxy::setGridColor(QColor color) -{ - _pPanel->getScene()->setGridColor(color); -}*/ diff --git a/diagramCavas/source/dataSourceDlg.cpp b/diagramCavas/source/dataSourceDlg.cpp index 67e9a96..cabf671 100644 --- a/diagramCavas/source/dataSourceDlg.cpp +++ b/diagramCavas/source/dataSourceDlg.cpp @@ -3,7 +3,7 @@ #include #include #include "structDataSource.h" -#include "instance/extraPropertyManager.h" +#include "extraPropertyManager.h" #include "propertyType/dataSourceType.h" #include #include "global.h" diff --git a/diagramCavas/source/diagramCavas.cpp b/diagramCavas/source/diagramCavas.cpp index 3fbdc13..fa7e3e0 100644 --- a/diagramCavas/source/diagramCavas.cpp +++ b/diagramCavas/source/diagramCavas.cpp @@ -26,7 +26,7 @@ #include "itemPropertyDlg.h" #include "monitorConfigDlg.h" #include "structDataPreviewDlg.h" -#include "instance/extraPropertyManager.h" +#include "extraPropertyManager.h" #include "QQuickDetailsViewMananger.h" #include "propertyType/propertyTypeCustomization_DataSourceType.h" @@ -46,7 +46,7 @@ DiagramCavas::DiagramCavas(QWidget *parent) DiagramCavas::~DiagramCavas() { - + disconnect(); //断开连接避免动态库释放时信号问题 } DrawingPanel* DiagramCavas::getPanel(QString sPage) @@ -196,6 +196,7 @@ void DiagramCavas::onSignal_addDrawingPanel(PowerEntity* pItem,DiagramMode mode, pModel->setCavas(QPointer(this)); connect(pModel,&FixedPortsModel::activatePage,this,&DiagramCavas::onSignal_activatePage); connect(pModel,&FixedPortsModel::updateCurrentItems,this,&DiagramCavas::onSignal_updateCurItems); + connect(pModel,&FixedPortsModel::updateTopologyItems,this,&DiagramCavas::onSignal_updateTopology); connect(pModel,&FixedPortsModel::itemSelected,this,&DiagramCavas::onSignal_selectedItems); connect(pPanel,&DrawingPanel::panelDelete,this,&DiagramCavas::onSignal_panelDelete); } @@ -606,6 +607,12 @@ void DiagramCavas::onTargetSelected(QObject* obj) if(obj) emit selectTarget(obj); } +/****************************************************/ + +void DiagramCavas::onSignal_updateTopology(QList lst,bool refresh) +{ + emit prepareUpdateTopology(lst,refresh); +} /*******************************************************/ @@ -650,7 +657,11 @@ EditPanel* DiagramCavas::onSignal_addEditPanel(QString sName) _curPage = sName; pPanel->setWindowTitle(_curPage); pPanel->setCavas(this); + DiagramEditorModel* pModel = pPanel->getModel(); connect(pPanel,&EditPanel::panelDelete,this,&DiagramCavas::onSignal_panelDelete); + if(pModel){ + connect(pModel,&DiagramEditorModel::updateTopologyItems,this,&DiagramCavas::onSignal_updateTopology); + } QMdiSubWindow* pSub = this->addSubWindow(pPanel); m_mapEditPanel.insert(_curPage,qMakePair(pPanel,pSub)); @@ -721,17 +732,17 @@ void DiagramCavas::onSignl_openCurrentBay() } } /*********************monitor**************************/ -void DiagramCavas::onSignal_updateCurItems(QList lst,bool refresh) +void DiagramCavas::onSignal_updateCurItems(QList lst,bool refresh) { emit prepareUpdateItems(lst,refresh); } -void DiagramCavas::onSignal_selectedItems(QList lst) +void DiagramCavas::onSignal_selectedItems(QList lst) { emit prepareSelectItems(lst); } -void DiagramCavas::onSignal_generate(QString sPage,QList lst) +void DiagramCavas::onSignal_generate(QString sPage,QList lst) { QWidget* pWindow= currentSubWindow()->widget(); DrawingPanel* pPanel = dynamic_cast(pWindow); @@ -745,7 +756,7 @@ void DiagramCavas::onSignal_monitorCreated(QString sProj,QPair pa emit updateMonitorList(sProj,pair); } -void DiagramCavas::onSignal_monitorItemCreated(QList lst) +void DiagramCavas::onSignal_monitorItemCreated(QList lst) { emit createdMonitorItems(lst); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp index db4e4fc..78ea872 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorBayDetailAddDlg.cpp @@ -482,6 +482,9 @@ void DiagramEditorBayDetailAddDlg::onOkClicked() } } } + if(_pParent){ + _pParent->showPreview(); + } hide(); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp index a39c53c..a9f3555 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorBayDetailSettingDlg.cpp @@ -9,7 +9,7 @@ #include "graphicsDataModel/diagramEditorModel.h" #include "topologyManager.h" -DiagramEditorBayDetailSettingDlg::DiagramEditorBayDetailSettingDlg(QWidget *parent) +DiagramEditorBayDetailSettingDlg::DiagramEditorBayDetailSettingDlg(QWidget *parent,DiagramEditorModel* pModel) : QDialog(parent) , ui(new Ui::diagramEditorBayDetailSettingDlg) ,_pAddDlg(nullptr) @@ -17,7 +17,7 @@ DiagramEditorBayDetailSettingDlg::DiagramEditorBayDetailSettingDlg(QWidget *pare ,_compoModel(nullptr) ,_routeModel(nullptr) ,_pPreviewDlg(nullptr) - ,_pModel(nullptr) + ,_pModel(pModel) ,_pWizard(nullptr) { ui->setupUi(this); @@ -41,7 +41,6 @@ void DiagramEditorBayDetailSettingDlg::initial() connect(ui->btn_add,&QPushButton::clicked,this,&DiagramEditorBayDetailSettingDlg::onAddClicked); connect(ui->btn_ok,&QPushButton::clicked,this,&DiagramEditorBayDetailSettingDlg::onOkClicked); connect(ui->btn_cancel,&QPushButton::clicked,this,&DiagramEditorBayDetailSettingDlg::onCancelClicked); - connect(ui->btn_preview,&QPushButton::clicked,this,&DiagramEditorBayDetailSettingDlg::onPreviewClicked); connect(ui->tableView, &QTableView::customContextMenuRequested, this, &DiagramEditorBayDetailSettingDlg::onRouteRbtnClicked); ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); @@ -52,6 +51,19 @@ void DiagramEditorBayDetailSettingDlg::initial() ui->cb_layout->addItem("纵向",0); ui->cb_layout->addItem("横向",1); + + if(_pPreviewDlg == nullptr){ + _pPreviewDlg = new DiagramEditorBayPreviewDlg(this); + _pPreviewDlg->setParent(this); + if(_pModel){ + _pModel->setCurBayComponentModel(_compoModel); + _pModel->setCurBayRouteModel(_routeModel); + } + _pPreviewDlg->setSceneRect(ui->tableView->rect()); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(_pPreviewDlg); + ui->groupBox_preview->setLayout(layout); + } } void DiagramEditorBayDetailSettingDlg::refreshModel() @@ -270,6 +282,10 @@ void DiagramEditorBayDetailSettingDlg::onOkClicked() } hide(); _pModel->clearCurPreview(); //关闭时清除预览Item + _pModel->generatePreview(); + _pModel->calculateBlockPos(); + _pModel->setItemInBlockPos(); + _pModel->refreshConnection(); //todo:清除mainPanel中的对应item(如果存在) } @@ -361,22 +377,12 @@ void DiagramEditorBayDetailSettingDlg::onRouteEditClicked() _pAddDlg->showDlg(routeInfo); } -void DiagramEditorBayDetailSettingDlg::onPreviewClicked() +void DiagramEditorBayDetailSettingDlg::showPreview() { int nLayout = ui->cb_layout->currentData().toInt(); - if(_pPreviewDlg == nullptr){ - _pPreviewDlg = new DiagramEditorBayPreviewDlg(this); - _pPreviewDlg->setParent(this); - _pModel->setCurBayComponentModel(_compoModel); - _pModel->setCurBayRouteModel(_routeModel); + _pPreviewDlg->showDlg(nLayout); + QRectF recContainAll = _pModel->generateTempBay(_curOperateObj); + if(_curOperateObj){ + _curOperateObj->setRecSize(recContainAll); } - if(!_pPreviewDlg->isVisible()){ - _pPreviewDlg->showDlg(nLayout); - QRectF recContainAll = _pModel->generateTempBay(_curOperateObj); - if(_curOperateObj){ - _curOperateObj->setRecSize(recContainAll); - } - } - else - _pPreviewDlg->hide(); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorBayPreviewDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorBayPreviewDlg.cpp index 4953ab3..d9807f3 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorBayPreviewDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorBayPreviewDlg.cpp @@ -12,6 +12,7 @@ DiagramEditorBayPreviewDlg::DiagramEditorBayPreviewDlg(QWidget *parent) ,_pMainLayout(nullptr) ,_pParent(nullptr) { + this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); QRect recParent = parent->geometry(); setGeometry(recParent.right(),recParent.y(),recParent.width(),recParent.height()); initial(); @@ -26,9 +27,10 @@ void DiagramEditorBayPreviewDlg::initial() { _pMainLayout = new QVBoxLayout(this); _pView = new EditView(this); + _pView->scale(0.5,0.5); //缩放为一半 _pMainLayout->addWidget(_pView); _pScene = new EditPreviewScene(this); - _pScene->setSceneRect(-g_dGriaphicsScene_Width / 2, -g_dGriaphicsScene_Height / 2, g_dGriaphicsScene_Width, g_dGriaphicsScene_Height); + _pScene->setSceneRect(-g_dGriaphicsScene_Width / 2, -g_dGriaphicsScene_Height / 2, g_dGriaphicsScene_Width, g_dGriaphicsScene_Height); //初始大小 _pView->setScene(_pScene); } @@ -37,7 +39,7 @@ void DiagramEditorBayPreviewDlg::showDlg(int nLayout) if(_pParent){ _pParent->getModel()->setCurPreviewScene(_pScene); } - show(); + //show(); int nDir = 0; if(nLayout == 0){ //纵,下右 nDir = 41; @@ -49,3 +51,8 @@ void DiagramEditorBayPreviewDlg::showDlg(int nLayout) _pParent->getModel()->updateTarget(_pParent->getBayInfo().mapRoute,_pParent->getBayInfo().mapComponent,nDir,0); } +void DiagramEditorBayPreviewDlg::setSceneRect(const QRect rec) +{ + if(_pScene) + _pScene->setSceneRect(-rec.width()*0.5,-rec.height()*0.5,rec.width(),rec.height()); +} diff --git a/diagramCavas/source/diagramEditor/diagramEditorPreviewDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorPreviewDlg.cpp index 8f8c114..5a9b27c 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorPreviewDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorPreviewDlg.cpp @@ -4,6 +4,8 @@ #include "graphicsDataModel/diagramEditorModel.h" #include "diagramEditor/editPanel.h" #include "global.h" +#include +#include DiagramEditorPreviewDlg::DiagramEditorPreviewDlg(QWidget *parent) : QDialog(parent) @@ -12,6 +14,7 @@ DiagramEditorPreviewDlg::DiagramEditorPreviewDlg(QWidget *parent) ,_pMainLayout(nullptr) ,_pParent(nullptr) { + setWindowTitle("预览"); auto pParent = dynamic_cast(parent); if(pParent) setParent(pParent); @@ -29,6 +32,7 @@ void DiagramEditorPreviewDlg::initial() { _pMainLayout = new QVBoxLayout(this); _pView = new EditView(this); + _pView->scale(0.5, 0.5); _pMainLayout->addWidget(_pView); _pScene = new EditPreviewScene(this); _pScene->setSceneRect(_pParent->getScene()->sceneRect()); //使用父窗口scene大小 @@ -39,9 +43,24 @@ void DiagramEditorPreviewDlg::initial() void DiagramEditorPreviewDlg::showDlg() { if(_pParent){ + _pScene->clear(); _pParent->getModel()->setCurPreviewScene(_pScene); } - show(); + show(); + // 设置大小为屏幕的1/3 + QScreen *screen = QGuiApplication::primaryScreen(); + QRect rec = screen->availableGeometry(); + int w = rec.width() / 3; + int h = rec.height() / 3; + // 确保最小尺寸 + w = qMax(w, 400); + h = qMax(h, 300); + resize(w, h); + + QRect mainRect = screen->availableGeometry(); + int x = mainRect.right() - width(); + int y = mainRect.bottom() - height(); + move(x, y); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorTransDetailAddDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorTransDetailAddDlg.cpp index 261f0c9..d93967e 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorTransDetailAddDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorTransDetailAddDlg.cpp @@ -466,6 +466,9 @@ void DiagramEditorTransDetailAddDlg::onOkClicked() } } } + if(_pParent){ + _pParent->showPreview(); + } hide(); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorTransDetailSettingDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorTransDetailSettingDlg.cpp index 0eb2b4a..d3ddd62 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorTransDetailSettingDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorTransDetailSettingDlg.cpp @@ -10,14 +10,14 @@ #include "topologyManager.h" #include "diagramEditor/diagramEditorTransPreviewDlg.h" -DiagramEditorTransDetailSettingDlg::DiagramEditorTransDetailSettingDlg(QWidget *parent) +DiagramEditorTransDetailSettingDlg::DiagramEditorTransDetailSettingDlg(QWidget *parent,DiagramEditorModel* pModel) : QDialog(parent) , ui(new Ui::diagramEditorTransDetailSettingDlg) ,_pAddDlg(nullptr) ,_curOperateObj(nullptr) ,_compoModel(nullptr) ,_pPreviewDlg(nullptr) - ,_pModel(nullptr) + ,_pModel(pModel) ,_curOperateRouteView(nullptr) { ui->setupUi(this); @@ -53,11 +53,12 @@ void DiagramEditorTransDetailSettingDlg::initial() connect(ui->btn_add,&QPushButton::clicked,this,&DiagramEditorTransDetailSettingDlg::onAddClicked); connect(ui->btn_ok,&QPushButton::clicked,this,&DiagramEditorTransDetailSettingDlg::onOkClicked); connect(ui->btn_cancel,&QPushButton::clicked,this,&DiagramEditorTransDetailSettingDlg::onCancelClicked); - connect(ui->btn_previewEquips,&QPushButton::clicked,this,&DiagramEditorTransDetailSettingDlg::onPreviewNeutralClicked); - connect(ui->btn_previewTrans,&QPushButton::clicked,this,&DiagramEditorTransDetailSettingDlg::onPreviewTransClicked); connect(ui->tableView_hv, &QTableView::customContextMenuRequested, this, &DiagramEditorTransDetailSettingDlg::onRouteRbtnClicked); connect(ui->tableView_mv, &QTableView::customContextMenuRequested, this, &DiagramEditorTransDetailSettingDlg::onRouteRbtnClicked); connect(ui->tableView_lv, &QTableView::customContextMenuRequested, this, &DiagramEditorTransDetailSettingDlg::onRouteRbtnClicked); + connect(ui->cb_previewType,&QComboBox::currentIndexChanged,this,[&](int index){ + showPreview(); + }); ui->tableView_hv->setContextMenuPolicy(Qt::CustomContextMenu); ui->tableView_hv->setSelectionMode(QAbstractItemView::SingleSelection); @@ -76,6 +77,19 @@ void DiagramEditorTransDetailSettingDlg::initial() ui->tableView_lv->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView_lv->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->tableView_lv->verticalHeader()->setVisible(false); + + if(_pPreviewDlg == nullptr){ + _pPreviewDlg = new DiagramEditorTransPreviewDlg(this); + _pPreviewDlg->setParent(this); + if(_pModel){ + _pModel->setCurTransComponentModel(_compoModel); + _pModel->setCurTransRouteModels(_routeModels); + } + _pPreviewDlg->setSceneRect(ui->tableView_hv->rect()); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(_pPreviewDlg); + ui->groupBox_preview->setLayout(layout); + } } void DiagramEditorTransDetailSettingDlg::refreshModel() @@ -318,6 +332,10 @@ void DiagramEditorTransDetailSettingDlg::onOkClicked() } hide(); _pModel->clearCurPreview(); //关闭时清除预览Item + _pModel->generatePreview(); + _pModel->calculateBlockPos(); + _pModel->setItemInBlockPos(); + _pModel->refreshConnection(); //todo:清除mainPanel中的对应item(如果存在) } @@ -425,37 +443,22 @@ void DiagramEditorTransDetailSettingDlg::onRouteEditClicked() _pAddDlg->showDlg(routeInfo); } -void DiagramEditorTransDetailSettingDlg::onPreviewNeutralClicked() +void DiagramEditorTransDetailSettingDlg::showPreview() { - if(_pPreviewDlg == nullptr){ - _pPreviewDlg = new DiagramEditorTransPreviewDlg(this); - _pPreviewDlg->setParent(this); - _pModel->setCurTransComponentModel(_compoModel); - _pModel->setCurTransRouteModels(_routeModels); - } - if(!_pPreviewDlg->isVisible()){ + int n = ui->cb_previewType->currentIndex(); + if(n == 0){ //中性点预览 int n = ui->tabWidget->currentIndex(); _pPreviewDlg->showDlg(n); - _pModel->clearCurPreview(); - _pModel->generateTempTrans(n,_curOperateObj); + if(_pModel){ + _pModel->clearCurPreview(); + _pModel->generateTempTrans(n,_curOperateObj); + } } - else - _pPreviewDlg->hide(); -} - -void DiagramEditorTransDetailSettingDlg::onPreviewTransClicked() -{ - if(_pPreviewDlg == nullptr){ - _pPreviewDlg = new DiagramEditorTransPreviewDlg(this); - _pPreviewDlg->setParent(this); - _pModel->setCurTransComponentModel(_compoModel); - _pModel->setCurTransRouteModels(_routeModels); - } - if(!_pPreviewDlg->isVisible()){ + else{ //变压器预览 _pPreviewDlg->showDlg(3); - _pModel->clearCurPreview(); - _pModel->generateTempTrans(3,_curOperateObj); + if(_pModel){ + _pModel->clearCurPreview(); + _pModel->generateTempTrans(3,_curOperateObj); + } } - else - _pPreviewDlg->hide(); } diff --git a/diagramCavas/source/diagramEditor/diagramEditorTransPreviewDlg.cpp b/diagramCavas/source/diagramEditor/diagramEditorTransPreviewDlg.cpp index 23bc930..9cf6716 100644 --- a/diagramCavas/source/diagramEditor/diagramEditorTransPreviewDlg.cpp +++ b/diagramCavas/source/diagramEditor/diagramEditorTransPreviewDlg.cpp @@ -37,7 +37,7 @@ void DiagramEditorTransPreviewDlg::showDlg(int nType) if(_pParent){ _pParent->getModel()->setCurPreviewScene(_pScene); } - show(); + //show(); updateModelData(nType); } @@ -60,3 +60,9 @@ void DiagramEditorTransPreviewDlg::updateModelData(int nType) _pParent->getModel()->updateTarget(_pParent->getTransInfo().mapNeutral[2].mapRoute,_pParent->getTransInfo().mapComponent,14,1); //1右2下 } } + +void DiagramEditorTransPreviewDlg::setSceneRect(const QRect rec) +{ + if(_pScene) + _pScene->setSceneRect(-rec.width()*0.5,-rec.height()*0.5,rec.width(),rec.height()); +} diff --git a/diagramCavas/source/diagramEditor/editPanel.cpp b/diagramCavas/source/diagramEditor/editPanel.cpp index e13d9a2..266801b 100644 --- a/diagramCavas/source/diagramEditor/editPanel.cpp +++ b/diagramCavas/source/diagramEditor/editPanel.cpp @@ -61,6 +61,8 @@ EditPanel::~EditPanel() void EditPanel::initByWizardInfo() { + QList lstBay; + QList lstItem; //if(!_lstData.empty() || !_pModel->getPreviewItem().empty()){ _pModel->clearItems(); m_pEditScene->clear(); @@ -112,6 +114,31 @@ void EditPanel::initByWizardInfo() pItem = pBus; layH->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); layH->setPreferredHeight(10); // 固定高度 + + RelationItem info; + info.item.nEquipType = 1; + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = pBlock->getName(); + info.item.uid = pBlock->getId(); //间隔id与对象id此处相同(表示此间隔对应一个设备) + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; + + bayTag = pBlock->getName(); + bayUuid = pBlock->getId().toString(); + sVoltageLevel = QString::number(pBlock->getVoltage()); + + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); } else if(nType == 2){ //间隔 auto pBay = new EditBayItem(); @@ -126,6 +153,14 @@ void EditPanel::initByWizardInfo() }*/ if(pItem){ + RelationItem bayInfo; //间隔层级 + bayInfo.item.nEquipType = 0; // 间隔的设备类型为0 + bayInfo.item.nCategory = 1; // 类别为1表示间隔 + bayInfo.item.sName = pBlock->getName(); + bayInfo.item.uid = pBlock->getId(); + bayInfo.item.sVoltageLevel = QString::number(pBlock->getVoltage()); + lstBay.append(bayInfo); + connect(pItem,&EditBaseItem::itemDbClicked,this,&EditPanel::onItemDbClicked); pItem->setName(pBlock->getName()); pItem->setBlockData(pBlock); @@ -209,9 +244,42 @@ void EditPanel::initByWizardInfo() pTrans->setType(EditorItemType::trans); pTrans->setBoundingRect(QRectF(0,0,g_dEditorItem_Width,g_dEditorItem_Width)); pItem = pTrans; + + RelationItem info; + info.item.nEquipType = 16; + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = pBlock->getName(); + info.item.uid = pBlock->getId(); //间隔id与对象id此处相同(表示此间隔对应一个设备) + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; + + bayTag = pBlock->getName(); + bayUuid = pBlock->getId().toString(); + sVoltageLevel = QString::number(pBlock->getVoltage()); + + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); } if(pItem){ + RelationItem bayInfo; //间隔层级 + bayInfo.item.nEquipType = 0; // 间隔的设备类型为0 + bayInfo.item.nCategory = 1; // 类别为1表示间隔 + bayInfo.item.sName = pBlock->getName(); + bayInfo.item.uid = pBlock->getId(); + bayInfo.item.sVoltageLevel = QString::number(pBlock->getVoltage()); + lstBay.append(bayInfo); + connect(pItem,&EditBaseItem::itemDbClicked,this,&EditPanel::onItemDbClicked); pItem->setName(pBlock->getName()); pItem->setBlockData(pBlock); @@ -231,6 +299,8 @@ void EditPanel::initByWizardInfo() } } _widgetLayout->addStretch(); + emit _pModel->updateTopologyItems(lstBay,true); + emit _pModel->updateTopologyItems(lstItem,false); QTimer::singleShot(300, [&]() { // 1000 毫秒 = 1 秒 qDebug() << "一次性定时器触发!"; initBlockConnection(); @@ -469,23 +539,23 @@ void EditPanel::onItemDbClicked(QPointer pBlock) { if(pBlock->getType() == 2){ //间隔 if(_bayDetailSetting == nullptr){ - _bayDetailSetting = new DiagramEditorBayDetailSettingDlg(this); - _bayDetailSetting->setModelDelegate(_pModel); + _bayDetailSetting = new DiagramEditorBayDetailSettingDlg(this,_pModel); _bayDetailSetting->setWizard(_pEditorWizard); } auto pBay = dynamic_cast(pBlock.data()); if(pBay) _bayDetailSetting->showDlg(pBay); + _bayDetailSetting->showPreview(); } else if(pBlock->getType() == 3){ //变压器 if(_transDetailSetting == nullptr){ - _transDetailSetting = new DiagramEditorTransDetailSettingDlg(this); - _transDetailSetting->setModelDelegate(_pModel); + _transDetailSetting = new DiagramEditorTransDetailSettingDlg(this,_pModel); _transDetailSetting->setWizard(_pEditorWizard); } auto pTrans = dynamic_cast(pBlock.data()); if(pTrans) _transDetailSetting->showDlg(pTrans); + _transDetailSetting->showPreview(); } } diff --git a/diagramCavas/source/drawingPanel.cpp b/diagramCavas/source/drawingPanel.cpp index 7775096..345f199 100644 --- a/diagramCavas/source/drawingPanel.cpp +++ b/diagramCavas/source/drawingPanel.cpp @@ -222,19 +222,19 @@ void DrawingPanel::loadNodes(QJsonObject obj) } if(_pModel){ - QList lstFirst; + QList lstFirst; for(auto& pBaseItem:_pModel->getProjectItems()) //首次循环添加母线及独立设备(变压器等),更新列表显示使用 { BaseProperty* pBase = dynamic_cast(pBaseItem->getProperty()); if(pBase->type() == 1){ //母线添加子间隔 - monitorRelationItem info; + RelationItem info; info.item.nEquipType = pBase->type(); info.item.nCategory = 0; info.item.sName = pBase->name(); info.item.uid = pBase->uuid(); for(auto& subPair:pBase->getSubList()){ - monitorRelationSturctItem subStruct; + RelationSturctItem subStruct; BayProperty* pTargetBay = nullptr; for(auto& pOtherItem:_pModel->getProjectBayItems()) @@ -259,14 +259,14 @@ void DrawingPanel::loadNodes(QJsonObject obj) lstFirst.append(info); } else if(pBase->type() == 15 || pBase->type() == 16){ - monitorRelationItem info; + RelationItem info; info.item.nEquipType = pBase->type(); info.item.nCategory = 0; info.item.sName = pBase->name(); info.item.uid = pBase->uuid(); for(auto& subPair:pBase->getSubList()){ - monitorRelationSturctItem subStruct; + RelationSturctItem subStruct; ModelProperty* pPro = nullptr; for(auto& item:_pModel->getProjectItems()){ @@ -290,12 +290,12 @@ void DrawingPanel::loadNodes(QJsonObject obj) } emit _pModel->updateCurrentItems(lstFirst,true); - QList lstSecond; + QList lstSecond; for(auto& pBaseItem:_pModel->getProjectItems()) //二次循环添加间隔内设备(更新列表显示使用) { BaseProperty* pBase = dynamic_cast(pBaseItem->getProperty()); if(pBase->type() != 1 && pBase->type() != 15 && pBase->type() != 16){ //设备添加 - monitorRelationItem info; + RelationItem info; info.item.nEquipType = pBase->type(); info.item.nCategory = 0; info.item.sName = pBase->name(); @@ -306,7 +306,9 @@ void DrawingPanel::loadNodes(QJsonObject obj) { BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); if(pBay){ - if(pBay->tag() == pBase->getBay()){ //将bay添加到parent + QString bayTag = pBay->tag(); + QString parentTag = pBase->getBay(); + if(bayTag == parentTag){ //将bay添加到parent info.parent.nEquipType = 0; info.parent.nCategory = 1; info.parent.sName = pBay->tag(); diff --git a/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp b/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp index 34c39ed..6dbeffa 100644 --- a/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp +++ b/diagramCavas/source/graphicsDataModel/diagramEditorModel.cpp @@ -39,6 +39,13 @@ DiagramEditorModel::~DiagramEditorModel() } +void DiagramEditorModel::clearItems() +{ + _previewItem.clear(); + if(_pCurPreviewScene) + _pCurPreviewScene->clear(); +} + bool DiagramEditorModel::addPreviewItem(QUuid uuid,GraphicsBaseModelItem* pItem,int mode) { if(mode == 0){ @@ -478,104 +485,193 @@ void DiagramEditorModel::linkTransItem(GraphicsBaseModelItem* pTrans,QStandardIt } } -void DiagramEditorModel::generatePreview() +void DiagramEditorModel::generatePreview(bool bVisible) { if(_pPanel){ + QList lstBay; + QList lstItem; + clearItems(); - _pPanel->showPreview(); + if(bVisible) + _pPanel->showPreview(); QList lst = _pPanel->getBlockItems(); QMap> baysCompo; QMap>> transCompo; for(auto item:lst){ - if(item->getType() == EditorItemType::bus){ //首次循环生成母线 - auto p = item->getBlockData(); //获取blockitem对应的data - DiagramEditorBusBlock* pBus = dynamic_cast(p.data()); - if(pBus){ - QUuid uid = p->getId(); - QString name = p->getName(); - auto pContainer = _pWizard->getContainerByBlock_all(name); //获取block所在的container + auto p = item->getBlockData(); //获取blockitem对应的data + if(p){ + RelationItem bayInfo; //间隔层级 + bayInfo.item.nEquipType = 0; // 间隔的设备类型为0 + bayInfo.item.nCategory = 1; // 类别为1表示间隔 + bayInfo.item.sName = p->getName(); + bayInfo.item.uid = p->getId(); + bayInfo.item.sVoltageLevel = QString::number(p->getVoltage()); + lstBay.append(bayInfo); + if(item->getType() == EditorItemType::bus){ //首次循环生成母线 + DiagramEditorBusBlock* pBus = dynamic_cast(p.data()); + if(pBus){ + QUuid uid = p->getId(); + QString name = p->getName(); + auto pContainer = _pWizard->getContainerByBlock_all(name); //获取block所在的container - auto mapBlocks = pContainer->getBlockMap(); - int nMaxLen = 0; - for(auto &lst:mapBlocks){ //根据容器中block的最大长度,计算出母线最小length - int nLen = 0; - for(auto block:lst){ - if(block->getType() == 1) //容器中block是母线不计算 - continue; - nLen = 100+block->getRecSize().width(); + auto mapBlocks = pContainer->getBlockMap(); + int nMaxLen = 0; + for(auto &lst:mapBlocks){ //根据容器中block的最大长度,计算出母线最小length + int nLen = 0; + for(auto block:lst){ + if(block->getType() == 1) //容器中block是母线不计算 + continue; + nLen = 100+block->getRecSize().width(); + } + if(nMaxLen < nLen) + nMaxLen = nLen; } - if(nMaxLen < nLen) - nMaxLen = nLen; + + QRectF rec = item->boundingRect(); + + QPointF pos = item->scenePos(); + if(_previewItem.contains(uid)) + continue; + auto pItem = generateComponent(uid,name,0,1,pos,0,1,pBus); + pBus->addSubList(qMakePair(0,uid)); + if(nMaxLen > rec.width()) + rec.setWidth(nMaxLen); + pItem->setBoundingRect(rec); + pBus->setRecSize(rec); + + RelationItem info; + info.item.nEquipType = 1; + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = p->getName(); + info.item.uid = p->getId(); //间隔id与对象id此处相同(表示此间隔对应一个设备) + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; + + bayTag = p->getName(); + bayUuid = p->getId().toString(); + sVoltageLevel = QString::number(p->getVoltage()); + + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); } - - QRectF rec = item->boundingRect(); - - QPointF pos = item->scenePos(); - if(_previewItem.contains(uid)) - continue; - auto pItem = generateComponent(uid,name,0,1,pos,0,1,pBus); - if(nMaxLen > rec.width()) - rec.setWidth(nMaxLen); - pItem->setBoundingRect(rec); - pBus->setRecSize(rec); } - } - else if(item->getType() == EditorItemType::bay){ //第二次生成间隔、变压器 - auto p = item->getBlockData(); //获取blockitem对应的data - DiagramEditorBayBlock* pBay = dynamic_cast(p.data()); - if(pBay){ - QString sBay = pBay->getName(); - auto mapRoute = pBay->getBayInfo().mapRoute; - auto mapCompo = pBay->getBayInfo().mapComponent; + else if(item->getType() == EditorItemType::bay){ //第二次生成间隔、变压器 + DiagramEditorBayBlock* pBay = dynamic_cast(p.data()); + if(pBay){ + QString sBay = pBay->getName(); + auto mapRoute = pBay->getBayInfo().mapRoute; + auto mapCompo = pBay->getBayInfo().mapComponent; - QRectF rect = item->boundingRect(); - // 计算中心点(本地坐标系) - QPointF centerLocal = rect.center(); - // 转换为场景坐标系 - QPointF centerScene = item->mapToScene(centerLocal); - QList lstCompo = generateItemByInfo(mapRoute,mapCompo,centerScene,pBay); //返回与外部连接的compo - if(!baysCompo.contains(sBay)) - baysCompo.insert(sBay,lstCompo); - } - } - else if(item->getType() == EditorItemType::trans){ - auto p = item->getBlockData(); //获取blockitem对应的data - DiagramEditorTransformerBlock* pTrans = dynamic_cast(p.data()); - if(pTrans){ - //首先绘制本体 - auto pType = pTrans->getTransType(); - QString sTrans = pTrans->getName(); - QUuid uid = pTrans->getId(); - QString name = pTrans->getName(); + QRectF rect = item->boundingRect(); + // 计算中心点(本地坐标系) + QPointF centerLocal = rect.center(); + // 转换为场景坐标系 + QPointF centerScene = item->mapToScene(centerLocal); + QList lstCompo = generateItemByInfo(mapRoute,mapCompo,centerScene,pBay); //返回与外部连接的compo + if(!baysCompo.contains(sBay)) + baysCompo.insert(sBay,lstCompo); + for(auto& compo:lstCompo){ + RelationItem info; + info.item.nEquipType = compo.nType; + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = compo.sName; + info.item.uid = compo.uid; //间隔id与对象id此处相同(表示此间隔对应一个设备) - QPointF pos = item->scenePos(); - int nType = 0; - if(pType == TransformerType::twoWinding) - nType = 15; - else - nType = 16; - auto pItem = generateComponent(uid,name,0,nType,pos,0,1,pTrans); - auto pro = pItem->getProperty(); + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; - QRectF rect = item->boundingRect(); - // 计算中心点(本地坐标系) - QPointF centerLocal = rect.center(); - // 转换为场景坐标系 - QPointF centerScene = item->mapToScene(centerLocal); - auto transInfo = pTrans->getTranInfo(); + bayTag = p->getName(); + bayUuid = p->getId().toString(); + sVoltageLevel = QString::number(p->getVoltage()); - QMap> neutralInfo; - for(auto &neutral:transInfo.mapNeutral){ - QPointF pDelta = neutral.delPoint; - int nT = neutral.nType; - QList lstCompo = generateItemByInfo(neutral.mapRoute,transInfo.mapComponent,centerScene+pDelta,pTrans); - if(!neutralInfo.contains(nT)) - neutralInfo.insert(nT,lstCompo); + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); + } } + } + else if(item->getType() == EditorItemType::trans){ + DiagramEditorTransformerBlock* pTrans = dynamic_cast(p.data()); + if(pTrans){ + //首先绘制本体 + auto pType = pTrans->getTransType(); + QString sTrans = pTrans->getName(); + QUuid uid = pTrans->getId(); + QString name = pTrans->getName(); - if(!transCompo.contains(sTrans)) //添加需连接的中性点 - transCompo.insert(sTrans,neutralInfo); + QPointF pos = item->scenePos(); + int nType = 0; + if(pType == TransformerType::twoWinding) + nType = 15; + else + nType = 16; + auto pItem = generateComponent(uid,name,0,nType,pos,0,1,pTrans); + auto pro = pItem->getProperty(); + + QRectF rect = item->boundingRect(); + // 计算中心点(本地坐标系) + QPointF centerLocal = rect.center(); + // 转换为场景坐标系 + QPointF centerScene = item->mapToScene(centerLocal); + auto transInfo = pTrans->getTranInfo(); + + QMap> neutralInfo; + for(auto &neutral:transInfo.mapNeutral){ + QPointF pDelta = neutral.delPoint; + int nT = neutral.nType; + QList lstCompo = generateItemByInfo(neutral.mapRoute,transInfo.mapComponent,centerScene+pDelta,pTrans); + if(!neutralInfo.contains(nT)) + neutralInfo.insert(nT,lstCompo); + for(auto& compo:lstCompo){ + RelationItem info; + info.item.nEquipType = compo.nType; + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = p->getName(); + info.item.uid = p->getId(); //间隔id与对象id此处相同(表示此间隔对应一个设备) + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; + + bayTag = p->getName(); + bayUuid = p->getId().toString(); + sVoltageLevel = QString::number(p->getVoltage()); + + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); + } + } + + if(!transCompo.contains(sTrans)) //添加需连接的中性点 + transCompo.insert(sTrans,neutralInfo); + } } } } @@ -678,6 +774,8 @@ void DiagramEditorModel::generatePreview() } } } + emit updateTopologyItems(lstBay,true); + emit updateTopologyItems(lstItem,false); } } diff --git a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp index 5fb12b1..812556b 100644 --- a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp +++ b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp @@ -1007,6 +1007,7 @@ void FixedPortsModel::saveNode(int nPageId) for(auto& info:lstTemp){ if(info.component_uuid != QUuid("11111111-1111-1111-1111-111111111111")) //只判断设备外量测 continue; + info.bay_tag = removeSuffix(info.bay_tag); lstExtra.append(info); } @@ -1107,7 +1108,7 @@ void FixedPortsModel::saveNode(int nPageId) extraPro.currentLevel = QString::number(pBay->getVoltage())+"kv"; extraPro.page_tag = _widget->pageName(); //暂时相同 extraPro.bay_name = pBay->name(); - extraPro.bay_tag = pBay->tag(); + extraPro.bay_tag = tempTag; extraPro.component_uuid = QUuid("11111111-1111-1111-1111-111111111111"); for(auto& groupInfo:groupMap){ @@ -1325,6 +1326,7 @@ void FixedPortsModel::saveNode(int nPageId) for(auto& info:lstTemp){ if(info.group_tag != "bay") //只对量测判断 continue; + info.bay_tag = removeSuffix(info.bay_tag); lstExtra.append(info); } @@ -2118,102 +2120,85 @@ void FixedPortsModel::generateProjectModel(const QString& sPageName,QList lstFirst; - for(auto& pBaseItem:lstItem) //首次循环添加母线及独立设备(变压器等),更新列表显示使用 - { - BaseModelProperty* pBase = dynamic_cast(pBaseItem->getProperty()); - if(pBase->type() == 1){ //母线添加子间隔 - monitorRelationItem info; - info.item.nEquipType = pBase->type(); - info.item.nCategory = 0; - info.item.sName = pBase->name(); - info.item.uid = pBase->uuid(); - - for(auto& subPair:pBase->getSubList()){ - monitorRelationSturctItem subStruct; - - BayProperty* pTargetBay = nullptr; - for(auto& pOtherItem:lstOther) - { - BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); - if(pBay){ - if(pBay->uuid() == subPair.second){ //从所有间隔中找到sublist中的间隔 - pTargetBay = pBay; - break; - } - } - } - - if(pTargetBay){ - subStruct.nEquipType = 0; - subStruct.nCategory = 1; - subStruct.sName = pTargetBay->tag(); - subStruct.uid = pTargetBay->uuid(); - info.subList.append(subStruct); - } - } - lstFirst.append(info); - } - else if(pBase->type() == 15 || pBase->type() == 16){ - monitorRelationItem info; - info.item.nEquipType = pBase->type(); - info.item.nCategory = 0; - info.item.sName = pBase->name(); - info.item.uid = pBase->uuid(); - - for(auto& subPair:pBase->getSubList()){ - monitorRelationSturctItem subStruct; - auto pPro = getItemByUid(lstBase,subPair.second); - if(pPro){ - subStruct.nEquipType = pPro->type(); - subStruct.nCategory = 0; - subStruct.sName = pPro->name(); - subStruct.uid = pPro->uuid(); - info.subList.append(subStruct); - } - } - - lstFirst.append(info); - } - } - emit updateCurrentItems(lstFirst,true); - - QList lstSecond; - for(auto& pBaseItem:lstItem) //二次循环添加间隔内设备(更新列表显示使用) - { - BaseModelProperty* pBase = dynamic_cast(pBaseItem->getProperty()); - if(pBase->type() != 1 && pBase->type() != 15 && pBase->type() != 16){ //设备添加 - monitorRelationItem info; - info.item.nEquipType = pBase->type(); - info.item.nCategory = 0; - info.item.sName = pBase->name(); - info.item.uid = pBase->uuid(); - - BayProperty* pTargetBay = nullptr; - for(auto& pOtherItem:lstOther) - { - BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); - if(pBay){ - if(pBay->tag() == pBase->getBay()){ //将bay添加到parent - info.parent.nEquipType = 0; - info.parent.nCategory = 1; - info.parent.sName = pBay->tag(); - info.parent.uid = pBay->uuid(); - break; - } - } - } - - lstSecond.append(info); - } - } - emit updateCurrentItems(lstSecond,false); + QList lstFirst; for(auto& pOtherItem:lstOther) { BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); if(pBay){ - BayProperty* pData = pProPanel->getModelController()->generateBayData(pBay,lstProData); + // 创建间隔项 + RelationItem bayInfo; + bayInfo.item.nEquipType = 0; // 间隔的设备类型为0 + bayInfo.item.nCategory = 1; // 类别为1表示间隔 + bayInfo.item.sName = pBay->tag(); + bayInfo.item.uid = pBay->uuid(); + + lstFirst.append(bayInfo); + } + } + + emit updateCurrentItems(lstFirst, true); + + // 第二阶段:处理所有设备 + QList lstSecond; + + // 建立间隔UUID到间隔标签的映射,提高查找效率 + QHash bayUuidToTag; + for(auto& pOtherItem:lstOther) + { + BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); + if(pBay){ + bayUuidToTag[pBay->uuid().toString()] = pBay->tag(); + } + } + + for(auto& pBaseItem:lstItem) + { + BaseModelProperty* pBase = dynamic_cast(pBaseItem->getProperty()); + + RelationItem info; + info.item.nEquipType = pBase->type(); + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = pBase->name(); + info.item.uid = pBase->uuid(); + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + + // 通过间隔标签直接查找 + bayTag = pBase->getBay(); + + // 如果需要间隔UUID,可以反向查找 + if(!bayTag.isEmpty()){ + for(auto& pOtherItem:lstOther){ + BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); + if(pBay && pBay->tag() == bayTag){ + bayUuid = pBay->uuid().toString(); + break; + } + } + } + + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + } + + lstSecond.append(info); + } + + emit updateCurrentItems(lstSecond, false); + + // 第三阶段:生成间隔数据(保持不变) + for(auto& pOtherItem:lstOther) + { + BayProperty* pBay = dynamic_cast(pOtherItem->getProperty()); + if(pBay){ + BayProperty* pData = pProPanel->getModelController()->generateBayData(pBay, lstProData); if(pData) { pData->setSubList(pBay->getSubList()); @@ -2235,10 +2220,45 @@ void FixedPortsModel::onWizardFinished(QMap mapIte } //pPanel->getModelController()->addTestData(); + QList lstItem; for(auto pItem:mapItem){ auto cloneItem = pItem->clone(); BaseModelProperty* pPro = BasePropertyManager::instance().findBaseEntityData(cloneItem->itemId()); if(pPro){ + RelationItem info; + info.item.nEquipType = pPro->type(); + info.item.nCategory = 0; // 类别为0表示设备 + info.item.sName = pPro->name(); + info.item.uid = pPro->uuid(); + + // 查找设备所属的间隔 + QString bayTag; + QString bayUuid; + QString sVoltageLevel; + + // 通过间隔标签直接查找 + bayTag = pPro->getBay(); + // 如果需要间隔UUID,可以反向查找 + if(!bayTag.isEmpty()){ + for(auto& pItem:mapBlock){ + auto pBlock = pItem->getBlockData(); + if(pBlock && pBlock->getName() == bayTag){ + bayUuid = pBlock->getId().toString(); + sVoltageLevel = QString::number(pBlock->getVoltage()); + break; + } + } + } + if(!bayTag.isEmpty()){ + // 设置父间隔信息 + info.parent.nEquipType = 0; + info.parent.nCategory = 1; + info.parent.sName = bayTag; + info.parent.uid = QUuid(bayUuid); + info.parent.sVoltageLevel = sVoltageLevel; + } + lstItem.append(info); + if(pPro->type() == 1){ //母线 for(auto item:mapBlock){ auto p = item->getBlockData(); //获取blockitem对应的data @@ -2249,7 +2269,7 @@ void FixedPortsModel::onWizardFinished(QMap mapIte if(sBus == pPro->name()){ double dVol = pBus->getVoltage(); pPro->setVoltageLevel(dVol); //设置本体电压层级 - pPro->setSubList(pBus->getSubList()); //将子列表转移到item + //pPro->setSubList(pBus->getSubList()); //将子列表转移到item } } } @@ -2265,7 +2285,7 @@ void FixedPortsModel::onWizardFinished(QMap mapIte if(sTrans == pPro->name()){ double dVol = pTrans->getVoltage(); pPro->setVoltageLevel(dVol); //设置本体电压 - pPro->setSubList(pTrans->getSubList()); //将子列表转移到item + //pPro->setSubList(pTrans->getSubList()); //将子列表转移到item } } } @@ -2325,8 +2345,19 @@ void FixedPortsModel::onWizardFinished(QMap mapIte //_widget->getView()->centerOn(center); //**************间隔************* + QList lstBay; for(auto item:mapBlock){ auto p = item->getBlockData(); //获取blockitem对应的data + + //间隔信息 + RelationItem bayInfo; + bayInfo.item.nEquipType = 0; // 间隔的设备类型为0 + bayInfo.item.nCategory = 1; // 类别为1表示间隔 + bayInfo.item.sName = p->getName(); + bayInfo.item.uid = p->getId(); + bayInfo.item.sVoltageLevel = QString::number(p->getVoltage()); + + lstBay.append(bayInfo); if(p->getType() == 1){ //母线 DiagramEditorBusBlock* pBus = dynamic_cast(p.data()); if(pBus){ @@ -2352,7 +2383,8 @@ void FixedPortsModel::onWizardFinished(QMap mapIte pBayData->setName(sBus); pBayData->setTag(sBus); pBayData->setType("母线间隔"); - //pBayData->setSubList(pBus->getSubList()); + pBayData->setVoltage(pBus->getVoltage()); + pBayData->setSubList(pBus->getSubList()); pBayData->getLstComponent().append(busId); addBayItem(bayId,pNew,ModelFunctionType::BaseModel); @@ -2427,6 +2459,7 @@ void FixedPortsModel::onWizardFinished(QMap mapIte pBayData->setName(sBay); pBayData->setTag(sBay); pBayData->setType(sType); + pBayData->setVoltage(pBay->getVoltage()); pBayData->setLstFrom(pBay->getBayInfo().lstFrom); pBayData->setLstTo(pBay->getBayInfo().lstTo); pBayData->setSubList(pBay->getSubList()); @@ -2497,6 +2530,7 @@ void FixedPortsModel::onWizardFinished(QMap mapIte pBayData->setName(sTrans); pBayData->setTag(sTrans); pBayData->setType(sType); + pBayData->setVoltage(pTrans->getVoltage()); pBayData->setSubList(pTrans->getSubList()); for(auto &info:lstInfo){ @@ -2508,20 +2542,23 @@ void FixedPortsModel::onWizardFinished(QMap mapIte } } } + emit updateTopologyItems(lstBay,true); + emit updateTopologyItems(lstItem,false); } void FixedPortsModel::addProjectItemByBaseData(DrawingPanel* pPanel,GraphicsBaseModelItem* pItem,BaseProperty* pPro,QString sGrid,QString sZone,QString sStation) { BaseModelProperty* pBase = dynamic_cast(pItem->getProperty()); if(pBase){ + QString sBay = pBase->getBay(); if(_baseItem.contains(pBase->uuid())){ GraphicsProjectModelItem* pProItem = nullptr; GraphicsBaseModelItem* pBaseItem = _baseItem.value(pBase->uuid()); pPro->setSourceItemId(pBaseItem->itemId().toString()); //设置被哪个对象生成 pPro->setMetaModelName(pBase->metaModelName()); //传递基模名 - pPro->setPath(pBase->getBay()); + pPro->setPath(sBay); pPro->setSubList(pBase->getSubList()); //传递sublist - pPro->setBay(pBase->getBay()); + pPro->setBay(sBay); pPro->setVoltageLevel(pBase->getVoltageLevel()); QString sMeta = pBase->metaModelName(); @@ -3306,7 +3343,7 @@ QList FixedPortsModel::turnJsonArrToList(QJsonObject object,QString sInne return lst; } -void FixedPortsModel::generateMonitor(QString sPage,QList lst) +void FixedPortsModel::generateMonitor(QString sPage,QList lst) { MonitorPanel* pPanel = nullptr; if(_cavas){ @@ -3323,7 +3360,7 @@ void FixedPortsModel::generateMonitor(QString sPage,QList l _widget->getGeneratePanelLst().append(sPage); //记录生成的运行页 pPanel->setParentPage(_pageName); //生成页记录被哪个组态生成 - QList lstFirst; + QList lstFirst; for(auto& itemInfo:lst) { if(itemInfo.item.nCategory == 0){ //设备 @@ -3358,7 +3395,7 @@ void FixedPortsModel::generateMonitor(QString sPage,QList l } } - QList lstSecond; + QList lstSecond; for(auto& itemInfo:lst) //第二次循环处理间隔 { if(itemInfo.item.nCategory == 1){ //间隔 diff --git a/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp b/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp index 7439144..6374d81 100644 --- a/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp +++ b/diagramCavas/source/graphicsItem/electricConnectLineItem.cpp @@ -41,54 +41,215 @@ void ElectricConnectLineItem::initial() void ElectricConnectLineItem::setStartPoint(const QPointF& p) { - int n = m_lstPoints.size(); - if(n) - { - if(n >2) - { - if(m_lstPoints[0].x() == m_lstPoints[1].x()) //相邻点在垂直方向,水平移动,否则垂直移动 - { - m_lstPoints[1].setX(p.x()); - } - else - { - m_lstPoints[1].setY(p.y()); - } - } + if (m_lstPoints.size() >= 2) { + // 保存终点 + QPointF endPoint = m_lstPoints.last(); + + // 清空并设置新起点 + m_lstPoints.clear(); + m_lstPoints.append(p); + m_lstPoints.append(endPoint); + + // 重新计算路径 + calculatePath(); + } else if (m_lstPoints.size() == 1) { m_lstPoints[0] = p; + } else { + m_lstPoints.append(p); } + update(); } void ElectricConnectLineItem::setEndPoint(const QPointF& p) { - int n = m_lstPoints.size(); - if(n) - { - if(n >2) - { - if(m_lstPoints[n-1].x() == m_lstPoints[n-2].x()) //相邻点在垂直方向,水平移动,否则垂直移动 - { - m_lstPoints[n-2].setX(p.x()); - } - else - { - m_lstPoints[n-2].setY(p.y()); - } - } - m_lstPoints[n-1] = p; + if (m_lstPoints.size() >= 2) { + // 保存起点 + QPointF startPoint = m_lstPoints.first(); + + // 清空并设置新终点 + m_lstPoints.clear(); + m_lstPoints.append(startPoint); + m_lstPoints.append(p); + + // 重新计算路径 + calculatePath(); + } else if (m_lstPoints.size() == 1) { + m_lstPoints.append(p); + } else { + m_lstPoints.append(p); } + update(); +} + +// 开始拖拽 +void ElectricConnectLineItem::startDrag(const QPointF& scenePos) +{ + qDebug() << "\n=== START DRAG ==="; + + // 重置状态 + m_dragData.isActive = false; + m_dragData.segmentIndex = -1; + + QPointF itemPos = mapFromScene(scenePos); + qDebug() << "Item pos:" << itemPos; + + // 从路径提取点 + QList points = extractPointsFromPath(); + qDebug() << "Extracted" << points.size() << "points from path"; + + // 查找线段 + int segmentIndex = findSegmentAt(points, itemPos); + + if (segmentIndex >= 0) { + m_dragData.isActive = true; + m_dragData.segmentIndex = segmentIndex; + m_dragData.startScenePos = scenePos; + m_dragData.originalPath = m_points; // 保存原始路径 + + // 判断线段方向 + if (segmentIndex < points.size() - 1) { + QPointF p1 = points[segmentIndex]; + QPointF p2 = points[segmentIndex + 1]; + m_dragData.isVertical = qFuzzyCompare(p1.x(), p2.x()); + } + + qDebug() << "✓ Dragging segment" << segmentIndex; + } +} + +// 更新拖拽 +void ElectricConnectLineItem::updateDrag(const QPointF& scenePos) +{ + if (!m_dragData.isActive) { + return; + } + + int idx = m_dragData.segmentIndex; + + // 从原始路径提取点 + QList points = extractPointsFromPath(m_dragData.originalPath); + + // 安全检查 + if (idx < 0 || idx >= points.size() - 1) { + qWarning() << "Invalid segment index:" << idx; + m_dragData.isActive = false; + return; + } + + // 计算移动距离 + QPointF startItemPos = mapFromScene(m_dragData.startScenePos); + QPointF currentItemPos = mapFromScene(scenePos); + QPointF delta = currentItemPos - startItemPos; + + // 获取当前线段 + QPointF& p1 = points[idx]; + QPointF& p2 = points[idx + 1]; + + // 限制移动方向 + if (m_dragData.isVertical) { + // 垂直线段:只能水平移动 + delta.setY(0); + + // 移动线段 + p1.rx() += delta.x(); + p2.rx() += delta.x(); + } else { + // 水平线段:只能垂直移动 + delta.setX(0); + + p1.ry() += delta.y(); + p2.ry() += delta.y(); + } + + // 修复连接 + fixConnections(points, idx, m_dragData.isVertical); + + // 更新拖拽起点 + m_dragData.startScenePos = scenePos; + + // 应用修改后的点 + applyPointsToPath(points); + + // 重新计算路径(调用原有的 calculatePath) + calculatePath(); + update(); +} +// 结束拖拽 +void ElectricConnectLineItem::endDrag() +{ + qDebug() << "\n" << QString(50, '='); + qDebug() << "END DRAG"; + qDebug() << QString(50, '='); + + if (!m_dragData.isActive) { + qDebug() << "No active drag to end"; + return; + } + + qDebug() << "Drag was active on segment:" << m_dragData.segmentIndex; + + // 验证和修复路径 + validateAndFixPath(); + + // 重置状态 + m_dragData.isActive = false; + m_dragData.segmentIndex = -1; + m_dragData.isVertical = false; + m_dragData.startScenePos = QPointF(); + m_dragData.originalPath = QPainterPath(); + + // 恢复光标 + setCursor(Qt::ArrowCursor); + + // 确保场景更新 + update(); + + qDebug() << "✓ Drag ended successfully"; + qDebug() << QString(50, '=') << "\n"; +} + +void ElectricConnectLineItem::setLastPoint(const QPointF& point) +{ + m_lastPoint = point; +} + +void ElectricConnectLineItem::setPath(const QPainterPath& path) +{ + qDebug() << "\n=== setPath ==="; + + if (m_points == path) { + return; + } + + prepareGeometryChange(); + m_points = path; // 使用已有的 m_points + updateBoundingRect(); + update(); } QPainterPath ElectricConnectLineItem::shape() const { - QPainterPath path; - //path.addPath(m_points); - path.addPath(m_pointsBoundingRect); - return path; + // 使用路径的轮廓 + if (m_points.isEmpty()) { + return QPainterPath(); + } + + QPainterPathStroker stroker; + stroker.setWidth(8.0); // 选择区域宽度 + + QPainterPath shape = stroker.createStroke(m_points); + return shape; } QRectF ElectricConnectLineItem::boundingRect() const { - return m_boundingRect; + QRectF rect = shape().boundingRect(); + + // 如果shape为空,使用路径边界 + if (rect.isNull() && !m_points.isEmpty()) { + rect = m_points.boundingRect().adjusted(-5, -5, 5, 5); + } + + return rect; } void ElectricConnectLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) @@ -111,245 +272,6 @@ void ElectricConnectLineItem::paint(QPainter* painter, const QStyleOptionGraphic painter->drawPath(m_points); } -void ElectricConnectLineItem::moveLine(QPointF pos) -{ - QPointF delta = pos - m_lastPoint; - if(_curLine.isNull()) - { - if(m_lstPoints.size() > 1) - { - int n = m_lstPoints.size(); - for(int i = 0;i < m_lstPoints.size() -1;++i) - { - QPointF p1 = m_lstPoints[i]; - QPointF p2 = m_lstPoints[i+1]; - - if(p1.x() == p2.x() && abs(p1.x() - pos.x()) < 2) //在相同竖线 - { - if(p1.y() > p2.y()) - { - if(pos.y() > p2.y() && pos.y() < p1.y()) //在竖线上 - { - - if(i == 0 ) //起点是连接点,创建复制点 - { - m_lstPoints.prepend(p1); - m_lstPoints.prepend(p1); - - i+=2; - if(m_lstPoints.size() < 6) //补齐后端 - { - m_lstPoints.append(m_lstPoints.last()); - } - } - if(i+1 == n-1) //终点是连接点,创建复制点 - { - m_lstPoints.append(p2); - m_lstPoints.append(p2); - - m_lstPoints[i+1] = p2; - if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点 - { - m_lstPoints.prepend(m_lstPoints.first()); - i+=1; - } - } - //qDebug() << 1 <<" "< p1.y()) //在竖线上 - { - - if(i == 0) //起点是连接点,创建复制点 - { - m_lstPoints.prepend(p1); - m_lstPoints.prepend(p1); - i+=2; - if(m_lstPoints.size() < 6) //补齐后端 - { - m_lstPoints.append(m_lstPoints.last()); - } - } - if(i+1 == n-1) //终点是连接点,创建复制点 - { - m_lstPoints.append(p2); - m_lstPoints.append(p2); - - m_lstPoints[i+1] = p2; - if(m_lstPoints.size() < 6) //补齐前端 - { - m_lstPoints.prepend(m_lstPoints.first()); - i+=1; - } - } - //qDebug() << 2 <<" "< p2.x()) - { - if(pos.x() > p2.x() && pos.x() < p1.x()) - { - - if(i == 0) //起点是连接点,创建复制点 - { - m_lstPoints.prepend(p1); - m_lstPoints.prepend(p1); - - i+=2; - if(m_lstPoints.size() < 6) //补齐后端 - { - m_lstPoints.append(m_lstPoints.last()); - } - } - if(i+1 == n-1) //终点是连接点,创建复制点 - { - m_lstPoints.append(p2); - m_lstPoints.append(p2); - - if(m_lstPoints.size() < 6) //补齐前端,移动后至少6个点 - { - m_lstPoints.prepend(m_lstPoints.first()); - i+=1; - } - } - //qDebug() << 3 <<" "< p1.x()) - { - - if(i == 0) //起点是连接点,创建复制点 - { - m_lstPoints.prepend(p1); - m_lstPoints.prepend(p1); - - i+=2; - m_lstPoints[i] = p1; - if(m_lstPoints.size() < 6) //补齐后端 - { - m_lstPoints.append(m_lstPoints.last()); - } - } - if(i+1 == n-1) //终点是连接点,创建复制点 - { - m_lstPoints.append(p2); - m_lstPoints.append(p2); - - if(m_lstPoints.size() < 6) //补齐前端 - { - m_lstPoints.prepend(m_lstPoints.first()); - i+=1; - } - } - //qDebug() << 4 <<" "< 3) - { - - if(_curLine.y() == 1) //竖线 - { - if(n == 0) //起点是原点 - { - QPointF p(0,delta.y()); //原点不动 - m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动 - m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只竖直移动 - } - else if(n == 1) - { - QPointF p(delta.x(),0); - m_lstPoints[n] += p; //第一个点只水平移动 - m_lstPoints[n +1] += p; //第二个点只水平移动 - } - else if(n == m_lstPoints.size()-2) //起点是倒数第二个点 - { - QPointF p(0,delta.y()); - m_lstPoints[n] += p; //起点只上下移动 - m_lstPoints[n-1] += p; //上个点只竖直移动 - } - else if(n == m_lstPoints.size()-3) //起点是倒数第三个点 - { - QPointF py(0,delta.y()); - QPointF px(delta.x(),0); - m_lstPoints[n-1] += py; //上个点只垂直移动 - m_lstPoints[n] += delta; //起点任意动 - m_lstPoints[n+1] += px; //第二个点只水平移动 - } - else - { - m_lstPoints[n -1].setY(m_lstPoints[n ].y()); - m_lstPoints[n] += delta; - m_lstPoints[n +1] += delta; - m_lstPoints[n +2].setY(m_lstPoints[n +1].y()); - } - } - else //横线 - { - if(n == 0) //起点是原点 - { - QPointF p(delta.x(),0); //原点不动 - m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只水平移动 - m_lstPoints[n +2] = m_lstPoints[n +2] + p; //第三个点只水平移动 - } - else if(n == 1) - { - QPointF p(0,delta.y()); - m_lstPoints[n] = m_lstPoints[n] + p; //第一个点只竖直移动 - m_lstPoints[n +1] = m_lstPoints[n +1] + p; //第二个点只竖直移动 - } - else if(n == m_lstPoints.size()-2) //起点是倒数第二个点 - { - QPointF p(delta.x(),0); - m_lstPoints[n] += p; //起点水平移动 - m_lstPoints[n-1] += p; //上个点只水平移动 - } - else if(n == m_lstPoints.size()-3) //起点是倒数第三个点 - { - QPointF py(0,delta.y()); - QPointF px(delta.x(),0); - m_lstPoints[n-1] += px; //上个点只水平移动 - m_lstPoints[n] += delta; //起点任意动 - m_lstPoints[n+1] += py; //第二个点只上下移动 - } - else - { - m_lstPoints[n -1].setX(m_lstPoints[n].x()); - m_lstPoints[n] += delta; - m_lstPoints[n +1] += delta; - m_lstPoints[n +2].setX(m_lstPoints[n +1].x()); - } - } - } - - calculatePath(); - } - - m_lastPoint = pos; -} - void ElectricConnectLineItem::calculatePath() { if (m_lstPoints.size() < 2) return; @@ -366,7 +288,7 @@ void ElectricConnectLineItem::calculatePath() qDebug() << "Initialized path, current position:" << m_points.currentPosition(); // 获取元件 - QList components = getComponentCollisionRects(); + QList components = getAllComponentRects(); qDebug() << "Found" << components.size() << "components"; // 检查起点终点距离 @@ -452,7 +374,7 @@ double ElectricConnectLineItem::calculatePathLength(const QList& path) // 单一线段与矩形相交检测 -bool ElectricConnectLineItem::lineIntersectsRect(const QLineF& line, const QRectF& rect) +bool ElectricConnectLineItem::lineIntersectsRect(const QLineF& line, const QRectF& rect) const { // 检查端点是否在矩形内 if (rect.contains(line.p1()) || rect.contains(line.p2())) { @@ -690,3 +612,375 @@ QRectF ElectricConnectLineItem::findFirstBlockingComponent(const QPointF& start, return QRectF(); } +double ElectricConnectLineItem::distancePointToLine(const QLineF& line, const QPointF& point) const +{ + // 向量法计算点到线段的最短距离 + + if (line.isNull()) { + return QLineF(point, line.p1()).length(); + } + + QPointF v = line.p2() - line.p1(); // 线段向量 + QPointF w = point - line.p1(); // 点到线段起点的向量 + + // 计算点积 + double c1 = w.x() * v.x() + w.y() * v.y(); // w·v + if (c1 <= 0.0) { + // 点在线段起点后方 + return QLineF(point, line.p1()).length(); + } + + double c2 = v.x() * v.x() + v.y() * v.y(); // v·v + if (c2 <= c1) { + // 点在线段终点前方 + return QLineF(point, line.p2()).length(); + } + + // 计算投影点 + double b = c1 / c2; + QPointF projection = line.p1() + b * v; + return QLineF(point, projection).length(); +} + +void ElectricConnectLineItem::ensureEnoughPointsForDrag() +{ + qDebug() << "\n=== ensureEnoughPointsForDrag ==="; + qDebug() << "Current points:" << m_lstPoints.size(); + + if (m_lstPoints.size() < 2) { + qWarning() << "Not enough points!"; + return; + } + + // 如果是只有2个点的直线,需要添加转折点 + if (m_lstPoints.size() == 2) { + QPointF start = m_lstPoints[0]; + QPointF end = m_lstPoints[1]; + + // 如果是斜线,添加转折点 + if (start.x() != end.x() && start.y() != end.y()) { + QPointF turnPoint; + + // 选择转折方式 + if (qAbs(end.x() - start.x()) < qAbs(end.y() - start.y())) { + // 接近垂直,先水平 + turnPoint = QPointF(end.x(), start.y()); + } else { + // 接近水平,先垂直 + turnPoint = QPointF(start.x(), end.y()); + } + + m_lstPoints.insert(1, turnPoint); + qDebug() << "Added turn point:" << turnPoint; + qDebug() << "Now have" << m_lstPoints.size() << "points"; + + // 重新计算路径 + calculatePath(); + } + } +} + +void ElectricConnectLineItem::debugPathState(const QString& context) const +{ + qDebug() << "\n=== Debug Path State:" << context << "==="; + qDebug() << "m_lstPoints count:" << m_lstPoints.size(); + qDebug() << "m_dragState.isDragging:" << m_dragData.isActive; + qDebug() << "m_dragState.segmentIndex:" << m_dragData.segmentIndex; + qDebug() << "m_dragState.isVertical:" << m_dragData.isVertical; + + for (int i = 0; i < m_lstPoints.size(); i++) { + qDebug() << QString(" Point[%1]: (%2, %3)") + .arg(i) + .arg(m_lstPoints[i].x(), 0, 'f', 1) + .arg(m_lstPoints[i].y(), 0, 'f', 1); + } + + // 检查每个线段 + for (int i = 0; i < m_lstPoints.size() - 1; i++) { + QPointF p1 = m_lstPoints[i]; + QPointF p2 = m_lstPoints[i + 1]; + + bool isVertical = qFuzzyCompare(p1.x(), p2.x()); + bool isHorizontal = qFuzzyCompare(p1.y(), p2.y()); + + QString type = "DIAGONAL"; + if (isVertical) type = "VERTICAL"; + else if (isHorizontal) type = "HORIZONTAL"; + + qDebug() << QString(" Segment[%1]: %2, length=%3") + .arg(i) + .arg(type) + .arg(QLineF(p1, p2).length(), 0, 'f', 1); + } +} + +QVector ElectricConnectLineItem::extractSegmentsFromPainterPath() const +{ + QVector segments; + + if (m_points.isEmpty()) { + return segments; + } + + // 遍历QPainterPath的所有元素 + QPointF lastPoint; + bool hasLastPoint = false; + + for (int i = 0; i < m_points.elementCount(); i++) { + QPainterPath::Element elem = m_points.elementAt(i); + QPointF currentPoint(elem.x, elem.y); + + switch (elem.type) { + case QPainterPath::MoveToElement: + lastPoint = currentPoint; + hasLastPoint = true; + break; + + case QPainterPath::LineToElement: + if (hasLastPoint) { + segments.append(QLineF(lastPoint, currentPoint)); + } + lastPoint = currentPoint; + hasLastPoint = true; + break; + + case QPainterPath::CurveToElement: + // 处理曲线(如果需要) + break; + + case QPainterPath::CurveToDataElement: + // 曲线数据 + break; + } + } + + return segments; +} + +int ElectricConnectLineItem::findSegmentAt(const QList& points, + const QPointF& itemPos) const +{ + if (points.size() < 2) { + return -1; + } + + const double HIT_TOLERANCE = 10.0; + int bestSegment = -1; + double bestDistance = HIT_TOLERANCE; + + for (int i = 0; i < points.size() - 1; i++) { + QLineF segment(points[i], points[i + 1]); + + // 计算距离 + double distance = distanceToSegment(segment, itemPos); + + if (distance < bestDistance) { + bestDistance = distance; + bestSegment = i; + } + } + + return bestSegment; +} + +double ElectricConnectLineItem::distanceToSegment(const QLineF& segment, const QPointF& point) const +{ + if (segment.isNull()) { + return std::numeric_limits::max(); + } + + // 检查是否是正交线段 + bool isHorizontal = qFuzzyCompare(segment.y1(), segment.y2()); + bool isVertical = qFuzzyCompare(segment.x1(), segment.x2()); + + if (isHorizontal) { + // 水平线段 + double minX = qMin(segment.x1(), segment.x2()); + double maxX = qMax(segment.x1(), segment.x2()); + double y = segment.y1(); + + if (point.x() >= minX && point.x() <= maxX) { + return qAbs(point.y() - y); + } else if (point.x() < minX) { + return QLineF(point, QPointF(minX, y)).length(); + } else { + return QLineF(point, QPointF(maxX, y)).length(); + } + } + else if (isVertical) { + // 垂直线段 + double minY = qMin(segment.y1(), segment.y2()); + double maxY = qMax(segment.y1(), segment.y2()); + double x = segment.x1(); + + if (point.y() >= minY && point.y() <= maxY) { + return qAbs(point.x() - x); + } else if (point.y() < minY) { + return QLineF(point, QPointF(x, minY)).length(); + } else { + return QLineF(point, QPointF(x, maxY)).length(); + } + } + else { + // 斜线(理论上不应该出现) + return QLineF(segment.p1(), point).length(); + } +} + +QList ElectricConnectLineItem::extractPointsFromPath() const +{ + QList points; + + if (m_points.isEmpty()) { + return points; + } + + // 从 QPainterPath 提取所有点 + for (int i = 0; i < m_points.elementCount(); i++) { + QPainterPath::Element elem = m_points.elementAt(i); + if (elem.type == QPainterPath::MoveToElement || + elem.type == QPainterPath::LineToElement) { + points.append(QPointF(elem.x, elem.y)); + } + } + + return points; +} + +QList ElectricConnectLineItem::extractPointsFromPath(const QPainterPath& path) const +{ + QList points; + + if (path.isEmpty()) { + return points; + } + + for (int i = 0; i < path.elementCount(); i++) { + QPainterPath::Element elem = path.elementAt(i); + if (elem.type == QPainterPath::MoveToElement || + elem.type == QPainterPath::LineToElement) { + points.append(QPointF(elem.x, elem.y)); + } + } + + return points; +} + +void ElectricConnectLineItem::applyPointsToPath(const QList& points) +{ + if (points.size() < 2) { + m_points = QPainterPath(); + return; + } + + QPainterPath newPath; + newPath.moveTo(points.first()); + + for (int i = 1; i < points.size(); i++) { + newPath.lineTo(points[i]); + } + + m_points = newPath; + setPath(m_points); +} + +void ElectricConnectLineItem::fixConnections(QList& points, + int segmentIndex, bool isVertical) +{ + int n = points.size(); + if (n < 3) { + return; + } + + if (isVertical) { + // 垂直线段移动 + if (segmentIndex > 0) { + points[segmentIndex - 1].setX(points[segmentIndex].x()); + } + if (segmentIndex + 2 < n) { + points[segmentIndex + 2].setX(points[segmentIndex + 1].x()); + } + } else { + // 水平线段移动 + if (segmentIndex > 0) { + points[segmentIndex - 1].setY(points[segmentIndex].y()); + } + if (segmentIndex + 2 < n) { + points[segmentIndex + 2].setY(points[segmentIndex + 1].y()); + } + } +} + +void ElectricConnectLineItem::validateAndFixPath() +{ + qDebug() << "Validating and fixing path..."; + + QList points = extractPointsFromPath(); + + if (points.size() < 2) { + qWarning() << "Path has less than 2 points"; + return; + } + + bool needsFix = false; + + // 检查每个线段 + for (int i = 0; i < points.size() - 1; i++) { + QPointF& p1 = points[i]; + QPointF& p2 = points[i + 1]; + + // 检查是否正交 + if (!qFuzzyCompare(p1.x(), p2.x()) && !qFuzzyCompare(p1.y(), p2.y())) { + qDebug() << "Fixing non-orthogonal segment" << i; + + // 选择主要方向 + double dx = qAbs(p2.x() - p1.x()); + double dy = qAbs(p2.y() - p1.y()); + + if (dx < dy) { + p2.setX(p1.x()); // 改为垂直 + } else { + p2.setY(p1.y()); // 改为水平 + } + + needsFix = true; + } + } + + // 移除连续重复点 + QList cleanedPoints; + cleanedPoints.append(points.first()); + + for (int i = 1; i < points.size(); i++) { + if (!points[i - 1].isNull() && + qFuzzyCompare(points[i - 1].x(), points[i].x()) && + qFuzzyCompare(points[i - 1].y(), points[i].y())) { + continue; // 跳过重复点 + } + cleanedPoints.append(points[i]); + } + + if (needsFix || cleanedPoints.size() != points.size()) { + qDebug() << "Applying fixes to path"; + applyPointsToPath(cleanedPoints); + + // 重新计算路径 + calculatePath(); + } +} + +void ElectricConnectLineItem::updateBoundingRect() +{ + if (m_points.isEmpty()) { + m_boundingRect = QRectF(); + } else { + // 使用路径的边界 + m_boundingRect = m_points.boundingRect(); + + // 添加一些边距 + const qreal MARGIN = 2.0; + m_boundingRect.adjust(-MARGIN, -MARGIN, MARGIN, MARGIN); + } + + qDebug() << "Updated bounds:" << m_boundingRect; +} diff --git a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp index f5b0b15..f07b952 100644 --- a/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp +++ b/diagramCavas/source/graphicsItem/graphicsBaseItem.cpp @@ -398,7 +398,7 @@ void GraphicsBaseItem::rearrangeDynamicText() } } -QList GraphicsBaseItem::getComponentCollisionRects() const +QList GraphicsBaseItem::getAllComponentRects() const { QList lst; if(_pHandle){ diff --git a/diagramCavas/source/monitorPanel.cpp b/diagramCavas/source/monitorPanel.cpp index ae138af..d4253fb 100644 --- a/diagramCavas/source/monitorPanel.cpp +++ b/diagramCavas/source/monitorPanel.cpp @@ -282,10 +282,10 @@ void MonitorPanel::loadNodes(QJsonObject obj) } QJsonArray relationArr = obj["relation"].toArray(); - QList lstRelation; + QList lstRelation; bool resRel = deserializeRelationFromJsonArray(relationArr, lstRelation); if(resRel){ - QList lstFirst; + QList lstFirst; if(_pModel){ auto pItems = _pModel->getProjectItems(); for(auto& itemInfo:lstRelation) @@ -299,7 +299,7 @@ void MonitorPanel::loadNodes(QJsonObject obj) } } - QList lstSecond; + QList lstSecond; for(auto& itemInfo:lstRelation) //第二次循环处理间隔内设备 { if(itemInfo.item.nCategory == 0){ //间隔 @@ -324,7 +324,7 @@ void MonitorPanel::saveNodes(int pageId) } -void MonitorPanel::updateSelectedItems(QList lst,bool val) +void MonitorPanel::updateSelectedItems(QList lst,bool val) { if(val){ QStandardItem *root = _itemListmodel->invisibleRootItem(); @@ -625,7 +625,7 @@ void MonitorPanel::initDisplaySetting() } } -QJsonArray MonitorPanel::serializeRelationToJsonArray(const QList& data) const +QJsonArray MonitorPanel::serializeRelationToJsonArray(const QList& data) const { QJsonArray rootArray; @@ -637,14 +637,14 @@ QJsonArray MonitorPanel::serializeRelationToJsonArray(const QList -bool MonitorPanel::deserializeRelationFromJsonArray(const QJsonArray& jsonArray, QList& result) +bool MonitorPanel::deserializeRelationFromJsonArray(const QJsonArray& jsonArray, QList& result) { result.clear(); for (const QJsonValue& itemValue : jsonArray) { if (!itemValue.isObject()) continue; - monitorRelationItem relationItem; + RelationItem relationItem; relationItem.fromJson(itemValue.toObject()); if (relationItem.isValid()) { diff --git a/diagramCavas/source/structDataPreviewDlg.cpp b/diagramCavas/source/structDataPreviewDlg.cpp index 5fdc540..545047f 100644 --- a/diagramCavas/source/structDataPreviewDlg.cpp +++ b/diagramCavas/source/structDataPreviewDlg.cpp @@ -7,7 +7,7 @@ #include #include #include "titleBar.h" -#include "instance/extraPropertyManager.h" +#include "extraPropertyManager.h" #include "structDataSource.h" #include "structDataMeasurementModel.h" #include "structDataPropertyModel.h" diff --git a/diagramCavas/source/util/baseSelector.cpp b/diagramCavas/source/util/baseSelector.cpp index 8502f13..9c91af4 100644 --- a/diagramCavas/source/util/baseSelector.cpp +++ b/diagramCavas/source/util/baseSelector.cpp @@ -292,7 +292,6 @@ void BaseSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene { if(item->getItemType() == GIT_bay) return; - item->setPosition(item->pos()); if(ms_nDragHandle == H_none) { //设置光标样式 @@ -475,12 +474,12 @@ void BaseSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, DesignerSc view->setDragMode(QGraphicsView::NoDrag); } - QList lst; //发送已选中的元件 + QList lst; //发送已选中的元件 QList items = scene->selectedItems(); for(auto& pItem:items){ GraphicsProjectModelItem* item = dynamic_cast(pItem); if(item){ - monitorRelationItem info; + RelationItem info; auto pPro = item->getProperty(); if(pPro){ info.item.nCategory = 0; @@ -493,7 +492,7 @@ void BaseSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, DesignerSc else{ GraphicsNonStandardItem* bay = dynamic_cast(pItem); if(bay){ - monitorRelationItem info; + RelationItem info; auto pBayPro = bay->getProperty(); if(pBayPro){ info.item.nCategory = 1; diff --git a/diagramCavas/source/util/linkMovingSelector.cpp b/diagramCavas/source/util/linkMovingSelector.cpp index 30a0850..e060bdb 100644 --- a/diagramCavas/source/util/linkMovingSelector.cpp +++ b/diagramCavas/source/util/linkMovingSelector.cpp @@ -17,31 +17,23 @@ LinkMovingSelector::~LinkMovingSelector() void LinkMovingSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene,DiagramMode sceneMode) { ms_ptMouseLast = event->scenePos(); - - //QList items = scene->selectedItems(); } void LinkMovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene,DiagramMode sceneMode) { ms_ptMouseLast = event->scenePos(); - - if(m_pMovingLine == nullptr) - { - QList items = scene->selectedItems(); - if (items.count() == 1) //只有一个选中 - { + if (m_pMovingLine == nullptr) { + QList items = scene->selectedItems(); + if (items.count() == 1) { ElectricConnectLineItem* item = qgraphicsitem_cast(items.first()); - if(item) - { + if (item) { m_pMovingLine = item; - item->setLastPoint(ms_ptMouseLast); + m_pMovingLine->startDrag(event->scenePos()); + qDebug() << "Started drag on line at:" << event->scenePos(); } } - } - else - { - //if(m_pMovingLine) - //m_pMovingLine->moveLine(ms_ptMouseLast); //暂时屏蔽移动线 260204 + } else { + m_pMovingLine->updateDrag(event->scenePos()); } } @@ -50,8 +42,7 @@ void LinkMovingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, Desi { if(m_pMovingLine) { - m_pMovingLine->resetCurLine(); - qDebug()<<"reset"; + m_pMovingLine->endDrag(); } m_pMovingLine = nullptr; ms_nDragHandle = H_none; diff --git a/diagramCavas/source/util/movingSelector.cpp b/diagramCavas/source/util/movingSelector.cpp index bdc3a99..085fc32 100644 --- a/diagramCavas/source/util/movingSelector.cpp +++ b/diagramCavas/source/util/movingSelector.cpp @@ -42,7 +42,7 @@ void MovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerSce void MovingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene,DiagramMode sceneMode) { - QList lst; //发送已选中的元件 + QList lst; //发送已选中的元件 QList items = scene->selectedItems(); for(int n = 0; n < items.size(); n++) { @@ -53,7 +53,7 @@ void MovingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, Designer GraphicsProjectModelItem* p = dynamic_cast(items.at(n)); if(p){ auto pPro = p->getProperty(); - monitorRelationItem info; + RelationItem info; if(pPro){ info.item.nCategory = 0; info.item.nEquipType = pPro->type(); @@ -65,7 +65,7 @@ void MovingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, Designer else{ GraphicsNonStandardItem* bay = dynamic_cast(items.at(n)); if(bay){ - monitorRelationItem info; + RelationItem info; auto pBayPro = bay->getProperty(); if(pBayPro){ info.item.nCategory = 1; diff --git a/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui b/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui index f116342..326ae34 100644 --- a/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui +++ b/diagramCavas/ui/diagramEditorBayDetailAddDlg.ui @@ -6,8 +6,8 @@ 0 0 - 650 - 460 + 605 + 580 diff --git a/diagramCavas/ui/diagramEditorBayDetailSettingDlg.ui b/diagramCavas/ui/diagramEditorBayDetailSettingDlg.ui index a03bc7d..330ce36 100644 --- a/diagramCavas/ui/diagramEditorBayDetailSettingDlg.ui +++ b/diagramCavas/ui/diagramEditorBayDetailSettingDlg.ui @@ -6,8 +6,8 @@ 0 0 - 650 - 460 + 605 + 580 @@ -18,7 +18,7 @@ Dialog - + 0 @@ -165,37 +165,6 @@ QPushButton:disabled { - - - - QPushButton { - background-color: #5a79a1; /* 中性灰蓝,不刺眼 */ - color: white; - border: none; /* 无边框,扁平化 */ - border-radius: 4px; /* 小圆角,扁平感 */ - font-size: 13px; /* 适中字号 */ - font-weight: 500; /* 中等字重 */ -} - -QPushButton:hover { - background-color: #4a5d7e; /* 稍深的灰蓝 */ -} - -QPushButton:pressed { - background-color: #3d4e6b; /* 更深的灰蓝 */ -} - -QPushButton:disabled { - background-color: #a0b3d1; /* 灰调的浅蓝 */ - color: #d1dce9; /* 浅灰色文字 */ -} - - - - 预览间隔 - - - @@ -211,6 +180,13 @@ QPushButton:disabled { + + + + 结构预览 + + + diff --git a/diagramCavas/ui/diagramEditorTransDetailSettingDlg.ui b/diagramCavas/ui/diagramEditorTransDetailSettingDlg.ui index 2739d57..eebf5ef 100644 --- a/diagramCavas/ui/diagramEditorTransDetailSettingDlg.ui +++ b/diagramCavas/ui/diagramEditorTransDetailSettingDlg.ui @@ -6,8 +6,8 @@ 0 0 - 650 - 460 + 605 + 580 @@ -18,7 +18,7 @@ Dialog - + 0 @@ -134,6 +134,27 @@ QWidget QLabel { + + + + 预览模式: + + + + + + + + 中性点 + + + + + 变压器 + + + + @@ -178,68 +199,6 @@ QPushButton:disabled { - - - - QPushButton { - background-color: #5a79a1; /* 中性灰蓝,不刺眼 */ - color: white; - border: none; /* 无边框,扁平化 */ - border-radius: 4px; /* 小圆角,扁平感 */ - font-size: 13px; /* 适中字号 */ - font-weight: 500; /* 中等字重 */ -} - -QPushButton:hover { - background-color: #4a5d7e; /* 稍深的灰蓝 */ -} - -QPushButton:pressed { - background-color: #3d4e6b; /* 更深的灰蓝 */ -} - -QPushButton:disabled { - background-color: #a0b3d1; /* 灰调的浅蓝 */ - color: #d1dce9; /* 浅灰色文字 */ -} - - - - 预览成套装置 - - - - - - - QPushButton { - background-color: #5a79a1; /* 中性灰蓝,不刺眼 */ - color: white; - border: none; /* 无边框,扁平化 */ - border-radius: 4px; /* 小圆角,扁平感 */ - font-size: 13px; /* 适中字号 */ - font-weight: 500; /* 中等字重 */ -} - -QPushButton:hover { - background-color: #4a5d7e; /* 稍深的灰蓝 */ -} - -QPushButton:pressed { - background-color: #3d4e6b; /* 更深的灰蓝 */ -} - -QPushButton:disabled { - background-color: #a0b3d1; /* 灰调的浅蓝 */ - color: #d1dce9; /* 浅灰色文字 */ -} - - - - 预览变压器 - - - @@ -329,6 +288,13 @@ QTabBar::tab:selected { + + + + 结构预览 + + + diff --git a/include/monitorItemsDlg.h b/include/monitorItemsDlg.h index 1140f5d..dc0322f 100644 --- a/include/monitorItemsDlg.h +++ b/include/monitorItemsDlg.h @@ -19,12 +19,12 @@ public: void initial(); signals: - void generateMonitor(QString,QList); //生成监控 + void generateMonitor(QString,QList); //生成监控 public slots: - void onUpdateItems(QList,bool refresh); //更新当前设备列表 - void onSelectItems(QList); //更新当前选中的设备 + void onUpdateItems(QList,bool refresh); //更新当前设备列表 + void onSelectItems(QList); //更新当前选中的设备 void onGenerateClicked(); - void onMonitorCreated(QList); //创建后的设备列表 + void onMonitorCreated(QList); //创建后的设备列表 void onItemChanged(QStandardItem *item); //item勾选事件 private: void resetSelect(); //重置选中 @@ -34,10 +34,15 @@ private: QList getCheckedItems(QStandardItem* parentItem); //返回checked对象 QList getTreeViewCheckedItems(QTreeView* treeView); //返回checked对象 + + // 查找间隔节点 + QStandardItem* findBayItem(const QString& bayName); private: Ui::monitorItemsDlg *ui; QStandardItemModel* _modelAll; //图中所有item QStandardItemModel* _modelSelect; //生成的item + // 存储间隔名称到树节点的映射,提高查找效率 + QHash m_mapBayItems; }; #endif diff --git a/include/topologyView.h b/include/topologyView.h index 26382c1..d1665a5 100644 --- a/include/topologyView.h +++ b/include/topologyView.h @@ -10,6 +10,8 @@ namespace Ui { class topologyView; } QT_END_NAMESPACE class TopologyTree; +class ExtraPropertyManager; +class StructDataSource; class TopologyView : public QDialog { @@ -27,18 +29,27 @@ signals: void entityDelete(EntityInfo); void entitySelected(EntityInfo); public slots: - void onIndexRbtnClicked(const QPoint &pos); //索引列表右键菜单 void onItemChanged(QStandardItem *item); void onItemClicked(const QModelIndex &index); - - void onDataCreated(QString uuid); - void onDataChanged(QString uuid); + void onUpdateTopology(QList lst,bool refresh); private: - void addItemToView(QString sGrid,QString sZone,QString sStation,QStandardItem *root,QStandardItem *item); + void clearItems(); + QString getLevelType(int index); + void buildTreeStructure(QStandardItemModel* model, const QVector& properties); + QVector getPropertiesForNode(QStandardItem* node); + QString getNodeInfo(QStandardItem* node); + QStandardItem* findBayItem(const QString& voltageLevel, const QString& bayName); + QStandardItem* findOrCreateVoltageLevel(const QString& voltageLevel); // 查找或创建电压层级节点 + QStandardItem* createBayItem(const QString& voltageLevel, const RelationSturctItem& bayInfo); + void createDeviceItem(QStandardItem* pParent, const RelationSturctItem& deviceInfo); // 创建设备节点 private: Ui::topologyView *ui; - QStandardItemModel* _pModel; + QStandardItemModel* _treeModel; + ExtraPropertyManager* _pExtraProManager; + StructDataSource* m_dataSource; TopologyTree* _treeView; + QHash m_mapVoltageLevels; // 存储电压层级名称到树节点的映射 + QHash m_mapBayItems; // 存储间隔节点,key格式为"电压层级|间隔名称" }; #endif diff --git a/source/mainwindow.cpp b/source/mainwindow.cpp index fc10028..63afcf0 100644 --- a/source/mainwindow.cpp +++ b/source/mainwindow.cpp @@ -175,6 +175,8 @@ void CMainWindow::initializeAction() connect(m_pTopologyView,&TopologyView::entityDelete,m_pDiagramCavas,&DiagramCavas::onSignal_deleteEntity); connect(m_pTopologyView,&TopologyView::entitySelected,m_pDiagramCavas,&DiagramCavas::onSignal_selectEntity); + connect(m_pDiagramCavas,&DiagramCavas::prepareUpdateTopology,m_pTopologyView,&TopologyView::onUpdateTopology); + //connect(m_pDiagramView,&DiagramView::diagramCreate,m_pDiagramCavas,&DiagramCavas::onSignal_createDiagram); connect(m_pDiagramView,&DiagramView::diagramChange,m_pDiagramCavas,&DiagramCavas::onSignal_changeDiagram); connect(m_pDiagramView,&DiagramView::diagramDelete,m_pDiagramCavas,&DiagramCavas::onSignal_deleteDiagram); diff --git a/source/monitorItemsDlg.cpp b/source/monitorItemsDlg.cpp index b05e0e8..d6a8a16 100644 --- a/source/monitorItemsDlg.cpp +++ b/source/monitorItemsDlg.cpp @@ -33,61 +33,74 @@ void MonitorItemsDlg::initial() connect(_modelAll, &QStandardItemModel::itemChanged,this, &MonitorItemsDlg::onItemChanged); } -void MonitorItemsDlg::onUpdateItems(QList lst,bool refresh) +void MonitorItemsDlg::onUpdateItems(QList lst,bool refresh) { if(refresh){ QStandardItem *root = _modelAll->invisibleRootItem(); - int rowCount = root->rowCount(); if (rowCount > 0) { _modelAll->removeRows(0, rowCount); } + // 清空间隔节点缓存 + m_mapBayItems.clear(); } + // 先处理间隔节点(nCategory == 1) for(auto &info:lst){ auto curItem = info.item; - if(curItem.nCategory == 0){ + if(curItem.nCategory == 1){ // 间隔信息 + // 查找是否已存在该间隔节点 + QStandardItem* pBayItem = findBayItem(curItem.sName); + if(!pBayItem){ + // 创建间隔节点 + pBayItem = new QStandardItem(curItem.sName); + pBayItem->setCheckable(true); // 启用勾选框 + pBayItem->setCheckState(Qt::Unchecked); + pBayItem->setData(curItem.nCategory, Qt::UserRole+1); // 存储类别 + pBayItem->setData(curItem.nEquipType, Qt::UserRole+2); // 存储设备类型 + pBayItem->setData(curItem.uid, Qt::UserRole+3); // 存储UUID - if(curItem.nEquipType == 1 || curItem.nEquipType == 15 || curItem.nEquipType == 16){ //母线与变压器等间隔外设备并列第一层 - QStandardItem *pItem = new QStandardItem(curItem.sName); - pItem->setCheckable(true); // 启用勾选框 - pItem->setCheckState(Qt::Unchecked); - pItem->setData(curItem.nCategory,Qt::UserRole+1); - pItem->setData(curItem.nEquipType,Qt::UserRole+2); - pItem->setData(curItem.uid,Qt::UserRole+3); - - for(auto& subInfo:info.subList){ //母线挂接间隔,变压器挂接设备 - QStandardItem *pSub = new QStandardItem(subInfo.sName); - pSub->setCheckable(true); // 启用勾选框 - pSub->setCheckState(Qt::Unchecked); - pSub->setData(subInfo.nCategory,Qt::UserRole+1); - pSub->setData(subInfo.nEquipType,Qt::UserRole+2); - pSub->setData(subInfo.uid,Qt::UserRole+3); - pItem->appendRow(pSub); - } - _modelAll->appendRow(pItem); + // 存储到缓存中 + m_mapBayItems[curItem.sName] = pBayItem; + _modelAll->appendRow(pBayItem); } - else{ //其他设备挂接在母线下的间隔中 - if(!info.parent.sName.isEmpty()){ //有父,在间隔内 + } + } + + // 再处理设备节点(nCategory == 0) + for(auto &info:lst){ + auto curItem = info.item; + if(curItem.nCategory == 0){ // 设备信息 + // 获取设备所属的间隔名称 + QString bayName = info.parent.sName; + + if(!bayName.isEmpty()){ + // 查找对应的间隔节点 + QStandardItem* pBayItem = findBayItem(bayName); + + if(pBayItem){ + // 创建设备节点 QStandardItem *pItem = new QStandardItem(curItem.sName); pItem->setCheckable(true); // 启用勾选框 pItem->setCheckState(Qt::Unchecked); - pItem->setData(curItem.nCategory,Qt::UserRole+1); - pItem->setData(curItem.nEquipType,Qt::UserRole+2); - pItem->setData(curItem.uid,Qt::UserRole+3); + pItem->setData(curItem.nCategory, Qt::UserRole+1); + pItem->setData(curItem.nEquipType, Qt::UserRole+2); + pItem->setData(curItem.uid, Qt::UserRole+3); - auto pParent = findStandardItemAtLevel(_modelAll,1,info.parent.sName,nullptr,0); //查找父间隔所在item - if(pParent){ - pParent->appendRow(pItem); - } + // 不再为母线或独立设备添加子设备 + // 所有设备都作为间隔的直接子节点 + + pBayItem->appendRow(pItem); } } } } + + // 展开所有节点 ui->treeView_all->expandAll(); } -void MonitorItemsDlg::onSelectItems(QList lst) +void MonitorItemsDlg::onSelectItems(QList lst) { ui->stackedWidget->setCurrentIndex(0); resetSelect(); @@ -109,10 +122,10 @@ void MonitorItemsDlg::onGenerateClicked() ui->le_name->setFocus(); return; } - QList lst; + QList lst; QList lstItem = getTreeViewCheckedItems(ui->treeView_all); for(auto& pItem:lstItem){ - monitorRelationItem info; + RelationItem info; auto pParent = pItem->parent(); if(pParent){ info.parent.nCategory = pParent->data(Qt::UserRole+1).toInt(); @@ -127,7 +140,7 @@ void MonitorItemsDlg::onGenerateClicked() auto lstChild = getAllChildren(pItem); for(auto &child:lstChild){ - monitorRelationSturctItem stru; + RelationSturctItem stru; stru.nCategory = child->data(Qt::UserRole+1).toInt(); stru.nEquipType = child->data(Qt::UserRole+2).toInt(); stru.uid = child->data(Qt::UserRole+3).toUuid(); @@ -140,7 +153,7 @@ void MonitorItemsDlg::onGenerateClicked() emit generateMonitor(sName,lst); } -void MonitorItemsDlg::onMonitorCreated(QList lst) +void MonitorItemsDlg::onMonitorCreated(QList lst) { /*ui->stackedWidget->setCurrentIndex(1); ui->listWidget_select->clear(); @@ -201,6 +214,24 @@ void MonitorItemsDlg::traverseSelectStandardItem(QStandardItem *item, int depth, } } +QStandardItem* MonitorItemsDlg::findBayItem(const QString& bayName) +{ + // 先从缓存查找 + if(m_mapBayItems.contains(bayName)){ + return m_mapBayItems[bayName]; + } + + // 遍历查找 + for(int i = 0; i < _modelAll->rowCount(); ++i){ + QStandardItem* pItem = _modelAll->item(i); + if(pItem->text() == bayName && + pItem->data(Qt::UserRole+1).toInt() == 1){ // 类别为间隔 + return pItem; + } + } + return nullptr; +} + QList MonitorItemsDlg::getCheckedItems(QStandardItem* parentItem) { QList checkedItems; diff --git a/source/topologyView.cpp b/source/topologyView.cpp index 4395919..6df3a4c 100644 --- a/source/topologyView.cpp +++ b/source/topologyView.cpp @@ -5,6 +5,8 @@ #include "dataBase.h" #include "basePropertyManager.h" #include "baseProperty.h" +#include "structDataSource.h" +#include "extraPropertyManager.h" #include #include #include @@ -12,12 +14,13 @@ TopologyView::TopologyView(QWidget *parent) : QDialog(parent) , ui(new Ui::topologyView) - ,_pModel(nullptr) + ,_treeModel(nullptr) ,_treeView(nullptr) + ,_pExtraProManager(nullptr) { ui->setupUi(this); //setWindowFlags(windowFlags() | Qt::WindowMinMaxButtonsHint&Qt::WindowCloseButtonHint); - _pModel = new QStandardItemModel(this); + _treeModel = new QStandardItemModel(this); _treeView = new TopologyTree(this); ui->verticalLayout->addWidget(_treeView); _treeView->setContextMenuPolicy(Qt::CustomContextMenu); @@ -31,170 +34,47 @@ TopologyView::~TopologyView() void TopologyView::initial() { - connect(_treeView, &QTreeView::customContextMenuRequested, this, &TopologyView::onIndexRbtnClicked); connect(_treeView, &QTreeView::clicked, this, &TopologyView::onItemClicked); - connect(_pModel, &QStandardItemModel::itemChanged, this, &TopologyView::onItemChanged); - connect(&BasePropertyManager::instance(),&BasePropertyManager::dataChanged,this,&TopologyView::onDataChanged); + connect(_treeModel, &QStandardItemModel::itemChanged, this, &TopologyView::onItemChanged); + + m_dataSource = new StructDataSource(this); + _pExtraProManager = new ExtraPropertyManager(this); + _pExtraProManager->initial(); + + if(_pExtraProManager) + m_dataSource->loadExtrapro(_pExtraProManager->geAlltProperty()); _treeView->setHeaderHidden(true); // 设置模型的列数 - _pModel->setColumnCount(1); - - // 设置模型的标题 - //_pModel->setHeaderData(0, Qt::Horizontal, QObject::tr("层级")); - - QStandardItem *rootItem = _pModel->invisibleRootItem(); - QList lst= DataBase::GetInstance()->getAllComponents(); - for(auto &info:lst) - { - QString nG= info.grid; - QString nZ = info.zone; - QString nS= info.station; - - //QString sGrid = DataBase::GetInstance()->getGridNameById(nG.toInt()); - //QString sZone = DataBase::GetInstance()->getZoneNameById(nZ.toInt()); - //QString sStation = DataBase::GetInstance()->getStationNameById(nS.toInt()); - - QString sGrid = nG; //暂时不使用id查找名称 - QString sZone = nZ; - QString sStation = nS; - - if(info.name.isEmpty()) - continue; - QStandardItem *pItem = new QStandardItem(info.name); - pItem->setData(info.uuid.toString(),Qt::UserRole); - addItemToView(sGrid,sZone,sStation,rootItem,pItem); - } + _treeModel->setColumnCount(1); // 创建树视图 - _treeView->setModel(_pModel); + _treeView->setModel(_treeModel); // 展开所有节点 _treeView->expandAll(); // 显示树视图 _treeView->setWindowTitle(QObject::tr("拓扑树")); + + loadTopologyFromDB(); } void TopologyView::loadTopologyFromDB() { - -} - -void TopologyView::onIndexRbtnClicked(const QPoint &pos) -{ - // 获取当前点击的位置对应的索引 - QModelIndex index = _treeView->indexAt(pos); - if (!index.isValid()) { - return; // 如果点击的是空白区域,直接返回 - } - - QMenu menu; - QStandardItem* item = _pModel->itemFromIndex(index); - - if(item) + if(_pExtraProManager) { - int nCount = item->rowCount(); - int nLevel = getLevel(item); - if(nLevel == -1) //根节点 - { - QAction *addAction = new QAction("添加电网", this); + //clearItems(); + auto& mapExtra = m_dataSource->allProperties; + /*QStandardItem* root = _treeModel->invisibleRootItem(); + for(auto& pro:mapExtra){ + QStandardItem* propertyItem = new QStandardItem(); + addItemToView(pro,"name",root,propertyItem); + }*/ + QVector vec = QVector::fromList(mapExtra.values()); + buildTreeStructure(_treeModel,vec); - connect(addAction,&QAction::triggered,this,[&](){ - QString uuid = QUuid::createUuid().toString(); - QStandardItem *gridItem = new QStandardItem(QString("电网_")+QString::number(nCount)); - gridItem->setData(uuid,Qt::UserRole+1); - gridItem->setData(int(EntityType::Grid),Qt::UserRole+2); - item->appendRow(gridItem); - - EntityInfo info; - info.eType = EntityType::Grid; - info.sName = gridItem->text(); - info.sUuid = uuid; - emit entityCreate(info); - }); - - menu.addAction(addAction); - } - else if(nLevel == 1) //grid - { - QAction *addAction = new QAction("添加区域", this); - QString sParentid = item->data(Qt::UserRole+1).toString(); - - connect(addAction,&QAction::triggered,this,[&](){ - QString uuid = QUuid::createUuid().toString(); - QStandardItem *zoneItem = new QStandardItem(QString("区域_")+QString::number(nCount)); - zoneItem->setData(uuid,Qt::UserRole+1); - zoneItem->setData(int(EntityType::Zone),Qt::UserRole+2); - item->appendRow(zoneItem); - - EntityInfo info; - info.eType = EntityType::Zone; - info.sName = zoneItem->text(); - info.sParentId = sParentid; - info.sUuid = uuid; - emit entityCreate(info); - - _treeView->expandAll(); - }); - - menu.addAction(addAction); - } - else if(nLevel == 2) //zone - { - QAction *addAction = new QAction("添加场站", this); - QString sParentid = item->data(Qt::UserRole+1).toString(); - - connect(addAction,&QAction::triggered,this,[&](){ - QString uuid = QUuid::createUuid().toString(); - QStandardItem *stationItem = new QStandardItem(QString("场站_")+QString::number(nCount)); - stationItem->setData(uuid,Qt::UserRole+1); - stationItem->setData(int(EntityType::Station),Qt::UserRole+2); - item->appendRow(stationItem); - - EntityInfo info; - info.eType = EntityType::Station; - info.sName = stationItem->text(); - info.sUuid = uuid; - info.sParentId = sParentid; - emit entityCreate(info); - - _treeView->expandAll(); - }); - - menu.addAction(addAction); - } - - if(nLevel != -1) //除了根节点其余都能删除 - { - QAction *delAction = new QAction("删除", this); - connect(delAction,&QAction::triggered,this,[&](){ - QModelIndex currentIndex = _treeView->currentIndex(); - if(currentIndex.isValid()) - { - QStandardItem* pItem = _pModel->itemFromIndex(currentIndex); - if(pItem) - { - QString str = item->text(); - EntityInfo info; - info.sName = str; - info.sUuid = item->data(Qt::UserRole+1).toString(); - info.eType = EntityType(item->data(Qt::UserRole+2).toInt()); - emit entityDelete(info); - - QStandardItem* pParent = item->parent(); - if(pParent) - { - pParent->removeRow(currentIndex.row()); - } - } - } - }); - menu.addAction(delAction); - } + _treeView->expandAll(); } - - // 在点击位置显示菜单 - menu.exec(_treeView->mapToGlobal(pos)); } void TopologyView::onItemChanged(QStandardItem *item) @@ -210,7 +90,7 @@ void TopologyView::onItemChanged(QStandardItem *item) void TopologyView::onItemClicked(const QModelIndex &index) { - QStandardItem* item = _pModel->itemFromIndex(index); + QStandardItem* item = _treeModel->itemFromIndex(index); if(item) { EntityType type = EntityType(item->data(Qt::UserRole+2).toInt()); @@ -226,99 +106,363 @@ void TopologyView::onItemClicked(const QModelIndex &index) } } -void TopologyView::onDataCreated(QString uuid) +void TopologyView::onUpdateTopology(QList lst,bool refresh) { + if(refresh){ + QStandardItem *root = _treeModel->invisibleRootItem(); + int rowCount = root->rowCount(); + if (rowCount > 0) { + _treeModel->removeRows(0, rowCount); + } + // 清空缓存 + m_mapVoltageLevels.clear(); + m_mapBayItems.clear(); + } -} + // 第一阶段:处理间隔节点(nCategory == 1) + for(auto &info:lst){ + auto curItem = info.item; + if(curItem.nCategory == 1){ // 间隔信息 + // 获取间隔的电压层级 + QString voltageLevel = curItem.sVoltageLevel; + if(voltageLevel.isEmpty()){ + voltageLevel = "未知电压等级"; // 默认值 + } -void TopologyView::onDataChanged(QString uuid) -{ - QModelIndex itemIndex = findIndex(_pModel,uuid,Qt::UserRole); - BaseProperty* pData = BasePropertyManager::instance().findEntityData(QUuid(uuid)); - if(pData) - { - if(itemIndex.isValid()) //已存在 - { - QStandardItem *pItem = _pModel->itemFromIndex(itemIndex); - if(pItem) - { - if(pItem->text() != pData->tag()) //已改名 - { - pItem->setText(pData->tag()); - } + // 查找或创建电压层级节点 + QStandardItem* pVoltageItem = findOrCreateVoltageLevel(voltageLevel); - QString sStation = pItem->parent()->text(); - QString sZone = pItem->parent()->parent()->text(); - QString sGrid = pItem->parent()->parent()->parent()->text(); - if(sStation == pData->station() && sZone == pData->zone() && sGrid == pData->grid()) //从属关系未变 - { + // 创建间隔节点 + QStandardItem* pBayItem = createBayItem(voltageLevel, curItem); - } - else - { - QStandardItem* item = _pModel->takeItem(pItem->row()); //从原层级中取出,添加到新的层级 - addItemToView(pData->grid(),pData->zone(),pData->station(),_pModel->invisibleRootItem(),item); + pVoltageItem->appendRow(pBayItem); + } + } + + // 第二阶段:处理设备节点(nCategory == 0) + for(auto &info:lst){ + auto curItem = info.item; + if(curItem.nCategory == 0){ // 设备信息 + // 获取设备所属的间隔名称和电压层级 + QString bayName = info.parent.sName; + QString voltageLevel = info.parent.sVoltageLevel; // 从父间隔获取电压层级 + + if(!bayName.isEmpty() && !voltageLevel.isEmpty()){ + // 查找对应的间隔节点 + QStandardItem* pBayItem = findBayItem(voltageLevel, bayName); + + if(pBayItem){ + // 创建设备节点 + createDeviceItem(pBayItem, curItem); } } } - else - { - QStandardItem *pItem = new QStandardItem(pData->tag()); - pItem->setData(uuid,Qt::UserRole); - addItemToView(pData->grid(),pData->zone(),pData->station(),_pModel->invisibleRootItem(),pItem); + } + + // 展开所有节点 + _treeView->expandAll(); +} + +void TopologyView::clearItems() +{ + if(_treeModel){ + QStandardItem *root = _treeModel->invisibleRootItem(); //先清空model + int rowCount = root->rowCount(); + if (rowCount > 0) { + _treeModel->removeRows(0, rowCount); } } } -void TopologyView::addItemToView(QString sGrid,QString sZone,QString sStation,QStandardItem *root,QStandardItem *pItem) -{ - QModelIndex iG; - QModelIndex iZ; - QModelIndex iS; - - iG = findIndex(_pModel, sGrid, Qt::DisplayRole, QModelIndex()); - if (iG.isValid()) { - iZ = findIndex(_pModel, sZone, Qt::DisplayRole, iG); // 只在Grid下查找 - if (iZ.isValid()) { - iS = findIndex(_pModel, sStation, Qt::DisplayRole, iZ); // 只在Zone下查找 - } - } - - if(iG.isValid()) //已创建 - { - QStandardItem* itemGrid = _pModel->itemFromIndex(iG); - if(iZ.isValid()) - { - QStandardItem* itemZone = _pModel->itemFromIndex(iZ); - if(iS.isValid()) - { - QStandardItem* itemStation = _pModel->itemFromIndex(iS); - itemStation->appendRow(pItem); - } - else - { - QStandardItem* itemStation = new QStandardItem(sStation); - itemStation->appendRow(pItem); - itemZone->appendRow(itemStation); - } - } - else - { - QStandardItem* itemZone = new QStandardItem(sZone); - QStandardItem* itemStation = new QStandardItem(sStation); - itemStation->appendRow(pItem); - itemZone->appendRow(itemStation); - itemGrid->appendRow(itemZone); - } - } - else - { - QStandardItem* itemGrid = new QStandardItem(sGrid); - QStandardItem* itemZone = new QStandardItem(sZone); - QStandardItem* itemStation = new QStandardItem(sStation); - itemStation->appendRow(pItem); - itemZone->appendRow(itemStation); - itemGrid->appendRow(itemZone); - root->appendRow(itemGrid); +QString TopologyView::getLevelType(int index) { + switch (index) { + case 0: return "电网"; + case 1: return "区域"; + case 2: return "站点"; + case 3: return "电压等级"; + case 4: return "间隔"; + case 5: return "设备"; + case 6: return "分组"; + default: return "未知层级"; } } + +void TopologyView::buildTreeStructure(QStandardItemModel* model, + const QVector& properties) { + // 清空模型 + model->clear(); + + // 创建根节点 + //QStandardItem* root = new QStandardItem("拓扑结构"); + //model->appendRow(root); + QStandardItem* root = _treeModel->invisibleRootItem(); + // 存储节点映射:路径 -> 节点 + QMap nodeMap; + + for (const auto& property : properties) { + // 判断是否有设备信息 + bool hasDevice = !property.component_uuid.isNull() && !property.component_name.isEmpty(); + + // 检查间隔信息(根据业务逻辑,间隔应该总是存在) + QString bayDisplayName = property.bay_name.isEmpty() ? + (property.bay_tag.isEmpty() ? "未命名间隔" : property.bay_tag) : + property.bay_name; + + // 构建完整的节点路径 + QStringList pathComponents; + + // 基本层级:电网、区域、站点、电压等级、间隔 + pathComponents << property.grid_name; + pathComponents << property.zone_name; + pathComponents << property.station_name; + pathComponents << property.currentLevel; + pathComponents << bayDisplayName; + + // 如果有设备信息,添加设备层级 + if (hasDevice) { + QString deviceDisplayName = property.component_name.isEmpty() ? + property.component_uuid.toString() : + property.component_name; + pathComponents << deviceDisplayName; + } + + // 构建路径字符串作为唯一标识 + QString pathKey = pathComponents.join("|"); + + // 查找或创建节点路径 + QStandardItem* currentNode = root; + QString currentPath = ""; + + for (int i = 0; i < pathComponents.size(); i++) { + currentPath += (i > 0 ? "|" : "") + pathComponents[i]; + + // 查找是否已存在该节点 + QStandardItem* existingNode = nodeMap.value(currentPath); + + if (!existingNode) { + // 在当前父节点下查找 + for (int row = 0; row < currentNode->rowCount(); row++) { + QStandardItem* child = currentNode->child(row, 0); + if (child && child->text() == pathComponents[i]) { + QVariantMap childData = child->data(Qt::UserRole + 1).toMap(); + QString childPath = childData.value("fullPath").toString(); + if (childPath == currentPath) { + existingNode = child; + nodeMap[currentPath] = child; + break; + } + } + } + } + + if (existingNode) { + currentNode = existingNode; + } else { + // 创建新节点 + QStandardItem* newNode = new QStandardItem(pathComponents[i]); + + // 确定节点类型和层级信息 + QVariantMap nodeData; + nodeData["fullPath"] = currentPath; + nodeData["level"] = i; + + // 根据层级设置节点类型 + QString nodeType; + QString levelType; + + switch (i) { + case 0: nodeType = "grid"; levelType = "电网"; break; + case 1: nodeType = "zone"; levelType = "区域"; break; + case 2: nodeType = "station"; levelType = "站点"; break; + case 3: nodeType = "voltage"; levelType = "电压等级"; break; + case 4: nodeType = "bay"; levelType = "间隔"; break; + case 5: + if (hasDevice) { + nodeType = "device"; + levelType = "设备"; + // 创建设备节点时初始化属性列表 + nodeData["properties"] = QVariant::fromValue(QVector()); + nodeData["propertyCount"] = 0; + nodeData["deviceId"] = property.component_uuid.toString(); + nodeData["deviceName"] = property.component_name; + //nodeData["deviceType"] = property.device_type; + } + break; + } + + // 如果是间隔节点(第4层),也初始化属性列表(用于无设备的情况) + if (i == 4) { + nodeData["properties"] = QVariant::fromValue(QVector()); + nodeData["propertyCount"] = 0; + nodeData["bayName"] = property.bay_name; + nodeData["bayTag"] = property.bay_tag; + } + + nodeData["nodeType"] = nodeType; + nodeData["levelType"] = levelType; + + newNode->setData(nodeData, Qt::UserRole + 1); + currentNode->appendRow(newNode); + currentNode = newNode; + nodeMap[currentPath] = newNode; + } + } + + // 将属性添加到合适的节点 + // 如果有设备,添加到设备节点;否则添加到间隔节点 + QVariantMap targetNodeData = currentNode->data(Qt::UserRole + 1).toMap(); + QVector nodeProperties = targetNodeData["properties"].value>(); + + // 检查属性是否已存在 + bool propertyExists = false; + for (const auto& existingProp : nodeProperties) { + if (existingProp.code == property.code) { + propertyExists = true; + break; + } + } + + if (!propertyExists) { + nodeProperties.append(property); + targetNodeData["properties"] = QVariant::fromValue(nodeProperties); + + // 更新属性数量 + int propertyCount = targetNodeData["propertyCount"].toInt() + 1; + targetNodeData["propertyCount"] = propertyCount; + + // 更新节点显示文本 + QString currentText = currentNode->text(); + // 移除可能存在的数量后缀 + currentText = currentText.replace(QRegularExpression("\\(\\d+\\)$"), "").trimmed(); + currentNode->setText(QString("%1 (%2)").arg(currentText).arg(propertyCount)); + + // 更新工具提示 + QString tooltip = QString("%1: %2").arg(targetNodeData["levelType"].toString()).arg(currentText); + + if (propertyCount > 0) { + tooltip += QString("\n属性数量: %1").arg(propertyCount); + } + + // 添加设备类型信息(如果是设备节点) + if (targetNodeData["nodeType"].toString() == "device") { + tooltip += QString("\n设备类型: %1").arg(targetNodeData["deviceType"].toString()); + } + + currentNode->setToolTip(tooltip); + + // 保存更新后的数据 + currentNode->setData(targetNodeData, Qt::UserRole + 1); + } + } +} + +// 简化的获取属性列表函数 +QVector TopologyView::getPropertiesForNode(QStandardItem* node) { + QVariantMap nodeData = node->data(Qt::UserRole + 1).toMap(); + QString nodeType = nodeData.value("nodeType").toString(); + + if (nodeType == "device" || nodeType == "bay") { + return nodeData["properties"].value>(); + } + + return QVector(); +} + +QString TopologyView::getNodeInfo(QStandardItem* node) { + QVariantMap nodeData = node->data(Qt::UserRole + 1).toMap(); + QString nodeType = nodeData.value("nodeType").toString(); + QString levelType = nodeData.value("levelType").toString(); + QString name = node->text().replace(QRegularExpression("\\(\\d+\\)$"), "").trimmed(); + int propertyCount = nodeData.value("propertyCount", 0).toInt(); + + if (nodeType == "device") { + return QString("%1: %2 (设备类型: %3, 属性数: %4)") + .arg(levelType) + .arg(name) + .arg(nodeData.value("deviceType").toString()) + .arg(propertyCount); + } else if (nodeType == "bay") { + return QString("%1: %2 (属性数: %3)") + .arg(levelType) + .arg(name) + .arg(propertyCount); + } + + return QString("%1: %2").arg(levelType).arg(name); +} + +// 查找或创建电压层级节点 +QStandardItem* TopologyView::findOrCreateVoltageLevel(const QString& voltageLevel) +{ + if(m_mapVoltageLevels.contains(voltageLevel)){ + return m_mapVoltageLevels[voltageLevel]; + } + + QStandardItem* pVoltageItem = new QStandardItem(voltageLevel); + //pVoltageItem->setCheckable(true); + //pVoltageItem->setCheckState(Qt::Unchecked); + pVoltageItem->setData(-1, Qt::UserRole+1); // 特殊标识,表示电压层级 + pVoltageItem->setData(-1, Qt::UserRole+2); + pVoltageItem->setData(QString(), Qt::UserRole+3); + + m_mapVoltageLevels[voltageLevel] = pVoltageItem; + _treeModel->appendRow(pVoltageItem); + + return pVoltageItem; +} + +// 创建间隔节点 +QStandardItem* TopologyView::createBayItem(const QString& voltageLevel, const RelationSturctItem& bayInfo) +{ + QStandardItem* pBayItem = new QStandardItem(bayInfo.sName); + //pBayItem->setCheckable(true); + //pBayItem->setCheckState(Qt::Unchecked); + pBayItem->setData(bayInfo.nCategory, Qt::UserRole+1); + pBayItem->setData(bayInfo.nEquipType, Qt::UserRole+2); + pBayItem->setData(bayInfo.uid, Qt::UserRole+3); + + // 存储到缓存中,key 使用"电压层级|间隔名称"确保唯一 + QString bayKey = QString("%1|%2").arg(voltageLevel).arg(bayInfo.sName); + m_mapBayItems[bayKey] = pBayItem; + + return pBayItem; +} + +// 在电压层级下查找间隔节点 +QStandardItem* TopologyView::findBayItem(const QString& voltageLevel, const QString& bayName) +{ + QString bayKey = QString("%1|%2").arg(voltageLevel).arg(bayName); + + // 先从缓存查找 + if(m_mapBayItems.contains(bayKey)){ + return m_mapBayItems[bayKey]; + } + + // 在对应电压层级下查找 + if(m_mapVoltageLevels.contains(voltageLevel)){ + QStandardItem* pVoltageItem = m_mapVoltageLevels[voltageLevel]; + for(int i = 0; i < pVoltageItem->rowCount(); ++i){ + QStandardItem* pItem = pVoltageItem->child(i); + if(pItem->text() == bayName && + pItem->data(Qt::UserRole+1).toInt() == 1){ + m_mapBayItems[bayKey] = pItem; // 加入缓存 + return pItem; + } + } + } + return nullptr; +} + +// 创建设备节点 +void TopologyView::createDeviceItem(QStandardItem* pParent, const RelationSturctItem& deviceInfo) +{ + QStandardItem* pItem = new QStandardItem(deviceInfo.sName); + //pItem->setCheckable(true); + //pItem->setCheckState(Qt::Unchecked); + pItem->setData(deviceInfo.nCategory, Qt::UserRole+1); + pItem->setData(deviceInfo.nEquipType, Qt::UserRole+2); + pItem->setData(deviceInfo.uid, Qt::UserRole+3); + + pParent->appendRow(pItem); +} +