You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxEditWellPlot.cpp

784 lines
32 KiB
C++

#include "nmWxEditWellPlot.h"
#include "nmWxNumericalDesign.h"
#include "nmWxParameterProperty.h"
// 包含所有需要的Qt布局和控件头文件
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QDebug>
#include <QSplitter>
#include <QCheckBox>
#include <QComboBox>
#include <QPushButton>
#include <QKeyEvent>
#include "iWxWellNew.h"
#include "ZxDataWell.h"
#include "zxSysUtils.h"
#include "nmDataWellBase.h"
#include "nmDataVerticalWell.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmWxWellboreTrajectoryDisplay.h"
#include "nmWxTimeDependentSkin.h"
#include "nmGUIComponentBase.h" // 基础组件类
#include "nmGUIComponentLineEdit.h" // 用于QLineEdit类型的参数
#include "nmGUIComponentComboBox.h" // 用于QComboBox类型的参数
#include "nmWellEditorController.h"
nmWxEditWellPlot::nmWxEditWellPlot(QWidget *parent, ZxDataWell* pZxDataWell, nmDataWellBase* pNmDataWell)
: QDialog(parent)
, m_pMainSplitter(nullptr)
, m_pTopVLayout(nullptr)
, m_pLeftVLayout(nullptr)
, m_pWellNameLineEdit(nullptr)
, m_pWellTypeComboBox(nullptr)
, m_pWellNewWidget(nullptr)
, m_pBottomLeftPanel(nullptr)
, m_pRightPanel(nullptr)
, m_pOverallBottomPanel(nullptr)
, m_pZxDataWell(pZxDataWell)
, m_pNmDataWell(nullptr)
, m_pWellEditorController(nullptr)
, m_bOriginalTimeDependentSkin(false)
{
// 设置新的数据,并创建其深拷贝
if(pNmDataWell) {
// 保存原始状态
m_bOriginalTimeDependentSkin = pNmDataWell->isTimeDependentSkin();
// 返回深拷贝对象。
m_pNmDataWell = pNmDataWell->clone();
// 数据模型变化时,刷新左侧参数面板
connect(m_pNmDataWell, SIGNAL(sigParameterChanged()),
this, SLOT(onWellDataChanged()));
}
// 初始化图标路径
m_sIconDir = QCoreApplication::applicationDirPath();
m_sIconDir = m_sIconDir.section('/', 0, -2); // 获取上一级目录
m_sIconDir += "/Res/Icon/";
this->resize(1121, 633);
// 调用初始化UI的方法
this->initUI();
// 创建控制器
if(m_pNmDataWell && m_pRightPanel) {
m_pWellEditorController = new nmWellEditorController(m_pNmDataWell, m_pRightPanel, this); // 将当前对话框作为父对象
setupControllerConnections(); // 调用连接设置函数
}
}
nmWxEditWellPlot::~nmWxEditWellPlot()
{
// 在析构函数中清理所有动态创建的组件,避免内存泄漏
qDeleteAll(m_listParameterComponents);
m_listParameterComponents.clear(); // 清空列表
}
void nmWxEditWellPlot::initUI()
{
this->initMainLayout();
// 在所有UI元素创建完成后根据井类型初始化底部左侧面板
// 注意m_pBottomLeftGridLayout 必须在这里之前被 createLeftPanel() 创建
updateBottomLeftPanelUI();
}
void nmWxEditWellPlot::initMainLayout()
{
// 创建左侧和右侧面板
QWidget* pLeftContainer = createLeftPanel();
QWidget* pRightPanelWidget = createRightPanel();
// 创建主分割器并添加左右面板
m_pMainSplitter = new QSplitter(Qt::Horizontal, this);
m_pMainSplitter->addWidget(pLeftContainer);
m_pMainSplitter->addWidget(pRightPanelWidget);
// 设置分割器的初始大小比例
QList<int> sizes;
sizes << 373 << 748;
m_pMainSplitter->setSizes(sizes);
// 创建底部面板
QWidget* pBottomPanel = createBottomPanel();
// 创建顶层垂直布局并添加分割器和底部面板
m_pTopVLayout = new QVBoxLayout(this);
m_pTopVLayout->setContentsMargins(0, 0, 0, 0);
m_pTopVLayout->setSpacing(0);
m_pTopVLayout->addWidget(m_pMainSplitter, 1); // 分割器可拉伸
m_pTopVLayout->addWidget(pBottomPanel, 0); // 底部面板固定高度,不拉伸
this->setLayout(m_pTopVLayout); // 将此布局设置为对话框的主布局
}
QWidget* nmWxEditWellPlot::createLeftPanel()
{
//m_pLeftVLayout = new QVBoxLayout();
//m_pLeftVLayout->setContentsMargins(0, 0, 0, 0);
//m_pLeftVLayout->setSpacing(5);
//// 井视图部分 (iWxWellNew) 保持不变
//m_pWellNewWidget = new iWxWellNew(this);
//m_pWellNewWidget->setDataWell(m_pZxDataWell);
//m_pWellNewWidget->setActionMode(DAM_Edit);
//m_pWellNewWidget->initUI();
//m_pWellNewWidget->setWindowFlags(Qt::Widget);
//m_pLeftVLayout->addWidget(m_pWellNewWidget, 1);
//// 1. 创建 m_pBottomLeftPanel (作为 QScrollArea 的容器)
//m_pBottomLeftPanel = new QWidget(this); // 确保它有父对象
//m_pBottomLeftPanel->setStyleSheet("background-color: white;");
//// 2. 在 m_pBottomLeftPanel 内部创建一个垂直布局来容纳 QScrollArea
//QVBoxLayout* pBottomLeftPanelVLayout = new QVBoxLayout(m_pBottomLeftPanel);
//pBottomLeftPanelVLayout->setContentsMargins(0, 0, 0, 0); // 内部布局边距
//pBottomLeftPanelVLayout->setSpacing(0); // 内部布局间距
//// 3. 创建 QScrollArea 并设置其父对象为 m_pBottomLeftPanel
//QScrollArea* pScrollArea = new QScrollArea(m_pBottomLeftPanel);
//pScrollArea->setWidgetResizable(true); // 允许滚动区域调整其内部控件的大小
//// 4. 创建一个 QWidget 作为滚动区域的内容容器
//QWidget* pScrollContent = new QWidget(pScrollArea); // 父对象是 pScrollArea
//// 5. 将 m_pBottomLeftGridLayout 设置为 pScrollContent 的布局
//m_pBottomLeftGridLayout = new QGridLayout(pScrollContent);
//m_pBottomLeftGridLayout->setContentsMargins(10, 10, 10, 10); // 网格布局的边距
//m_pBottomLeftGridLayout->setSpacing(8);
//m_pBottomLeftGridLayout->setColumnStretch(0, 1); // 标签列
//m_pBottomLeftGridLayout->setColumnStretch(1, 2); // 值输入列
//// 6. 将 pScrollContent 设置为滚动区域的内容控件
//pScrollArea->setWidget(pScrollContent);
//// 7. 将滚动区域添加到 m_pBottomLeftPanel 的内部布局中
//pBottomLeftPanelVLayout->addWidget(pScrollArea);
//// 将 m_pBottomLeftPanel (现在包含了滚动区域) 添加到左侧主垂直布局
//m_pLeftVLayout->addWidget(m_pBottomLeftPanel, 1); // 占据垂直布局的1份空间
//// 创建一个 QWidget 来承载左侧的垂直布局
//QWidget* pLeftContainer = new QWidget(this);
//pLeftContainer->setLayout(m_pLeftVLayout);
//pLeftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//return pLeftContainer;
m_pLeftVLayout = new QVBoxLayout();
m_pLeftVLayout->setContentsMargins(0, 0, 0, 0);
m_pLeftVLayout->setSpacing(5);
// 1. 创建 m_pBottomLeftPanel (作为 QScrollArea 的容器)
m_pBottomLeftPanel = new QWidget(this); // 确保它有父对象
m_pBottomLeftPanel->setStyleSheet("background-color: white;");
// 2. 在 m_pBottomLeftPanel 内部创建一个垂直布局来容纳 QScrollArea
QVBoxLayout* pBottomLeftPanelVLayout = new QVBoxLayout(m_pBottomLeftPanel);
pBottomLeftPanelVLayout->setContentsMargins(0, 0, 0, 0); // 内部布局边距
pBottomLeftPanelVLayout->setSpacing(0); // 内部布局间距
// 3. 创建 QScrollArea 并设置其父对象为 m_pBottomLeftPanel
QScrollArea* pScrollArea = new QScrollArea(m_pBottomLeftPanel);
pScrollArea->setWidgetResizable(true); // 允许滚动区域调整其内部控件的大小
// 4. 创建一个 QWidget 作为滚动区域的内容容器
QWidget* pScrollContent = new QWidget(pScrollArea); // 父对象是 pScrollArea
// 5. 将 m_pBottomLeftGridLayout 设置为 pScrollContent 的布局
m_pBottomLeftGridLayout = new QGridLayout(pScrollContent);
m_pBottomLeftGridLayout->setContentsMargins(10, 10, 10, 10); // 网格布局的边距
m_pBottomLeftGridLayout->setSpacing(8);
m_pBottomLeftGridLayout->setColumnStretch(0, 1); // 标签列
m_pBottomLeftGridLayout->setColumnStretch(1, 2); // 值输入列
// 6. 将 pScrollContent 设置为滚动区域的内容控件
pScrollArea->setWidget(pScrollContent);
// 7. 将滚动区域添加到 m_pBottomLeftPanel 的内部布局中
pBottomLeftPanelVLayout->addWidget(pScrollArea);
// 将 m_pBottomLeftPanel (现在包含了滚动区域) 添加到左侧主垂直布局
m_pLeftVLayout->addWidget(m_pBottomLeftPanel, 1); // 占据垂直布局的1份空间
// 创建一个 QWidget 来承载左侧的垂直布局
QWidget* pLeftContainer = new QWidget(this);
pLeftContainer->setLayout(m_pLeftVLayout);
pLeftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
return pLeftContainer;
}
QWidget* nmWxEditWellPlot::createRightPanel()
{
m_pRightPanel = new nmWxWellboreTrajectoryDisplay(this);
m_pRightPanel->setContentsMargins(0, 0, 0, 0); // 可以设置外部边距
m_pRightPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// 设置井数据
m_pRightPanel->setCurrentWellboreData(m_pNmDataWell);
return m_pRightPanel;
}
QWidget* nmWxEditWellPlot::createBottomPanel()
{
m_pOverallBottomPanel = new QWidget(this);
m_pOverallBottomPanel->setFixedHeight(80); // 增加高度以容纳两行内容
QVBoxLayout* mainBottomVLayout = new QVBoxLayout(m_pOverallBottomPanel);
mainBottomVLayout->setContentsMargins(5, 5, 5, 5);
mainBottomVLayout->setSpacing(5);
// 第一行:原有的控件
QWidget* hContentContainer = new QWidget(m_pOverallBottomPanel);
QHBoxLayout* bottomContentHLayout = new QHBoxLayout(hContentContainer);
bottomContentHLayout->setContentsMargins(0, 0, 0, 0);
bottomContentHLayout->setSpacing(10);
QCheckBox* myCheckBox = new QCheckBox("Use in multiple well modes", hContentContainer);
QComboBox* myComboBox = new QComboBox(hContentContainer);
myComboBox->addItem("Tested well");
myComboBox->addItem("well_1");
myComboBox->addItem("well_2");
QPushButton* pOKButton = new QPushButton("OK", hContentContainer);
QPushButton* pCancelButton = new QPushButton("Cancel", hContentContainer);
bottomContentHLayout->addWidget(myCheckBox);
bottomContentHLayout->addWidget(myComboBox);
bottomContentHLayout->addStretch();
bottomContentHLayout->addWidget(pOKButton);
bottomContentHLayout->addWidget(pCancelButton);
// 连接按钮到自定义槽函数 (Qt 4 语法)
connect(pOKButton, SIGNAL(clicked()), this, SLOT(onOkClicked()));
connect(pCancelButton, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
// 第二行:时间相关复选框和关联的时钟图标按钮
QWidget* timeContainer = new QWidget(m_pOverallBottomPanel);
QHBoxLayout* pTimeDependentLayout = new QHBoxLayout(timeContainer);
pTimeDependentLayout->setContentsMargins(0, 0, 0, 0);
pTimeDependentLayout->setSpacing(5);
m_pTimeDependentCheck = new QCheckBox(tr("Time dependent"), timeContainer);
m_pTimeDependentCheck->setChecked(m_pNmDataWell->isTimeDependentSkin());
m_pTimeDependentIconButton = new QPushButton(timeContainer);
m_pTimeDependentIconButton->setIcon(QIcon(m_sIconDir + "NmAnalDesign3.png")); // 使用时钟图标
m_pTimeDependentIconButton->setIconSize(QSize(20, 20));
m_pTimeDependentIconButton->setFixedSize(22, 22);
m_pTimeDependentIconButton->setEnabled(m_pNmDataWell->isTimeDependentSkin());
pTimeDependentLayout->addWidget(m_pTimeDependentCheck);
pTimeDependentLayout->addWidget(m_pTimeDependentIconButton);
pTimeDependentLayout->addStretch(); // 添加拉伸器,将它们推到左侧
// 连接复选框状态变化信号到槽函数
connect(m_pTimeDependentCheck, SIGNAL(toggled(bool)),
m_pTimeDependentIconButton, SLOT(setEnabled(bool)));
connect(m_pTimeDependentIconButton, SIGNAL(clicked()),
this, SLOT(onTimeDependentIconClicked()));
connect(m_pTimeDependentCheck, SIGNAL(toggled(bool)),
this, SLOT(onTimeDependentCheckToggled(bool)));
// 将两行内容添加到主垂直布局
mainBottomVLayout->addWidget(hContentContainer);
mainBottomVLayout->addWidget(timeContainer);
return m_pOverallBottomPanel;
}
void nmWxEditWellPlot::setupControllerConnections()
{
if(!m_pWellEditorController || !m_pRightPanel || !m_pNmDataWell) {
return;
}
// --- 1. nmWxWellboreTrajectoryDisplay (视图) 发出的模式请求信号连接到控制器 ---
// 这些信号会在用户点击工具栏按钮时发出
connect(m_pRightPanel, SIGNAL(requestedEditWellMode(int)),
m_pWellEditorController, SLOT(onRequestEditWellMode(int)));
connect(m_pRightPanel, SIGNAL(requestedEditPerforationsMode(int)),
m_pWellEditorController, SLOT(onRequestEditPerforationsMode(int)));
connect(m_pRightPanel, SIGNAL(requestedNewPerforationMode(int)),
m_pWellEditorController, SLOT(onRequestNewPerforationMode(int)));
connect(m_pRightPanel, SIGNAL(requestedDeletePerforationMode(int)),
m_pWellEditorController, SLOT(onRequestDeletePerforationMode(int)));
connect(m_pRightPanel, SIGNAL(requestedSnapPerforationMode(int)),
m_pWellEditorController, SLOT(onRequestSnapPerforationMode(int)));
connect(m_pRightPanel, SIGNAL(sigClearViewStates()),
m_pWellEditorController, SLOT(slotClearViewStates()));
// --- 2. nmWxWellboreTrajectoryDisplay (视图) 发出的视图切换信号连接到控制器 ---
connect(m_pRightPanel, SIGNAL(currentViewChanged(int)),
m_pWellEditorController, SLOT(onViewChanged(int)));
// 井筒点移动信号到控制器 (只在拖动结束时触发)
connect(m_pRightPanel, SIGNAL(sigWellboreTrajectoryPointMoved(QPointF)),
m_pWellEditorController, SLOT(slotWellboreTrajectoryPointMoved(QPointF)));
// 射孔拖动信号到控制器 (只在拖动结束时触发)
connect(m_pRightPanel, SIGNAL(sigPerforationDragFinished(nmDataPerforation*, double, double)),
m_pWellEditorController, SLOT(slotPerforationDragFinished(nmDataPerforation*, double, double)));
// 射孔添加模式,发送给控制器
connect(m_pRightPanel, SIGNAL(sigTryAddNewPerforation(QPointF, double, double, QLineF)),
m_pWellEditorController, SLOT(slotTryAddNewPerforation(QPointF, double, double, QLineF)));
// 射孔删除模式
connect(m_pRightPanel, SIGNAL(sigTryDeletePerforation(nmDataPerforation*)),
m_pWellEditorController, SLOT(slotDeletePerforation(nmDataPerforation*)));
// 更新裂缝俯视位置
connect(m_pRightPanel, SIGNAL(sigFractureGeometryDragFinished(double, double)),
m_pWellEditorController, SLOT(slotFractureGeometryChanged(double, double)));
// 连接截面图下更新裂缝位置的信号槽
connect(m_pRightPanel, SIGNAL(sigRequestFractureRectUpdate(qreal, qreal)),
m_pWellEditorController, SLOT(slotHandleFractureRectUpdate(qreal, qreal)));
// 射孔更新
connect(m_pRightPanel, SIGNAL(sigFractureDragFinished(const QMap<nmDataPerforation*, QPair<double, double>>&)),
m_pWellEditorController, SLOT(slotUpdatePerforations(const QMap<nmDataPerforation*, QPair<double, double>>&)));
// 裂缝半长更新
connect(m_pRightPanel, SIGNAL(sigFractureHalfLengthChanged(double)),
m_pWellEditorController, SLOT(slotUpdateFractureHalfLength(double)));
// 井身位置更新
connect(m_pRightPanel, SIGNAL(sigWellboreDragFinished(QPointF)),
m_pWellEditorController, SLOT(slotUpdateWellborePos(QPointF)));
// 多段压裂水平井截面图裂缝位置更新
connect(m_pRightPanel, SIGNAL(sigFractureGeometryChanged(double, double)),
m_pWellEditorController, SLOT(slotHFWellFractureGeometryChanged(double, double)));
}
void nmWxEditWellPlot::updateBottomLeftPanelUI()
{
if(!m_pNmDataWell || !m_pBottomLeftGridLayout) {
qDebug() << "nmDataWellBase pointer or m_pBottomLeftGridLayout is null in updateBottomLeftPanelUI!";
return;
}
// 1. 清空当前网格布局中的所有控件
// 并从 m_listParameterComponents 中删除并释放所有组件
QLayoutItem *item;
while((item = m_pBottomLeftGridLayout->takeAt(0)) != nullptr) {
if(item->widget()) {
// 从 m_listParameterComponents 中移除并删除对应的组件
nmGUIComponentBase* component = qobject_cast<nmGUIComponentBase*>(item->widget());
if(component) {
m_listParameterComponents.removeOne(component); // 从列表中移除
// component->deleteLater(); // item->widget() 会处理删除
}
item->widget()->deleteLater(); // 删除Qt控件
}
delete item; // 删除布局项
}
m_listParameterComponents.clear(); // 确保列表清空
int currentRow = 0; // 用于跟踪当前添加控件的行数
// 2. 添加井名称的 QLabel 和 QLineEdit
m_pWellNameLineEdit = nullptr;
QLabel* pWellNameLabel = new QLabel(tr("Well Name:"), this);
// 使用成员变量 m_pWellNameLineEdit确保在槽函数中可以访问
m_pWellNameLineEdit = new QLineEdit(this);
m_pWellNameLineEdit->setText(m_pNmDataWell->getWellName());
// 连接编辑框的编辑完成信号到槽函数
connect(m_pWellNameLineEdit, SIGNAL(editingFinished()),
this, SLOT(onWellNameEditingFinished()));
m_pBottomLeftGridLayout->addWidget(pWellNameLabel, currentRow, 0, 1, 1);
m_pBottomLeftGridLayout->addWidget(m_pWellNameLineEdit, currentRow, 1, 1, 1);
currentRow++; // 行号递增
// 3. 创建并添加 QLabel 和 QComboBox
m_pWellTypeComboBox = nullptr;
QLabel* pWellTypeLabel = new QLabel(tr("Well Type:"), this);
m_pWellTypeComboBox = new QComboBox(this);
m_pWellTypeComboBox->addItem(tr("Vertical Well"), NM_WELL_MODEL::Vertical_Well);
m_pWellTypeComboBox->addItem(tr("Vertical Fractured Well"), NM_WELL_MODEL::Vertical_Fractured_Well);
m_pWellTypeComboBox->addItem(tr("Horizontal Fractured Well"), NM_WELL_MODEL::Horizontal_Fractured_Well);
// 重新连接信号槽
connect(m_pWellTypeComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(onWellTypeChanged(int)));
// 4. 根据当前 m_pNmDataWell 的类型设置选中项
NM_WELL_MODEL currentType = m_pNmDataWell->getWellType();
int index = m_pWellTypeComboBox->findData(currentType);
if(index != -1) {
m_pWellTypeComboBox->setCurrentIndex(index);
}
// 5. 将 QLabel 和 QComboBox 添加到布局
m_pBottomLeftGridLayout->addWidget(pWellTypeLabel, currentRow, 0, 1, 1);
m_pBottomLeftGridLayout->addWidget(m_pWellTypeComboBox, currentRow, 1, 1, 1);
currentRow++;
// 6. 根据井类型动态添加参数
// 这里使用 dynamic_cast 来判断具体的井类型并访问其特有属性
// 井的通用参数(所有井类型都可能有的)
// Location---位置
// addLineEditComponentToGrid(m_pNmDataWell->getInputWellHead(), currentRow);
// addLineEditComponentToGrid(m_pNmDataWell->getWellHeadX(), currentRow);
// addLineEditComponentToGrid(m_pNmDataWell->getWellHeadY(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getX(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getY(), currentRow);
// Geometry and properties---几何与属性
addLineEditComponentToGrid(m_pNmDataWell->getDrillFloorElevation(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getRadius(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getZw(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getWellLength(), currentRow);
// addLineEditComponentToGrid(m_pNmDataWell->getRateDependentSkin(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getdSdQ(), currentRow);
// Wellbore---井储
addComboBoxComponentToGrid(m_pNmDataWell->getWellboreModel(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getWellboreStorage(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getFinalWellboreStorage(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getCInitialCFinal(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getDtChangingStorage(), currentRow);
addLineEditComponentToGrid(m_pNmDataWell->getLeakSkin(), currentRow);
// Bottomhole conditions---井底条件
addLineEditComponentToGrid(m_pNmDataWell->getBottomholeMD(), currentRow);
// 射孔段的表皮系数(如果井有射孔段)
if(m_pNmDataWell->getPerforationCount() > 0) {
for(int i = 0; i < m_pNmDataWell->getPerforationCount(); ++i) {
nmDataPerforation* perforation = m_pNmDataWell->getPerforation(i);
if(perforation) {
addLineEditComponentToGrid(perforation->getName(), currentRow);
addLineEditComponentToGrid(perforation->getMdStart(), currentRow);
addLineEditComponentToGrid(perforation->getMdEnd(), currentRow);
addLineEditComponentToGrid(perforation->getSkin(), currentRow);
}
}
}
// 根据具体的井模型添加特有参数
if(nmDataVerticalFracturedWell * pVFWell = dynamic_cast<nmDataVerticalFracturedWell * >(m_pNmDataWell)) {
// 垂直裂缝井特有参数
addVerticalFracturedWellParameters(pVFWell, currentRow); // 委托给私有辅助函数
} else if(nmDataHorizontalFracturedWell * pHFWell = dynamic_cast<nmDataHorizontalFracturedWell * >(m_pNmDataWell)) {
// 多段压裂水平井特有参数
addHorizontalFracturedWellParameters(pHFWell, currentRow); // 委托给私有辅助函数
} else if(nmDataVerticalWell * pVWell = dynamic_cast<nmDataVerticalWell * >(m_pNmDataWell)) {
// 直井特有参数
addVerticalWellParameters(pVWell, currentRow); // 委托给私有辅助函数
}
// 强制刷新布局和调整面板大小
// m_pBottomLeftGridLayout->update();
// m_pBottomLeftPanel->adjustSize(); // 调整面板大小以适应新内容
}
// 辅助函数:向网格布局中添加 nmGUIComponentLineEdit
void nmWxEditWellPlot::addLineEditComponentToGrid(nmDataAttribute& attribute, int& row)
{
// const_cast 是安全的,因为 nmGUIComponentLineEdit 内部会操作 nmDataAttribute 的非 const 引用,
// 而这个引用在 nmDataWell 对象内部是可修改的。
nmGUIComponentLineEdit* component = new nmGUIComponentLineEdit(const_cast<nmDataAttribute*>(&attribute), true, m_pBottomLeftPanel);
// 设置实时更新数据
component->setIsRealTimeUpdateValue(true);
m_listParameterComponents.append(component); // 添加到管理列表中
m_pBottomLeftGridLayout->addWidget(component, row, 0, 1, 2); // 跨两列
row++; // 行号递增
}
// 辅助函数:向网格布局中添加 nmGUIComponentComboBox
void nmWxEditWellPlot::addComboBoxComponentToGrid(nmDataAttribute& attribute, int& row)
{
nmGUIComponentComboBox* component = new nmGUIComponentComboBox(const_cast<nmDataAttribute*>(&attribute), true, m_pBottomLeftPanel);
m_listParameterComponents.append(component); // 添加到管理列表中
m_pBottomLeftGridLayout->addWidget(component, row, 0, 1, 2); // 跨两列
row++; // 行号递增
}
// 私有辅助函数:添加垂直井特有参数
void nmWxEditWellPlot::addVerticalWellParameters(nmDataVerticalWell* well, int& row)
{
if(!well) return;
// 添加垂直井特有的参数
addLineEditComponentToGrid(well->getPerforationLength(), row);
}
// 私有辅助函数:添加垂直压裂井特有参数
void nmWxEditWellPlot::addVerticalFracturedWellParameters(nmDataVerticalFracturedWell* well, int& row)
{
if(!well) return;
// 添加垂直压裂井特有的参数
addComboBoxComponentToGrid(well->getFractureModel(), row);
addLineEditComponentToGrid(well->getFractureHalfLength(), row);
addLineEditComponentToGrid(well->getFractureHeight(), row);
addLineEditComponentToGrid(well->getFractureMidPointHeight(), row);
addLineEditComponentToGrid(well->getWidth(), row);
addLineEditComponentToGrid(well->getFractureAngle(), row);
addLineEditComponentToGrid(well->getDfc(), row);
}
// 私有辅助函数:添加水平压裂井特有参数
void nmWxEditWellPlot::addHorizontalFracturedWellParameters(nmDataHorizontalFracturedWell* well, int& row)
{
if(!well) return;
// 添加水平压裂井特有的参数
addLineEditComponentToGrid(well->getDrainAngle(), row);
addComboBoxComponentToGrid(well->getModelingType(), row);
addComboBoxComponentToGrid(well->getFractureModel(), row);
addLineEditComponentToGrid(well->getNumberOfFractures(), row);
addLineEditComponentToGrid(well->getFractureHalfLength(), row);
addLineEditComponentToGrid(well->getFractureHeight(), row);
addLineEditComponentToGrid(well->getFractureMidPointHeight(), row);
addLineEditComponentToGrid(well->getWidth(), row);
addLineEditComponentToGrid(well->getFractureAngle(), row);
addLineEditComponentToGrid(well->getStimulatedZonesAroundFracture(), row);
addLineEditComponentToGrid(well->getStimulationRadius(), row);
addLineEditComponentToGrid(well->getPermeabilityMultiplier(), row);
addLineEditComponentToGrid(well->getPorosityMultiplier(), row);
addLineEditComponentToGrid(well->getDfc(), row);
}
nmDataWellBase* nmWxEditWellPlot::getModifiedDataWell()
{
return m_pNmDataWell;
}
void nmWxEditWellPlot::onOkClicked()
{
if(!m_pNmDataWell) {
qDebug() << "nmDataWellBase pointer is null in onOkClicked!";
QDialog::reject();
return;
}
// 应用时间变表皮状态到真实数据
nmDataWellBase* pRealWell = nmDataAnalyzeManager::getCurrentInstance()->getCurWellData();
if(pRealWell && pRealWell->getWellName() == m_pNmDataWell->getWellName()) {
pRealWell->setTimeDependentSkin(m_pNmDataWell->isTimeDependentSkin());
}
nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance();
NM_WELL_MODEL currentWellType = m_pNmDataWell->getWellType();
// 根据井类型调用对应的update方法
if(currentWellType == NM_WELL_MODEL::Vertical_Well) {
// 转换为垂直井类型
if(auto * verticalWell = dynamic_cast<nmDataVerticalWell * >(m_pNmDataWell)) {
QVector<nmDataVerticalWell> wells;
wells.append(*verticalWell); // 添加井的副本到QVector中
manager->updateVerticalWells(wells);
}
} else if(currentWellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
// 转换为垂直压裂井类型
if(auto * verticalFracturedWell = dynamic_cast<nmDataVerticalFracturedWell * >(m_pNmDataWell)) {
QVector<nmDataVerticalFracturedWell> wells;
wells.append(*verticalFracturedWell); // 添加井的副本到QVector中
manager->updateVerticalFracturedWells(wells);
}
} else if(currentWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
// 转换为水平压裂井类型
if(auto * horizontalFracturedWell = dynamic_cast<nmDataHorizontalFracturedWell * >(m_pNmDataWell)) {
QVector<nmDataHorizontalFracturedWell> wells;
wells.append(*horizontalFracturedWell); // 添加井的副本到QVector中
manager->updateHorizontalFracturedWells(wells);
}
} else {
QDialog::reject();
return;
}
// 更新完成后,通知参数界面刷新
nmWxParameterProperty::notifyUpdateTable();
accept();
}
void nmWxEditWellPlot::onCancelClicked()
{
if(m_pNmDataWell) {
nmWxNumericalDesign::notifyTimeDependentSkinChanged(m_pNmDataWell->getWellName(), m_bOriginalTimeDependentSkin);
delete m_pNmDataWell;
m_pNmDataWell = nullptr;
}
reject();
}
void nmWxEditWellPlot::onWellDataChanged()
{
// 重新加载所有参数将模型中的新值显示在UI上
updateBottomLeftPanelUI();
}
void nmWxEditWellPlot::onWellTypeChanged(int index)
{
// 1. 获取选择的井类型枚举值
// 使用 itemData() 方法获取在 addItem() 时关联的枚举值
QVariant selectedData = m_pWellTypeComboBox->itemData(index);
if(!selectedData.isValid()) {
return;
}
NM_WELL_MODEL newWellType = static_cast<NM_WELL_MODEL>(selectedData.toInt());
// 2. 获取当前井的类型
NM_WELL_MODEL currentWellType = m_pNmDataWell->getWellType();
// 3. 如果新旧类型相同,则无需操作
if(newWellType == currentWellType) {
return;
}
// 4. 实现核心逻辑:创建新对象、复制数据、销毁旧对象
// 保存旧数据模型的指针
nmDataWellBase* pOldWellData = m_pNmDataWell;
// 创建一个新的数据模型对象
nmDataWellBase* pNewWellData = nullptr;
if(newWellType == NM_WELL_MODEL::Vertical_Well) {
pNewWellData = new nmDataVerticalWell();
pNewWellData->setWellType(Vertical_Well);
} else if(newWellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
pNewWellData = new nmDataVerticalFracturedWell();
pNewWellData->setWellType(Vertical_Fractured_Well);
} else if(newWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
pNewWellData = new nmDataHorizontalFracturedWell();
pNewWellData->setWellType(Horizontal_Fractured_Well);
} else {
return;
}
// 将旧数据中的通用属性复制到新数据中
if(pNewWellData && pOldWellData) {
// 通用几何位置
pNewWellData->setWellName(pOldWellData->getWellName());
pNewWellData->setX(pOldWellData->getX());
pNewWellData->setY(pOldWellData->getY());
pNewWellData->setRadius(pOldWellData->getRadius());
// 历史数据
pNewWellData->setPressurePoints(pOldWellData->getPressurePoints());
pNewWellData->setFlowPoints(pOldWellData->getFlowPoints());
pNewWellData->setIndexF(pOldWellData->getIndexF());
// 结果数据
pNewWellData->setResultPressure(pOldWellData->getResultPressure());
pNewWellData->setResultLogLog(pOldWellData->getResultLogLog());
pNewWellData->setResultSemiLog(pOldWellData->getResultSemiLog());
}
// 对于裂缝类型的井,需要更新裂缝位置
if(newWellType == NM_WELL_MODEL::Vertical_Fractured_Well) {
if(nmDataVerticalFracturedWell * pVFWell = dynamic_cast<nmDataVerticalFracturedWell * >(pNewWellData)) {
pVFWell->setFracs();
}
} else if(newWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) {
if(nmDataHorizontalFracturedWell * pHFWell = dynamic_cast<nmDataHorizontalFracturedWell * >(pNewWellData)) {
pHFWell->setFracs();
}
}
// 5. 更新 m_pNmDataWell 指针
m_pNmDataWell = pNewWellData;
// 6. 重新连接信号:先断开旧连接,再连接新对象
if(pOldWellData) {
disconnect(pOldWellData, SIGNAL(sigParameterChanged()), this, SLOT(onWellDataChanged()));
}
if(m_pNmDataWell) {
connect(m_pNmDataWell, SIGNAL(sigParameterChanged()), this, SLOT(onWellDataChanged()));
}
// 7. 销毁旧控制器并创建新控制器
// 由于控制器是 QObject 的子对象它会被父对象this自动管理内存。
// 但是为了保证逻辑的清晰和安全,我们手动处理。
if(m_pWellEditorController) {
delete m_pWellEditorController;
m_pWellEditorController = nullptr;
}
if(m_pNmDataWell && m_pRightPanel) {
m_pWellEditorController = new nmWellEditorController(m_pNmDataWell, m_pRightPanel, this);
// 重建控制器后,必须重新连接所有信号
setupControllerConnections();
}
// 8. 销毁旧数据对象
if(pOldWellData) {
delete pOldWellData;
}
// 9. 刷新 UI
updateBottomLeftPanelUI();
// 10. 通知 nmWxWellboreTrajectoryDisplay 视图刷新
if(m_pRightPanel) {
m_pRightPanel->setCurrentWellboreData(m_pNmDataWell); // 重新设置数据
}
}
void nmWxEditWellPlot::onWellNameEditingFinished()
{
if(m_pNmDataWell && m_pWellNameLineEdit) {
// 获取编辑框中的文本并更新数据模型
m_pNmDataWell->setWellName(m_pWellNameLineEdit->text());
}
}
void nmWxEditWellPlot::keyPressEvent(QKeyEvent *event)
{
// 如果按下的键是回车键,则忽略它,不调用父类的 keyPressEvent
if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
// 事件已被处理,阻止它继续传播
event->ignore();
return;
}
// 对于所有其他按键,调用基类的处理
QDialog::keyPressEvent(event);
}
void nmWxEditWellPlot::onTimeDependentIconClicked()
{
if(!m_pNmDataWell) {
return;
}
nmWxTimeDependentSkin::showForCurrentWell(m_pNmDataWell, this); // 传具体井数据
}
void nmWxEditWellPlot::onTimeDependentCheckToggled(bool checked)
{
if(!m_pNmDataWell) {
return;
}
// 更新数据模型
m_pNmDataWell->setTimeDependentSkin(checked);
nmWxNumericalDesign::notifyTimeDependentSkinChanged(m_pNmDataWell->getWellName(), checked);
}