From 1b5be4de1f1cfaf923a9f1ab375f53a8ed5105ed Mon Sep 17 00:00:00 2001 From: baiYue Date: Tue, 22 Apr 2025 10:10:55 +0800 Subject: [PATCH] fix loger generate --- common/include/global.h | 20 ++ diagramCavas/CMakeLists.txt | 8 + diagramCavas/include/powerConnection.h | 30 +++ diagramCavas/include/powerEntity.h | 100 ++++++++ diagramCavas/include/powerTerminal.h | 52 +++++ diagramCavas/include/topologyManager.h | 74 ++++++ diagramCavas/source/powerConnection.cpp | 13 ++ diagramCavas/source/powerEntity.cpp | 43 ++++ diagramCavas/source/powerTerminal.cpp | 44 ++++ diagramCavas/source/topologyManager.cpp | 298 ++++++++++++++++++++++++ diagramUtils/source/logger.cpp | 2 +- 11 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 diagramCavas/include/powerConnection.h create mode 100644 diagramCavas/include/powerEntity.h create mode 100644 diagramCavas/include/powerTerminal.h create mode 100644 diagramCavas/include/topologyManager.h create mode 100644 diagramCavas/source/powerConnection.cpp create mode 100644 diagramCavas/source/powerEntity.cpp create mode 100644 diagramCavas/source/powerTerminal.cpp create mode 100644 diagramCavas/source/topologyManager.cpp diff --git a/common/include/global.h b/common/include/global.h index 0c51088..580f6d6 100644 --- a/common/include/global.h +++ b/common/include/global.h @@ -207,6 +207,26 @@ struct propertyContentInfo //单个属性结构 QString proType; //类型 QWidget* proEditer = NULL; //编辑窗口对象 }; + +//==================组态图使用===================== +// 基础实体类型(电力元素或组态图) +enum class EntityType { + Grid, + Zone, + Station, + ConfigurationDiagram, + Transformer, + BusBar, + CircuitBreaker }; + +struct DiagramView { + QString diagramId; // 对应的PowerEntity ID + + // 元素位置信息 <元素ID, 位置> + QHash elementPositions; + //QHash connectionColors; // <连接ID, 显示颜色> + QHash> connectionPaths; // 自定义路径点 +}; //================================================== struct componentInfo diff --git a/diagramCavas/CMakeLists.txt b/diagramCavas/CMakeLists.txt index a06aca1..f0ecf94 100644 --- a/diagramCavas/CMakeLists.txt +++ b/diagramCavas/CMakeLists.txt @@ -10,6 +10,10 @@ set(DIAGRAMCAVAS_HEADER_FILES include/propertyContentDlg.h include/serializable.h include/statusBar.h + include/powerEntity.h + include/topologyManager.h + include/powerConnection.h + include/powerTerminal.h include/graphicsDataModel/baseModel.h include/graphicsDataModel/fixedPortsModel.h include/graphicsItem/electricConnectLineItem.h @@ -51,6 +55,10 @@ set(DIAGRAMCAVAS_SOURCE_FILES source/itemPropertyDlg.cpp source/propertyContentDlg.cpp source/statusBar.cpp + source/powerEntity.cpp + source/topologyManager.cpp + source/powerConnection.cpp + source/powerTerminal.cpp #source/serializable.cpp source/graphicsDataModel/baseModel.cpp source/graphicsDataModel/fixedPortsModel.cpp diff --git a/diagramCavas/include/powerConnection.h b/diagramCavas/include/powerConnection.h new file mode 100644 index 0000000..cd8b722 --- /dev/null +++ b/diagramCavas/include/powerConnection.h @@ -0,0 +1,30 @@ +#ifndef POWETCONNECTION_H +#define POWETCONNECTION_H +/**************************** + * 拓扑单元的连接线,表示连接关系 + * *************************/ +#include +#include + +// 连接线元数据(抽象连接关系) +class PowerConnection : public QObject { + Q_OBJECT +public: + PowerConnection(const QString& uuid,const QString& fromTerminalId,const QString& toTerminalId,QObject* parent = nullptr); + + QString id() const {return m_uuid;} + QString fromTerminalId() const { return m_fromTerminal; } + QString toTerminalId() const { return m_toTerminal; } + QVariantMap properties() const { return m_properties; } + + void setProperty(const QString& key, const QVariant& value); + + QJsonObject toJson() const; + +private: + QString m_uuid; + QString m_fromTerminal; + QString m_toTerminal; + QVariantMap m_properties; +}; +#endif //POWETCONNECTION_H diff --git a/diagramCavas/include/powerEntity.h b/diagramCavas/include/powerEntity.h new file mode 100644 index 0000000..a6ed2c5 --- /dev/null +++ b/diagramCavas/include/powerEntity.h @@ -0,0 +1,100 @@ +#ifndef POWERENTITY_H +#define POWERENTITY_H +/**************************** + * 电力实体类,实现拓扑层级的建立 grid-zone-station-diagram + * *************************/ +#include +#include +#include "global.h" + +class PowerTerminal; + +// 所有实体的基类(组合模式核心) +class PowerEntity :public QObject{ + Q_OBJECT +public: + PowerEntity(EntityType type, const QString& id, const QString& name) + : m_type(type), m_id(id), m_name(name) {} + + virtual ~PowerEntity() { + qDeleteAll(m_children); + } + + // 添加/删除子元素 + void addChild(PowerEntity* child) { + if (child == this || getAllDescendants().contains(this)) { + qCritical() << "Detected cyclic parent-child relationship!"; + return; + } + if (child && !m_children.contains(child)) { + m_children.append(child); + child->m_parent = this; + } + } + + void removeChild(PowerEntity* child) { + if (child && m_children.removeOne(child)) { + child->m_parent = nullptr; + } + } + + // 获取属性 + EntityType type() const { return m_type; } + QString id() const { return m_id; } + QString name() const { return m_name; } + QList children() const { return m_children; } + PowerEntity* parent() const { return m_parent; } + + // 递归查找 + QList getAllDescendants() const { + QList descendants; + for (PowerEntity* child : m_children) { + descendants.append(child); + descendants.append(child->getAllDescendants()); + } + return descendants; + } + + virtual QJsonObject toJson() const; +public: + // 接线点管理 + void addTerminal(PowerTerminal* terminal); + void removeTerminal(const QString& terminalId); + QList terminals() const { return m_terminals; } + PowerTerminal* findTerminal(const QString& terminalId) const; +signals: + void terminalAdded(PowerTerminal* terminal); + void terminalRemoved(const QString& terminalId); +protected: + QList m_terminals; +private: + EntityType m_type; + QString m_id; // 唯一标识符(可用UUID生成) + QString m_name; + PowerEntity* m_parent = nullptr; + QList m_children; +}; + +// 组态图特殊属性(继承自PowerEntity) +class ConfigurationDiagram : public PowerEntity { +public: + ConfigurationDiagram(const QString& id, const QString& name) + : PowerEntity(EntityType::ConfigurationDiagram, id, name) {} + + // 可扩展图特有属性(如版本、创建时间等) +}; + +//电网区域划分 grid-zone-station +class PowerDivision : public PowerEntity { +public: + PowerDivision(EntityType type,const QString& id, const QString& name) + : PowerEntity(type, id, name) {} +}; + +//电力元件(拓扑) +class PowerComponent : public PowerEntity { +public: + PowerComponent(EntityType type,const QString& id, const QString& name) + : PowerEntity(type, id, name) {} +}; +#endif diff --git a/diagramCavas/include/powerTerminal.h b/diagramCavas/include/powerTerminal.h new file mode 100644 index 0000000..91ce230 --- /dev/null +++ b/diagramCavas/include/powerTerminal.h @@ -0,0 +1,52 @@ +#ifndef POWERTERMINAL_H +#define POWERTERMINAL_H +/**************************** + * 拓扑元件的接线口,拓扑关系的精确表示 + * *************************/ +#include +#include +#include +#include + +enum class TerminalType { + PowerInput, + PowerOutput, + ControlSignal, + ProtectiveGround +}; + +class PowerTerminal : public QObject { + Q_OBJECT +public: + explicit PowerTerminal(const QString& parentEntityId, + TerminalType type, + const QString& name, + const QPointF& relativePos = QPointF(), + QObject* parent = nullptr); + + // 属性访问 + void setId(const QString& sId){m_id = sId;} + QString id() const { return m_id; } + QString parentEntityId() const { return m_parentEntityId; } + TerminalType type() const { return m_type; } + QString name() const { return m_name; } + QPointF relativePosition() const { return m_relativePosition; } + + // 设置相对位置 + void setRelativePosition(const QPointF& newPos); + + // 序列化 + QJsonObject toJson() const; + static PowerTerminal* fromJson(const QJsonObject& json, QObject* parent = nullptr); + +signals: + void positionChanged(const QPointF& newPosition); + +private: + QString m_id; + const QString m_parentEntityId; + const TerminalType m_type; + QString m_name; + QPointF m_relativePosition; +}; +#endif //POWERTERMINAL_H diff --git a/diagramCavas/include/topologyManager.h b/diagramCavas/include/topologyManager.h new file mode 100644 index 0000000..8b92b71 --- /dev/null +++ b/diagramCavas/include/topologyManager.h @@ -0,0 +1,74 @@ +#ifndef TOPOLOGYMANAGER_H +#define TOPOLOGYMANAGER_H +/**************************** + * 拓扑关系管理类 + * *************************/ +#include +#include +#include "powerConnection.h" +#include "powerTerminal.h" +#include "global.h" + +class PowerEntity; + +class TopologyManager : public QObject { + Q_OBJECT +public: + static TopologyManager& instance(); + + // 实体管理 + PowerEntity* createEntity(EntityType type,const QString& uuid,const QString& name); + PowerEntity* findEntity(const QString& id) const; + bool deleteEntity(const QString& id); + + // 序列化 + QJsonObject serialize() const; + void deserialize(const QJsonObject& json); + + // 连接管理 + PowerConnection* createConnection(const QString& uuid,const QString& fromId, const QString& toId); + QList getConnectionsForElement(const QString& elementId) const; + void removeConnection(const QString& connId); + + // 连接查询接口 + QList connectionsFrom(const QString& elementId) const; + QList connectionsTo(const QString& elementId) const; + QList getConnectionsFor(const QString& entityId) const; + + void saveToDB(const QString& path); + void loadFromDB(const QString& path); + + PowerEntity* getEntity(const QString& id) const; + QList findEntitiesByName(const QString& name) const; + +public: + // 接线点管理 + PowerTerminal* createTerminal(const QString& parentEntityId, + TerminalType type, + const QString& name, + const QPointF& relPos = QPointF()); + bool deleteTerminal(const QString& terminalId); + PowerTerminal* getTerminal(const QString& terminalId) const; + QList getTerminalsForEntity(const QString& entityId) const; +signals: + void entityCreated(const QString&); + void entityDeleted(const QString&); + void connectionCreated(const QString&); + void connectionRemoved(const QString&); + +private: + explicit TopologyManager(QObject* parent = nullptr); + ~TopologyManager(); + void clearAllData(); + QHash m_entities; // ID到实体映射 + QHash m_views; // 组态图视图存储 + + // 连接存储 + QHash m_connections; + QMultiHash m_connectionIndex; // 元素ID到连接的映射 +private: + QHash m_allTerminals; // ID到接线点映射 + QHash> m_terminalsByEntity; // 实体ID到接线点列表 +}; + +#endif diff --git a/diagramCavas/source/powerConnection.cpp b/diagramCavas/source/powerConnection.cpp new file mode 100644 index 0000000..d54c976 --- /dev/null +++ b/diagramCavas/source/powerConnection.cpp @@ -0,0 +1,13 @@ +#include +#include "powerConnection.h" + +PowerConnection::PowerConnection(const QString& uuid,const QString& fromTerminal, const QString& toTerminal, QObject* parent) + : QObject(parent),m_uuid(uuid), m_fromTerminal(fromTerminal), m_toTerminal(toTerminal) {} + +QJsonObject PowerConnection::toJson() const { + QJsonObject obj; + obj["id"] = m_uuid; + obj["from"] = m_fromTerminal; + obj["to"] = m_toTerminal; + return obj; +} diff --git a/diagramCavas/source/powerEntity.cpp b/diagramCavas/source/powerEntity.cpp new file mode 100644 index 0000000..0793461 --- /dev/null +++ b/diagramCavas/source/powerEntity.cpp @@ -0,0 +1,43 @@ +#include +#include +#include "powerEntity.h" +#include "powerTerminal.h" + +QJsonObject PowerEntity::toJson() const { + QJsonObject obj; + obj["id"] = m_id; + obj["type"] = static_cast(m_type); + obj["name"] = m_name; + + QJsonArray childrenArray; + for (auto child : m_children) + childrenArray.append(child->id()); + obj["children"] = childrenArray; + + return obj; +} + +void PowerEntity::addTerminal(PowerTerminal* terminal) { + if (terminal && terminal->parentEntityId() == m_id) { + m_terminals.append(terminal); + terminal->setParent(this); + emit terminalAdded(terminal); + } +} + +void PowerEntity::removeTerminal(const QString& terminalId) { + auto it = std::find_if(m_terminals.begin(), m_terminals.end(), + [terminalId](PowerTerminal* t) { return t->id() == terminalId; }); + if (it != m_terminals.end()) { + PowerTerminal* term = *it; + m_terminals.erase(it); + term->deleteLater(); + emit terminalRemoved(terminalId); + } +} + +PowerTerminal* PowerEntity::findTerminal(const QString& terminalId) const { + auto it = std::find_if(m_terminals.begin(), m_terminals.end(), + [terminalId](PowerTerminal* t) { return t->id() == terminalId; }); + return (it != m_terminals.end()) ? *it : nullptr; +} diff --git a/diagramCavas/source/powerTerminal.cpp b/diagramCavas/source/powerTerminal.cpp new file mode 100644 index 0000000..6a5c1ca --- /dev/null +++ b/diagramCavas/source/powerTerminal.cpp @@ -0,0 +1,44 @@ +#include "powerTerminal.h" + +PowerTerminal::PowerTerminal(const QString& parentEntityId, + TerminalType type, + const QString& name, + const QPointF& relativePos, + QObject* parent) + : QObject(parent), + m_id(QUuid::createUuid().toString()), + m_parentEntityId(parentEntityId), + m_type(type), + m_name(name), + m_relativePosition(relativePos) {} + +void PowerTerminal::setRelativePosition(const QPointF& newPos) { + if (m_relativePosition != newPos) { + m_relativePosition = newPos; + emit positionChanged(newPos); + } +} + +QJsonObject PowerTerminal::toJson() const { + QJsonObject obj; + obj["id"] = m_id; + obj["parentEntity"] = m_parentEntityId; + obj["type"] = static_cast(m_type); + obj["name"] = m_name; + obj["relX"] = m_relativePosition.x(); + obj["relY"] = m_relativePosition.y(); + return obj; +} + +PowerTerminal* PowerTerminal::fromJson(const QJsonObject& json, QObject* parent) { + QString id = json["id"].toString(); + QString parentId = json["parentEntity"].toString(); + TerminalType type = static_cast(json["type"].toInt()); + QString name = json["name"].toString(); + qreal x = json["relX"].toDouble(); + qreal y = json["relY"].toDouble(); + + PowerTerminal* term = new PowerTerminal(parentId, type, name, QPointF(x, y), parent); + term->m_id = id; // 注意:需要修改m_id为可写,或使用其他机制保持ID一致 + return term; +} diff --git a/diagramCavas/source/topologyManager.cpp b/diagramCavas/source/topologyManager.cpp new file mode 100644 index 0000000..2e9eadf --- /dev/null +++ b/diagramCavas/source/topologyManager.cpp @@ -0,0 +1,298 @@ +#include +#include +#include "topologyManager.h" +#include "powerEntity.h" + +TopologyManager& TopologyManager::instance() +{ + static TopologyManager instance; + return instance; +} + +TopologyManager::TopologyManager(QObject* parent) + : QObject(parent) {} + +TopologyManager::~TopologyManager() { + clearAllData(); +} + +void TopologyManager::clearAllData() +{ + // 删除所有连接 + qDeleteAll(m_connections); + m_connections.clear(); + m_connectionIndex.clear(); + + // 删除所有实体(自动删除子对象) + qDeleteAll(m_entities); + m_entities.clear(); +} + +PowerEntity* TopologyManager::createEntity(EntityType type,const QString& uuid, const QString& name) +{ + PowerEntity* entity = nullptr; + switch(type) { + case EntityType::ConfigurationDiagram: + entity = new ConfigurationDiagram(uuid,name); + break; + case EntityType::Grid: + case EntityType::Zone: + case EntityType::Station: + entity = new PowerDivision(type, uuid,name); + default: + entity = new PowerComponent(type, uuid,name); + } + + m_entities.insert(entity->id(), entity); + emit entityCreated(entity->id()); // 发送信号通知 + return entity; +} + +PowerEntity* TopologyManager::findEntity(const QString& id) const +{ + return m_entities.value(id, nullptr); // 避免异常的安全查询 +} + +bool TopologyManager::deleteEntity(const QString& id) +{ + if (!m_entities.contains(id)) return false; + + PowerEntity* entity = m_entities[id]; + + // 步骤1:删除所有相关连接 + auto relatedConns = m_connectionIndex.values(id); + for (auto conn : relatedConns) { + removeConnection(conn->id()); + } + + // 步骤2:从父节点移除(防止悬空指针) + if (PowerEntity* parent = entity->parent()) { + parent->removeChild(entity); + } + + // 步骤3:递归删除子实体 + auto children = entity->children(); + for (auto child : children) { + deleteEntity(child->id()); // 递归删除 + } + + // 步骤4:从哈希表移除并释放内存 + m_entities.remove(id); + delete entity; // 触发PowerEntity析构函数 + + emit entityDeleted(id); + return true; +} + + +PowerConnection* TopologyManager::createConnection(const QString& connId,const QString& fromId, const QString& toId) +{ + // 验证有效性 + if (!m_entities.contains(fromId) || + !m_entities.contains(toId) || + fromId == toId) + { + qWarning() << "Invalid connection endpoints"; + return nullptr; + } + + // 防止重复连接 + foreach (auto conn, m_connections) { + if (conn->fromTerminalId() == fromId && + conn->toTerminalId() == toId) + { + return conn; // 返回已存在的连接 + } + } + + // 创建新连接 + PowerConnection* conn = new PowerConnection(connId,fromId, toId); + m_connections[connId] = conn; + + // 更新索引 + m_connectionIndex.insert(fromId, conn); + m_connectionIndex.insert(toId, conn); + + emit connectionCreated(connId); + return conn; +} + +QList TopologyManager::getConnectionsForElement(const QString& elementId) const +{ + return m_connectionIndex.values(elementId); +} + +void TopologyManager::removeConnection(const QString& connId) +{ + if (!m_connections.contains(connId)) return; + + PowerConnection* conn = m_connections[connId]; + + // 更新索引 + m_connectionIndex.remove(conn->fromTerminalId(), conn); + m_connectionIndex.remove(conn->toTerminalId(), conn); + + // 清理内存 + m_connections.remove(connId); + delete conn; + + emit connectionRemoved(connId); +} + +// 连接查询接口 +QList TopologyManager::connectionsFrom(const QString& elementId) const +{ + QList res; + QList lst = m_connectionIndex.values(elementId); + for(auto &val:lst) + { + if(val->fromTerminalId() == elementId) + res.append(val); + } + return res; +} + +QList TopologyManager::connectionsTo(const QString& elementId) const +{ + QList res; + QList lst = m_connectionIndex.values(elementId); + for(auto &val:lst) + { + if(val->toTerminalId() == elementId) + res.append(val); + } + return res; +} + +QList TopologyManager::getConnectionsFor(const QString& entityId) const +{ + return m_connectionIndex.values(entityId); +} + +void TopologyManager::saveToDB(const QString& path) +{ + QJsonObject root; + + QJsonArray entitiesArray; + for (auto entity : m_entities) + entitiesArray.append(entity->toJson()); + root["entities"] = entitiesArray; + + QJsonArray connectionsArray; + for (auto conn : m_connections) + connectionsArray.append(conn->toJson()); + root["connections"] = connectionsArray; + + //todo:写入到数据库 +} + +void TopologyManager::loadFromDB(const QString& path) +{ + //todo::将读到的字为json + QString strJson; + QJsonDocument doc = QJsonDocument::fromJson(strJson.toLocal8Bit()); + QJsonObject root = doc.object(); + + clearAllData(); // 清除现有数据 + + // 阶段1:创建所有实体 + QHash pendingChildren; + + QJsonArray entities = root["entities"].toArray(); + foreach (QJsonValue entVal, entities) { + QJsonObject entObj = entVal.toObject(); + + // 创建实体 + EntityType type = static_cast(entObj["type"].toInt()); + QString id = entObj["id"].toString(); + QString name = entObj["name"].toString(); + + PowerEntity* entity = createEntity(type, id, name); + + // 记录待处理的子关系 + pendingChildren[id] = entObj["children"].toVariant().toStringList(); + } + + // 阶段2:建立父子关系 + QHashIterator it(pendingChildren); + while (it.hasNext()) { + it.next(); + PowerEntity* parent = getEntity(it.key()); + if (!parent) continue; + + foreach (QString childId, it.value()) { + if (PowerEntity* child = getEntity(childId)) { + parent->addChild(child); + } + } + } + + // 阶段3:创建连接 + QJsonArray connections = root["connections"].toArray(); + foreach (QJsonValue connVal, connections) { + QJsonObject connObj = connVal.toObject(); + createConnection( + connObj["id"].toString(), + connObj["from"].toString(), + connObj["to"].toString() + ); + } +} + +PowerEntity* TopologyManager::getEntity(const QString& id) const +{ + auto it = m_entities.find(id); + return (it != m_entities.end()) ? it.value() : nullptr; +} + +QList TopologyManager::findEntitiesByName(const QString& name) const +{ + QList results; + foreach (auto entity, m_entities) { + if (entity->name() == name) { + results.append(entity); + } + } + return results; +} + +PowerTerminal* TopologyManager::createTerminal(const QString& parentEntityId, + TerminalType type, + const QString& name, + const QPointF& relPos) { + if (!m_entities.contains(parentEntityId)) return nullptr; + + PowerTerminal* term = new PowerTerminal(parentEntityId, type, name, relPos); + m_allTerminals[term->id()] = term; + m_terminalsByEntity[parentEntityId].append(term); + + // 关联到父实体 + if (PowerEntity* parent = getEntity(parentEntityId)) { + parent->addTerminal(term); + } + + return term; +} + +bool TopologyManager::deleteTerminal(const QString& terminalId) { + if (!m_allTerminals.contains(terminalId)) return false; + + PowerTerminal* term = m_allTerminals[terminalId]; + QString parentId = term->parentEntityId(); + + // 从父实体移除 + if (PowerEntity* parent = getEntity(parentId)) { + parent->removeTerminal(terminalId); + } + + // 清理全局存储 + m_terminalsByEntity[parentId].removeAll(term); + m_allTerminals.remove(terminalId); + //delete term; //在parent中已经delete + + return true; +} + +QList TopologyManager::getTerminalsForEntity(const QString& entityId) const { + return m_terminalsByEntity.value(entityId); +} diff --git a/diagramUtils/source/logger.cpp b/diagramUtils/source/logger.cpp index d10d027..9b9c8e8 100644 --- a/diagramUtils/source/logger.cpp +++ b/diagramUtils/source/logger.cpp @@ -37,7 +37,7 @@ void Logger::initialize() void Logger::loadConfig(/*const QString& configFilePath*/) { //QString filePath = Settings::instance().value("Log", "logFile").toString(); - QString filePath = QApplication::applicationDirPath(); + QString filePath = QCoreApplication::applicationDirPath() + "/log/app.log"; setLogFile(filePath); /*QString strLevel = Settings::instance().value("Log", "level").toString().toUpper();