#include #include #include "diagramEditor/diagramEditorBayDetailSettingDlg.h" #include "diagramEditor/diagramEditorBayDetailAddDlg.h" #include "diagramEditor/diagramEditorBayPreviewDlg.h" #include "ui_diagramEditorBayDetailSettingDlg.h" #include "diagramEditor/diagramEditorBaseBlock.h" #include "graphicsDataModel/diagramEditorModel.h" #include "include/instance/baseTypeManager.h" #include "diagramEditor/diagramEditorStructContainer.h" #include "diagramEditor/editPanel.h" #include "topologyManager.h" #include #include "titleBar.h" #include DiagramEditorBayDetailSettingDlg::DiagramEditorBayDetailSettingDlg(QWidget *parent,DiagramEditorModel* pModel) : QDialog(parent) , ui(new Ui::diagramEditorBayDetailSettingDlg) ,_pAddDlg(nullptr) ,_curOperateObj(nullptr) ,_compoModel(nullptr) ,_routeModel(nullptr) ,_pPreviewDlg(nullptr) ,_pModel(pModel) ,_pWizard(nullptr) ,_pSizeGrip(nullptr) { ui->setupUi(this); this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); this->setWindowModality(Qt::WindowModal); setStyleSheet("background-color: white;"); initial(); } DiagramEditorBayDetailSettingDlg::~DiagramEditorBayDetailSettingDlg() { delete ui; } void DiagramEditorBayDetailSettingDlg::initial() { m_titleBar = new TitleBar(this); m_titleBar->setTitle("间隔详细设置"); ui->verticalLayout_2->insertWidget(0,m_titleBar); _pSizeGrip = new QSizeGrip(this); _pSizeGrip->setFixedSize(12, 12); _compoModel = new QStandardItemModel(this); _routeModel = new QStandardItemModel(this); _routeModel->setHorizontalHeaderLabels({"线路名", "父线路","包含设备"}); ui->tableView->setModel(_routeModel); QHeaderView *header = ui->tableView->horizontalHeader(); ui->tableView->setColumnWidth(0, 40); ui->tableView->setColumnWidth(1, 40); header->setStretchLastSection(true); 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->tableView, &QTableView::customContextMenuRequested, this, &DiagramEditorBayDetailSettingDlg::onRouteRbtnClicked); ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->verticalHeader()->setVisible(false); ui->cb_layout->addItem("纵向",0); ui->cb_layout->addItem("横向",1); ui->cb_locate->addItem("上",0); ui->cb_locate->addItem("下",3); 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() { if(_curOperateObj){ _compoModel->clear(); _compoModel->setColumnCount(5); _compoModel->setHorizontalHeaderLabels({"分类", "名称", "类型", "关联对象", "引用线路"}); auto mapComponent = _curOperateObj->getBayInfo().mapComponent; for(auto& comp:mapComponent){ DiagramEditorComponentInfo info = comp; QStandardItem *itemCate = new QStandardItem(); QStandardItem *itemName = new QStandardItem(); QStandardItem *itemType = new QStandardItem(); QStandardItem *itemObj = new QStandardItem(); QStandardItem *itemRoute = new QStandardItem(); QString sCategory; QString sType; if(info.nCategory == 0){ sCategory = "电气设备"; sType = BaseTypeManager::getInstance()->getNameById(info.nType); } else if(info.nCategory == 1){ sCategory = "连接关系"; if(info.nType == 0){ //连接点暂时写死 sType = "连接点"; } } int nBaseType = BaseTypeManager::getInstance()->getBaseTypeById(info.nType); itemCate->setText(sCategory); itemCate->setData(info.nCategory); itemName->setText(info.sName); itemName->setData(info.nUsedDirection); itemName->setData(info.deltaPos,Qt::UserRole+2); itemName->setData(info.uid,Qt::UserRole+3); itemName->setData(info.nFlag,Qt::UserRole+4); itemName->setData(info.nRotate,Qt::UserRole+5); itemType->setText(sType); itemType->setData(info.nType); itemType->setData(nBaseType,Qt::UserRole+2); itemObj->setText(info.sBindObj); itemObj->setData(info.nBindType); itemObj->setData(info.nBindPara,Qt::UserRole+2); itemObj->setData(info.sBindParent,Qt::UserRole+3); itemRoute->setText(info.sUsedRoute.join("、")); QList lstItems; lstItems<appendRow(lstItems); } _routeModel->clear(); _routeModel->setColumnCount(3); _routeModel->setHorizontalHeaderLabels({"线路名","父线路","包含设备"}); auto info = _curOperateObj->getBayInfo(); if(info.nLayout == 0) //纵向 ui->cb_layout->setCurrentIndex(0); else ui->cb_layout->setCurrentIndex(1); setBayInfo(info); auto mapRoute = info.mapRoute; //更新路径数据到本界面 for(auto& route:mapRoute){ QString sRoute = route.sRouteName; if(sRoute.isEmpty()) continue; QStringList lstComp; for(auto& comp:route.lstCompo){ lstComp.append(comp.sName); } QStandardItem *itemRoute = new QStandardItem(); QStandardItem *itemParent = new QStandardItem(); QStandardItem *itemComponents = new QStandardItem(); itemRoute->setText(sRoute); itemRoute->setData(route.bMainRoute); itemParent->setText(route.sParentRoute); itemComponents->setText(lstComp.join(",")); QList lstItems; lstItems<appendRow(lstItems); } } } void DiagramEditorBayDetailSettingDlg::showDlg(DiagramEditorBayBlock* p) { show(); _curOperateObj = p; if(p->getBayType() == BayType::busSectionBay) //分段间隔默认水平 ui->cb_layout->setCurrentIndex(1); else ui->cb_layout->setCurrentIndex(0); if(p->getBayLocate() == 0) ui->cb_locate->setCurrentIndex(0); else ui->cb_locate->setCurrentIndex(1); m_titleBar->setCenterText(p->getName()); refreshModel(); } void DiagramEditorBayDetailSettingDlg::onAddClicked() { if(_pAddDlg == nullptr){ _pAddDlg = new DiagramEditorBayDetailAddDlg(this); _pAddDlg->setParent(this); } _pAddDlg->showDlg(); } void DiagramEditorBayDetailSettingDlg::onOkClicked() { //将ui设置的参数更新到对应block bool changePos = false; if(_curOperateObj){ QMap tempComponents; int nRowCount = _compoModel->rowCount(); for (int i = 0; i < nRowCount; ++i) { QStandardItem *itemCate = _compoModel->item(i, 0); QStandardItem *itemName = _compoModel->item(i, 1); QStandardItem *itemType = _compoModel->item(i, 2); QStandardItem *itemBind = _compoModel->item(i, 3); QStandardItem *itemRoute = _compoModel->item(i, 4); DiagramEditorComponentInfo info; // ✅ 必须恢复的字段(原代码中有) int nDir = itemName->data(Qt::UserRole+1).toInt(); QPoint deltaPos = itemName->data(Qt::UserRole+2).toPoint(); int nVal = itemName->data(Qt::UserRole+4).toInt(); int nRotate = itemName->data(Qt::UserRole+5).toInt(); info.sName = itemName->text(); info.uid = itemName->data(Qt::UserRole+3).toUuid(); if(itemCate->text() == "电气设备"){ info.nCategory = 0; } else if(itemCate->text() == "连接关系"){ info.nCategory = 1; } info.nType = itemType->data().toInt(); info.sBindObj = itemBind->text(); info.nBindType = itemBind->data().toInt(); info.nBindPara = itemBind->data(Qt::UserRole+2).toInt(); info.sBindParent = itemBind->data(Qt::UserRole+3).toString(); info.sUsedRoute = itemRoute->text().split(","); // ✅ 关键修复:恢复被丢弃的状态 info.nUsedDirection = nDir; info.deltaPos = deltaPos; info.nFlag = nVal; info.nRotate = nRotate; tempComponents.insert(info.sName, info); } // ✅ 2. 设置布局参数 int nLayout = ui->cb_layout->currentData().toInt(); _curBayInfo.nLayout = nLayout; _curBayInfo.mapComponent = tempComponents; // ✅ 仅存非布局数据 int nLocate = ui->cb_locate->currentData().toInt(); if(_curBayInfo.nLocate != nLocate){ //位置发生变动 _curOperateObj->getCurContainer()->changeBlockLocate(_curOperateObj,_curBayInfo.nLocate,nLocate); _curBayInfo.nLocate = nLocate; _curOperateObj->setBayLocate(nLocate); //emit _pWizard->wizardFinish(); changePos = true; } // ✅ 3. 执行布局(唯一正确时机) int nDir = (nLayout == 0) ? 41 : 14; getModel()->clearCompoDir( _curBayInfo.mapRoute, _curBayInfo.mapComponent, _curBayInfo.directionOccupancyMap, _curBayInfo.routeDirectionMap, 0); QRectF recBounding = getModel()->updateTarget( _curBayInfo.mapRoute, _curBayInfo.mapComponent, _curBayInfo.directionOccupancyMap, _curBayInfo.routeDirectionMap, nDir, 0, false); // ✅ 结果写回 mapComponent // ✅ 4. 保存“已经算好的正确数据” if (_curOperateObj->getRecSize().isEmpty()) _curOperateObj->setRecSize(recBounding); _curOperateObj->setBayInfo(_curBayInfo); // ✅ 此时 mapComponent 是正确的 TopologyManager::instance().clearGlobalBlockData(_curOperateObj->getName()); TopologyManager::instance().moveTempBlockData(); _curOperateObj->setEditState(true); _curOperateObj = nullptr; } hide(); if(changePos){ _pModel->getPanel()->initByWizardInfo(); } QTimer::singleShot(300, this, [this]() { _pModel->clearCurPreview(); //关闭时清除预览Item _pModel->generatePreview(); _pModel->calculateBlockPos(); _pModel->setItemInBlockPos(); _pModel->refreshConnection(); }); } void DiagramEditorBayDetailSettingDlg::onCancelClicked() { _pModel->clearCurPreview(); hide(); } void DiagramEditorBayDetailSettingDlg::onRouteDeleteClicked() { // 获取当前选中的索引 QModelIndexList selectedIndexes = ui->tableView->selectionModel()->selectedRows(); if (selectedIndexes.isEmpty()) { return; // 没有选中任何行 } // 获取行号并排序(从大到小删除避免索引变化) QList rowsToRemove; foreach (const QModelIndex &index, selectedIndexes) { rowsToRemove.append(index.row()); } // 获取当前选中的第一项索引 QModelIndex index = selectedIndexes.first(); if (!index.isValid()) { return; } QModelIndex indexName = index.sibling(index.row(),0); QString sName = indexName.data().toString(); // 移除行 foreach (int row, rowsToRemove) { QList rowItems; for (int col = 0; col < _routeModel->columnCount(); ++col) { QStandardItem *item = _routeModel->takeItem(row, col); rowItems.append(item); } qDeleteAll(rowItems); //take的item不释放 _routeModel->removeRow(row); } onRouteModified(_curBayInfo.mapRoute,_curBayInfo.routeOrder,sName,true); auto info = _curBayInfo.mapRoute.value(sName); QStringList lst; for(auto &compo:info.lstCompo){ lst.append(compo.sName); } removeRouteUsageFromDevices(lst,sName); _curBayInfo.mapRoute.remove(sName); //同步移除数据 _curBayInfo.routeOrder.removeAll(sName); //移除排序 _pModel->removeRouteDir(sName,_curBayInfo.mapComponent,_curBayInfo.directionOccupancyMap,_curBayInfo.routeDirectionMap,0); for(int i = 0;i < _routeModel->rowCount();++i){ //重新加载所有父路线 QStandardItem *itemName = _routeModel->item(i, 0); for(auto& route:_curBayInfo.mapRoute){ if(itemName->text() == route.sRouteName){ QStandardItem *itemParnet = _routeModel->item(i, 1); itemParnet->setText(route.sParentRoute); continue; } } } _pModel->clearCurPreview(); showPreview(); } void DiagramEditorBayDetailSettingDlg::onRouteRbtnClicked(const QPoint &pos) { QModelIndex index = ui->tableView->indexAt(pos); if (!index.isValid()) { return; // 如果点击的是空白区域,直接返回 } QMenu menu; QAction *deleteAction = new QAction("删除", this); QAction *modifyAction = new QAction("修改", this); menu.addAction(deleteAction); menu.addAction(modifyAction); // 连接删除菜单项的触发信号与槽函数 connect(deleteAction, &QAction::triggered, this, &DiagramEditorBayDetailSettingDlg::onRouteDeleteClicked); //连接修改 connect(modifyAction, &QAction::triggered, this, &DiagramEditorBayDetailSettingDlg::onRouteEditClicked); // 在点击位置显示菜单 menu.exec(ui->tableView->mapToGlobal(pos)); } void DiagramEditorBayDetailSettingDlg::onRouteEditClicked() { if(_pAddDlg == nullptr){ _pAddDlg = new DiagramEditorBayDetailAddDlg(this); _pAddDlg->setParent(this); } // 获取当前选中的索引 QModelIndexList selectedIndexes = ui->tableView->selectionModel()->selectedRows(); if (selectedIndexes.isEmpty()) { return; // 没有选中任何行 } // 获取当前选中的第一项索引 QModelIndex index = selectedIndexes.first(); if (!index.isValid()) { return; } QModelIndex indexName = index.sibling(index.row(),0); QString sName = indexName.data().toString(); auto routeInfo = _curBayInfo.mapRoute.value(sName); _pAddDlg->showDlg(routeInfo); } void DiagramEditorBayDetailSettingDlg::showPreview() { int nLayout = ui->cb_layout->currentData().toInt(); _pPreviewDlg->showDlg(nLayout); QRectF recContainAll = _pModel->generateTempBay(_curOperateObj); if(_curOperateObj){ _curOperateObj->setRecSize(recContainAll); } } QString DiagramEditorBayDetailSettingDlg::calculateParent(const QMap& mapRoute,const QList& routeOrder,DiagramEditorRouteInfo& cur) { int curIndex = routeOrder.indexOf(cur.sRouteName); for (int i = 0; i < curIndex; ++i) { const QString& otherName = routeOrder.at(i); const DiagramEditorRouteInfo& other = mapRoute.value(otherName); if (shareComponent(other, cur)) { return otherName; } } return QString(); } void DiagramEditorBayDetailSettingDlg::markAffectedRoutes(const QMap& mapRoute,const QList& routeOrder, const QString& routeName,QSet& affected) { if (affected.contains(routeName)) return; affected.insert(routeName); int idx = routeOrder.indexOf(routeName); for (int i = idx + 1; i < routeOrder.size(); ++i) { const QString& otherName = routeOrder.at(i); const auto& other = mapRoute.value(otherName); if (shareComponent(other, mapRoute.value(routeName))) { markAffectedRoutes(mapRoute, routeOrder, otherName, affected); } } } void DiagramEditorBayDetailSettingDlg::onRouteModified(QMap& mapRoute,QList& routeOrder,const QString& modifiedRoute,bool onlyClear) { QSet affected; markAffectedRoutes(mapRoute, routeOrder, modifiedRoute, affected); for (const auto& name : affected) { auto& route = mapRoute[name]; route.sParentRoute.clear(); if(onlyClear) continue; route.sParentRoute = calculateParent(mapRoute, routeOrder, route); } } void DiagramEditorBayDetailSettingDlg::resizeEvent(QResizeEvent *) { _pSizeGrip->move(width() - _pSizeGrip->width(), height() - _pSizeGrip->height()); } void DiagramEditorBayDetailSettingDlg::removeRouteUsageFromDevices(const QStringList &deviceNames, const QString &routeName) { if (deviceNames.isEmpty() || routeName.isEmpty()) { qWarning() << "设备名列表或路线名为空"; return; } auto pCompoModel = _compoModel; if (!pCompoModel) { qWarning() << "组件模型为空"; return; } // 1. 设备名去重 QSet uniqueDeviceNames(deviceNames.begin(),deviceNames.end()); // 2. 遍历组件模型 for (int row = 0; row < pCompoModel->rowCount(); ++row) { QStandardItem *itemName = pCompoModel->item(row, 1); if (!itemName) continue; QString currentDevice = itemName->text(); if (uniqueDeviceNames.contains(currentDevice)) { // 3. 移除路线占用 QStandardItem *itemUsed = pCompoModel->item(row, 4); if (!itemUsed) continue; QString usageText = itemUsed->text(); QStringList routes = usageText.split(",", Qt::SkipEmptyParts); int beforeCount = routes.count(); routes.removeAll(routeName); // 4. 只有当有实际变化时才更新 if (routes.count() != beforeCount) { itemUsed->setText(routes.isEmpty() ? "" : routes.join(",")); } // 5. 从待处理集合中移除 uniqueDeviceNames.remove(currentDevice); // 6. 如果所有设备都已处理,提前结束 if (uniqueDeviceNames.isEmpty()) { break; } } } }