469 lines
16 KiB
C++
469 lines
16 KiB
C++
#include "topologyView.h"
|
||
#include "ui_topologyView.h"
|
||
#include "tools.h"
|
||
#include "topologyTree.h"
|
||
#include "dataBase.h"
|
||
#include "basePropertyManager.h"
|
||
#include "baseProperty.h"
|
||
#include "structDataSource.h"
|
||
#include "extraPropertyManager.h"
|
||
#include <QStandardItemModel>
|
||
#include <QMenu>
|
||
#include <QUuid>
|
||
|
||
TopologyView::TopologyView(QWidget *parent)
|
||
: QDialog(parent)
|
||
, ui(new Ui::topologyView)
|
||
,_treeModel(nullptr)
|
||
,_treeView(nullptr)
|
||
,_pExtraProManager(nullptr)
|
||
{
|
||
ui->setupUi(this);
|
||
//setWindowFlags(windowFlags() | Qt::WindowMinMaxButtonsHint&Qt::WindowCloseButtonHint);
|
||
_treeModel = new QStandardItemModel(this);
|
||
_treeView = new TopologyTree(this);
|
||
ui->verticalLayout->addWidget(_treeView);
|
||
_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||
|
||
}
|
||
|
||
TopologyView::~TopologyView()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
void TopologyView::initial()
|
||
{
|
||
connect(_treeView, &QTreeView::clicked, this, &TopologyView::onItemClicked);
|
||
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);
|
||
// 设置模型的列数
|
||
_treeModel->setColumnCount(1);
|
||
|
||
// 创建树视图
|
||
_treeView->setModel(_treeModel);
|
||
|
||
// 展开所有节点
|
||
_treeView->expandAll();
|
||
// 显示树视图
|
||
_treeView->setWindowTitle(QObject::tr("拓扑树"));
|
||
|
||
loadTopologyFromDB();
|
||
}
|
||
|
||
void TopologyView::loadTopologyFromDB()
|
||
{
|
||
if(_pExtraProManager)
|
||
{
|
||
//clearItems();
|
||
auto& mapExtra = m_dataSource->allProperties;
|
||
/*QStandardItem* root = _treeModel->invisibleRootItem();
|
||
for(auto& pro:mapExtra){
|
||
QStandardItem* propertyItem = new QStandardItem();
|
||
addItemToView(pro,"name",root,propertyItem);
|
||
}*/
|
||
QVector<ExtraProperty> vec = QVector<ExtraProperty>::fromList(mapExtra.values());
|
||
buildTreeStructure(_treeModel,vec);
|
||
|
||
_treeView->expandAll();
|
||
}
|
||
}
|
||
|
||
void TopologyView::onItemChanged(QStandardItem *item)
|
||
{
|
||
int nLevel = getLevel(item);
|
||
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 entityChange(info);
|
||
}
|
||
|
||
void TopologyView::onItemClicked(const QModelIndex &index)
|
||
{
|
||
QStandardItem* item = _treeModel->itemFromIndex(index);
|
||
if(item)
|
||
{
|
||
EntityType type = EntityType(item->data(Qt::UserRole+2).toInt());
|
||
if(type == EntityType::ConfigurationDiagram)
|
||
{
|
||
EntityInfo info;
|
||
info.eType = EntityType::ConfigurationDiagram;
|
||
info.sName = item->text();
|
||
info.sUuid = item->data(Qt::UserRole+1).toString();
|
||
info.sParentId = item->parent()->data(Qt::UserRole+1).toString();
|
||
emit entitySelected(info);
|
||
}
|
||
}
|
||
}
|
||
|
||
void TopologyView::onUpdateTopology(QList<RelationItem> 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 = "未知电压等级"; // 默认值
|
||
}
|
||
|
||
// 查找或创建电压层级节点
|
||
QStandardItem* pVoltageItem = findOrCreateVoltageLevel(voltageLevel);
|
||
|
||
// 创建间隔节点
|
||
QStandardItem* pBayItem = createBayItem(voltageLevel, curItem);
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 展开所有节点
|
||
_treeView->expandAll();
|
||
}
|
||
|
||
void TopologyView::clearItems()
|
||
{
|
||
if(_treeModel){
|
||
QStandardItem *root = _treeModel->invisibleRootItem(); //先清空model
|
||
int rowCount = root->rowCount();
|
||
if (rowCount > 0) {
|
||
_treeModel->removeRows(0, rowCount);
|
||
}
|
||
}
|
||
}
|
||
|
||
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<ExtraProperty>& properties) {
|
||
// 清空模型
|
||
model->clear();
|
||
|
||
// 创建根节点
|
||
//QStandardItem* root = new QStandardItem("拓扑结构");
|
||
//model->appendRow(root);
|
||
QStandardItem* root = _treeModel->invisibleRootItem();
|
||
// 存储节点映射:路径 -> 节点
|
||
QMap<QString, QStandardItem*> 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<ExtraProperty>());
|
||
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<ExtraProperty>());
|
||
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<ExtraProperty> nodeProperties = targetNodeData["properties"].value<QVector<ExtraProperty>>();
|
||
|
||
// 检查属性是否已存在
|
||
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<ExtraProperty> 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<QVector<ExtraProperty>>();
|
||
}
|
||
|
||
return QVector<ExtraProperty>();
|
||
}
|
||
|
||
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);
|
||
}
|
||
|