GridFrame/diagramCavas/source/diagramEditor/diagramEditorBayDetailSetti...

530 lines
19 KiB
C++

#include <QMessageBox>
#include <QMenu>
#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 <QTimer>
#include "titleBar.h"
#include <QSizeGrip>
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<QStandardItem*> lstItems;
lstItems<<itemCate<<itemName<<itemType<<itemObj<<itemRoute;
_compoModel->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<QStandardItem*> lstItems;
lstItems<<itemRoute<<itemParent<<itemComponents;
_routeModel->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<QString, DiagramEditorComponentInfo> 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()
{
hide();
}
void DiagramEditorBayDetailSettingDlg::onRouteDeleteClicked()
{
// 获取当前选中的索引
QModelIndexList selectedIndexes = ui->tableView->selectionModel()->selectedRows();
if (selectedIndexes.isEmpty()) {
return; // 没有选中任何行
}
// 获取行号并排序(从大到小删除避免索引变化)
QList<int> 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<QStandardItem*> 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;
}
}
}
}
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<QString, DiagramEditorRouteInfo>& mapRoute,const QList<QString>& 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<QString, DiagramEditorRouteInfo>& mapRoute,const QList<QString>& routeOrder,
const QString& routeName,QSet<QString>& 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<QString, DiagramEditorRouteInfo>& mapRoute,QList<QString>& routeOrder,const QString& modifiedRoute,bool onlyClear)
{
QSet<QString> 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<QString> 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;
}
}
}
}