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/nmWxWellEditor.cpp

739 lines
25 KiB
C++

#include "nmWxWellEditor.h"
#include "iUnitWxBinder.h"
#include "mModuleDefines.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataPerforation.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataWellBase.h"
#include "nmWellEditorController.h"
#include "nmWellEditorSession.h"
#include "nmWellParameterPanel.h"
#include "nmWxTimeDependentSkin.h"
#include "nmWxWellboreTrajectoryDisplay.h"
#include "ZxBaseUtil.h"
#include <QCheckBox>
#include <QComboBox>
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QFrame>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QIcon>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QPalette>
#include <QPushButton>
#include <QRegExp>
#include <QScrollArea>
#include <QSplitter>
#include <QToolButton>
#include <QVector>
#include <QVBoxLayout>
nmWxWellEditor::nmWxWellEditor(const nmWellEditContext& oContext,
QWidget* pParent)
: iDlgBase(pParent),
m_pSession(new nmWellEditorSession(oContext)),
m_pParameterPanel(nullptr),
m_pTrajectoryDisplay(nullptr),
m_pWellEditorController(nullptr),
m_pWellCodeLineEdit(nullptr),
m_pWellNameLineEdit(nullptr),
m_pWellTypeComboBox(nullptr),
m_pTimeDependentCheckBox(nullptr),
m_pTimeDependentButton(nullptr),
m_pButtonBox(nullptr),
m_pStatusLabel(nullptr),
m_pMainSplitter(nullptr),
m_sPanelValidationMessage(),
m_bInitialized(false),
m_bChangingWellType(false)
{
// 构造阶段只创建静态界面工作副本和轨迹绑定由initialize()完成。
setParaSrcTag(s_Nm_Serie);
createUi();
setWindowTitle(tr("Edit well"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumSize(940, 600);
resize(1180, 720);
}
nmWxWellEditor::~nmWxWellEditor()
{
// 界面和控制器仍引用工作副本,必须在会话释放井对象前销毁。
delete m_pWellEditorController;
m_pWellEditorController = nullptr;
delete m_pMainSplitter;
m_pMainSplitter = nullptr;
m_pParameterPanel = nullptr;
m_pTrajectoryDisplay = nullptr;
delete m_pSession;
m_pSession = nullptr;
}
bool nmWxWellEditor::initialize(QString& sError)
{
if (m_pSession == nullptr || !m_pSession->initialize(sError))
{
return false;
}
nmDataWellBase* pWell = m_pSession->currentWell();
if (pWell == nullptr)
{
sError = tr("The well working copy is unavailable.");
return false;
}
// 第一步:同步井信息和时间变表皮控件。
m_pWellCodeLineEdit->setText(pWell->getWellCode());
m_pWellNameLineEdit->setText(pWell->getWellName());
int nWellTypeIndex = m_pWellTypeComboBox->findData(
static_cast<int>(pWell->getWellType()));
m_bChangingWellType = true;
m_pWellTypeComboBox->setCurrentIndex(nWellTypeIndex);
m_bChangingWellType = false;
reloadTimeDependentSkinControls(pWell);
// 第二步:创建当前井型字段并将轨迹视图绑定到同一工作副本。
if (!m_pParameterPanel->setWellData(pWell, sError))
{
return false;
}
m_pTrajectoryDisplay->setCurrentWellboreData(pWell);
createController();
m_bInitialized = true;
updateAcceptState();
sError.clear();
return true;
}
nmDataWellBase* nmWxWellEditor::takeModifiedWell()
{
return m_pSession != nullptr
? m_pSession->takeModifiedWell() : nullptr;
}
bool nmWxWellEditor::bindUnitField(
QLineEdit* pLineEdit,
QComboBox* pUnitComboBox,
const QString& sBaseParameterId)
{
return bindUnitPairWxs(pLineEdit,
pUnitComboBox,
sBaseParameterId,
false);
}
void nmWxWellEditor::setUnitBaseValue(QLineEdit* pLineEdit,
double dBaseValue)
{
if (m_pUnitBinder != nullptr)
{
m_pUnitBinder->setBaseValue(pLineEdit, dBaseValue);
}
}
double nmWxWellEditor::unitBaseValue(QLineEdit* pLineEdit) const
{
return m_pUnitBinder != nullptr
? m_pUnitBinder->getBaseValue(pLineEdit) : 0.0;
}
bool nmWxWellEditor::isUnitInputValid(QLineEdit* pLineEdit)
{
return m_pUnitBinder != nullptr &&
m_pUnitBinder->isInputOK(pLineEdit, true, nullptr);
}
QString nmWxWellEditor::currentUnit(QLineEdit* pLineEdit) const
{
return m_pUnitBinder != nullptr
? m_pUnitBinder->getCurrentUnit(pLineEdit) : QString();
}
iUnitGroup* nmWxWellEditor::unitGroup(QLineEdit* pLineEdit) const
{
return m_pUnitBinder != nullptr
? m_pUnitBinder->getUnitGroup(pLineEdit) : nullptr;
}
void nmWxWellEditor::accept()
{
if (!m_bInitialized)
{
return;
}
// 第一步:井名和参数必须全部通过校验,原始井此时仍未修改。
QString sWellName;
QString sError;
if (!validateWellName(sWellName, sError))
{
m_pStatusLabel->setText(sError);
m_pWellNameLineEdit->setFocus();
m_pWellNameLineEdit->selectAll();
updateAcceptState();
return;
}
if (!m_pParameterPanel->commitPendingEdits(sError))
{
m_pStatusLabel->setText(sError);
m_pParameterPanel->focusFirstInvalid();
updateAcceptState();
return;
}
// 第二步只整理最终工作副本真实数据由Binder在窗口返回后替换。
m_pSession->setWellName(sWellName);
nmDataWellBase* pWell = m_pSession->currentWell();
if (nmDataVerticalFracturedWell* pVertical =
dynamic_cast<nmDataVerticalFracturedWell*>(pWell))
{
pVertical->setFracs();
}
if (nmDataHorizontalFracturedWell* pHorizontal =
dynamic_cast<nmDataHorizontalFracturedWell*>(pWell))
{
pHorizontal->setFracs();
}
iDlgBase::accept();
}
void nmWxWellEditor::reject()
{
iDlgBase::reject();
}
void nmWxWellEditor::keyPressEvent(QKeyEvent* pEvent)
{
// 参数输入框按回车只结束编辑,不能绕过完整校验直接关闭窗口。
if (pEvent != nullptr &&
(pEvent->key() == Qt::Key_Enter ||
pEvent->key() == Qt::Key_Return))
{
pEvent->ignore();
return;
}
iDlgBase::keyPressEvent(pEvent);
}
void nmWxWellEditor::slotWellTypeChanged(int nIndex)
{
if (m_bChangingWellType || !m_bInitialized || nIndex < 0)
{
return;
}
NM_WELL_MODEL ePreviousType = m_pSession->currentWellType();
NM_WELL_MODEL eNewType = static_cast<NM_WELL_MODEL>(
m_pWellTypeComboBox->itemData(nIndex).toInt());
if (eNewType == ePreviousType)
{
return;
}
// 第一步:离开当前井型前保存全部有效输入,非法时回退选择。
QString sError;
if (!m_pParameterPanel->commitPendingEdits(sError))
{
m_bChangingWellType = true;
m_pWellTypeComboBox->setCurrentIndex(
m_pWellTypeComboBox->findData(
static_cast<int>(ePreviousType)));
m_bChangingWellType = false;
m_pStatusLabel->setText(sError);
m_pParameterPanel->focusFirstInvalid();
return;
}
// 第二步:恢复目标井型缓存,首次进入时由会话保留该井型默认几何。
if (!m_pSession->switchWellType(eNewType, sError))
{
m_bChangingWellType = true;
m_pWellTypeComboBox->setCurrentIndex(
m_pWellTypeComboBox->findData(
static_cast<int>(ePreviousType)));
m_bChangingWellType = false;
m_pStatusLabel->setText(sError);
return;
}
// 第三步:同步井名,并从目标工作副本恢复井型专属状态。
m_pSession->setWellName(m_pWellNameLineEdit->text());
nmDataWellBase* pWell = m_pSession->currentWell();
reloadTimeDependentSkinControls(pWell);
if (!m_pParameterPanel->setWellData(pWell, sError))
{
m_pStatusLabel->setText(sError);
return;
}
m_pTrajectoryDisplay->setCurrentWellboreData(pWell);
createController();
updateAcceptState();
}
void nmWxWellEditor::slotWellNameEdited(const QString& sWellName)
{
if (m_pSession != nullptr)
{
m_pSession->setWellName(sWellName);
}
updateAcceptState();
}
void nmWxWellEditor::slotTimeDependentToggled(bool bChecked)
{
m_pTimeDependentButton->setEnabled(bChecked);
if (m_pSession != nullptr)
{
m_pSession->setTimeDependentSkin(bChecked);
}
}
void nmWxWellEditor::reloadTimeDependentSkinControls(
nmDataWellBase* pWell)
{
bool bEnabled = pWell != nullptr &&
pWell->isTimeDependentSkin();
// 程序回填不应再次写会话,避免覆盖目标井型缓存。
bool bSignalsWereBlocked =
m_pTimeDependentCheckBox->blockSignals(true);
m_pTimeDependentCheckBox->setChecked(bEnabled);
m_pTimeDependentCheckBox->blockSignals(bSignalsWereBlocked);
m_pTimeDependentButton->setEnabled(bEnabled);
}
void nmWxWellEditor::slotEditTimeDependentSkin()
{
if (!m_bInitialized || m_pSession->currentWell() == nullptr)
{
return;
}
// 第一步:子窗口打开前先提交主窗口输入,保证两处看到同一份数据。
QString sError;
if (!m_pParameterPanel->commitPendingEdits(sError))
{
m_pStatusLabel->setText(sError);
m_pParameterPanel->focusFirstInvalid();
return;
}
// 第二步:旧子窗口会直接修改传入井,打开前保存完整射孔快照。
nmDataWellBase* pWell = m_pSession->currentWell();
QVector<nmDataPerforation> vecOriginalPerforations;
for (int nIndex = 0; nIndex < pWell->getPerforationCount(); ++nIndex)
{
vecOriginalPerforations.append(
pWell->getPerforationCopy(nIndex));
}
nmWxTimeDependentSkin oDialog(pWell, this);
oDialog.setWindowModality(Qt::WindowModal);
if (oDialog.exec() != QDialog::Accepted)
{
// 第三步:取消时恢复数量和内容,保证会话工作副本也具备回滚语义。
while (pWell->getPerforationCount() >
vecOriginalPerforations.size())
{
pWell->removePerforation(
pWell->getPerforationCount() - 1);
}
int nCommonCount = qMin(
pWell->getPerforationCount(),
vecOriginalPerforations.size());
for (int nIndex = 0; nIndex < nCommonCount; ++nIndex)
{
pWell->updatePerforation(
nIndex, vecOriginalPerforations[nIndex]);
}
for (int nIndex = nCommonCount;
nIndex < vecOriginalPerforations.size();
++nIndex)
{
pWell->addPerforation(new nmDataPerforation(
vecOriginalPerforations[nIndex]));
}
}
m_pParameterPanel->reloadFromWell();
}
void nmWxWellEditor::slotPanelValidityChanged(bool bValid)
{
Q_UNUSED(bValid);
updateAcceptState();
}
void nmWxWellEditor::slotPanelValidationMessageChanged(
const QString& sMessage)
{
m_sPanelValidationMessage = sMessage;
updateAcceptState();
}
void nmWxWellEditor::createUi()
{
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(12, 10, 12, 0);
pMainLayout->setSpacing(8);
// 第一步:左侧固定井信息并滚动参数分组,右侧保持常驻轨迹视图。
m_pMainSplitter = new QSplitter(Qt::Horizontal, this);
m_pMainSplitter->setChildrenCollapsible(false);
QWidget* pParameterContainer = new QWidget(m_pMainSplitter);
QVBoxLayout* pParameterLayout = new QVBoxLayout(pParameterContainer);
pParameterLayout->setContentsMargins(0, 0, 0, 0);
pParameterLayout->setSpacing(8);
QScrollArea* pScrollArea = new QScrollArea(pParameterContainer);
pScrollArea->setWidgetResizable(true);
pScrollArea->setFrameShape(QFrame::NoFrame);
m_pParameterPanel = new nmWellParameterPanel(this, pScrollArea);
pParameterLayout->addWidget(
createWellInformationWidget(pParameterContainer));
m_pWellTypeComboBox->addItem(
tr("Vertical well"), static_cast<int>(Vertical_Well));
m_pWellTypeComboBox->addItem(
tr("Fractured vertical well"),
static_cast<int>(Vertical_Fractured_Well));
m_pWellTypeComboBox->addItem(
tr("Multistage fractured horizontal well"),
static_cast<int>(Horizontal_Fractured_Well));
pScrollArea->setWidget(m_pParameterPanel);
pParameterLayout->addWidget(pScrollArea, 1);
// 第二步:右侧轨迹视图占据剩余空间,避免参数区拉伸破坏绘图比例。
m_pTrajectoryDisplay =
new nmWxWellboreTrajectoryDisplay(m_pMainSplitter);
m_pMainSplitter->addWidget(pParameterContainer);
m_pMainSplitter->addWidget(m_pTrajectoryDisplay);
m_pMainSplitter->setStretchFactor(0, 0);
m_pMainSplitter->setStretchFactor(1, 1);
QList<int> listSizes;
listSizes << 410 << 730;
m_pMainSplitter->setSizes(listSizes);
// 第三步:底部命令区跨越两列,并集中连接编辑状态信号。
pMainLayout->addWidget(m_pMainSplitter, 1);
pMainLayout->addWidget(createFooter());
connect(m_pWellNameLineEdit, SIGNAL(textChanged(QString)),
this, SLOT(slotWellNameEdited(QString)));
connect(m_pWellTypeComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(slotWellTypeChanged(int)));
connect(m_pParameterPanel, SIGNAL(sigValidityChanged(bool)),
this, SLOT(slotPanelValidityChanged(bool)));
connect(m_pParameterPanel,
SIGNAL(sigValidationMessageChanged(QString)),
this, SLOT(slotPanelValidationMessageChanged(QString)));
}
QWidget* nmWxWellEditor::createWellInformationWidget(QWidget* pParent)
{
QGroupBox* pInformationGroup = new QGroupBox(
tr("Well information"), pParent);
QGridLayout* pInformationLayout = new QGridLayout(pInformationGroup);
pInformationLayout->setContentsMargins(8, 15, 8, 10);
pInformationLayout->setHorizontalSpacing(6);
pInformationLayout->setVerticalSpacing(6);
pInformationLayout->setColumnStretch(0, 0);
pInformationLayout->setColumnStretch(1, 1);
QLabel* pCodeLabel = new QLabel(tr("Well number"), pInformationGroup);
QLabel* pNameLabel = new QLabel(tr("Well name"), pInformationGroup);
QLabel* pTypeLabel = new QLabel(tr("Well type"), pInformationGroup);
pCodeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pNameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pTypeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_pWellCodeLineEdit = new QLineEdit(pInformationGroup);
m_pWellNameLineEdit = new QLineEdit(pInformationGroup);
m_pWellTypeComboBox = new QComboBox(pInformationGroup);
m_pWellCodeLineEdit->setReadOnly(true);
m_pWellCodeLineEdit->setToolTip(
tr("Project-level unique well identifier"));
QList<QWidget*> listEditors;
listEditors << m_pWellCodeLineEdit
<< m_pWellNameLineEdit
<< m_pWellTypeComboBox;
for (int nIndex = 0; nIndex < listEditors.size(); ++nIndex)
{
listEditors[nIndex]->setFixedHeight(
nmParameterField::editorHeight());
listEditors[nIndex]->setMinimumWidth(
nmParameterField::editorMinimumWidth());
listEditors[nIndex]->setSizePolicy(
QSizePolicy::Expanding, QSizePolicy::Fixed);
}
pInformationLayout->addWidget(pCodeLabel, 0, 0);
pInformationLayout->addWidget(m_pWellCodeLineEdit, 0, 1);
pInformationLayout->addWidget(pNameLabel, 1, 0);
pInformationLayout->addWidget(m_pWellNameLineEdit, 1, 1);
pInformationLayout->addWidget(pTypeLabel, 2, 0);
pInformationLayout->addWidget(m_pWellTypeComboBox, 2, 1);
return pInformationGroup;
}
QWidget* nmWxWellEditor::createFooter()
{
QWidget* pFooter = new QWidget(this);
QHBoxLayout* pFooterLayout = new QHBoxLayout(pFooter);
pFooterLayout->setContentsMargins(4, 5, 4, 5);
pFooterLayout->setSpacing(8);
// 左侧保留时间变表皮开关和详情入口。
m_pTimeDependentCheckBox = new QCheckBox(
tr("Time-dependent skin"), pFooter);
m_pTimeDependentButton = new QToolButton(pFooter);
QString sIconDir = QCoreApplication::applicationDirPath()
.section('/', 0, -2) + "/Res/Icon/";
m_pTimeDependentButton->setIcon(
QIcon(sIconDir + "NmAnalDesign3.png"));
m_pTimeDependentButton->setIconSize(QSize(20, 20));
m_pTimeDependentButton->setFixedSize(26, 26);
m_pTimeDependentButton->setAutoRaise(true);
m_pTimeDependentButton->setToolTip(
tr("Edit time-dependent skin"));
m_pTimeDependentButton->setEnabled(false);
// 中间状态区使用主题调色板,仅将错误文字标红。
m_pStatusLabel = new QLabel(pFooter);
m_pStatusLabel->setWordWrap(true);
QPalette oStatusPalette = m_pStatusLabel->palette();
oStatusPalette.setColor(QPalette::WindowText, QColor(Qt::red));
m_pStatusLabel->setPalette(oStatusPalette);
// 右侧使用标准确定和取消角色,维持平台统一交互。
m_pButtonBox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal,
pFooter);
QPushButton* pOkButton =
m_pButtonBox->button(QDialogButtonBox::Ok);
QPushButton* pCancelButton =
m_pButtonBox->button(QDialogButtonBox::Cancel);
if (pOkButton != nullptr)
{
pOkButton->setIcon(zxLoadIcon("OK"));
pOkButton->setText(tr("OK"));
}
if (pCancelButton != nullptr)
{
pCancelButton->setIcon(zxLoadIcon("Cancel"));
pCancelButton->setText(tr("Cancel"));
}
pFooterLayout->addWidget(m_pTimeDependentCheckBox);
pFooterLayout->addWidget(m_pTimeDependentButton);
pFooterLayout->addWidget(m_pStatusLabel, 1);
pFooterLayout->addWidget(m_pButtonBox);
connect(m_pTimeDependentCheckBox, SIGNAL(toggled(bool)),
this, SLOT(slotTimeDependentToggled(bool)));
connect(m_pTimeDependentButton, SIGNAL(clicked()),
this, SLOT(slotEditTimeDependentSkin()));
connect(m_pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
return pFooter;
}
void nmWxWellEditor::createController()
{
// 控制器持有当前工作副本指针,井型切换后必须销毁并重新绑定。
delete m_pWellEditorController;
m_pWellEditorController = nullptr;
if (m_pSession == nullptr || m_pSession->currentWell() == nullptr ||
m_pTrajectoryDisplay == nullptr)
{
return;
}
m_pWellEditorController = new nmWellEditorController(
m_pSession->currentWell(),
m_pTrajectoryDisplay,
this);
setupControllerConnections();
}
void nmWxWellEditor::setupControllerConnections()
{
if (m_pWellEditorController == nullptr ||
m_pTrajectoryDisplay == nullptr)
{
return;
}
// 第一步:工具栏只发出模式请求,由控制器决定具体编辑行为。
connect(m_pTrajectoryDisplay, SIGNAL(requestedEditWellMode(int)),
m_pWellEditorController, SLOT(onRequestEditWellMode(int)));
connect(m_pTrajectoryDisplay,
SIGNAL(requestedEditPerforationsMode(int)),
m_pWellEditorController,
SLOT(onRequestEditPerforationsMode(int)));
connect(m_pTrajectoryDisplay,
SIGNAL(requestedNewPerforationMode(int)),
m_pWellEditorController,
SLOT(onRequestNewPerforationMode(int)));
connect(m_pTrajectoryDisplay,
SIGNAL(requestedDeletePerforationMode(int)),
m_pWellEditorController,
SLOT(onRequestDeletePerforationMode(int)));
connect(m_pTrajectoryDisplay,
SIGNAL(requestedSnapPerforationMode(int)),
m_pWellEditorController,
SLOT(onRequestSnapPerforationMode(int)));
// 第二步:视图产生的几何修改统一交给控制器写入工作副本。
connect(m_pTrajectoryDisplay, SIGNAL(sigClearViewStates()),
m_pWellEditorController, SLOT(slotClearViewStates()));
connect(m_pTrajectoryDisplay, SIGNAL(currentViewChanged(int)),
m_pWellEditorController, SLOT(onViewChanged(int)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigWellboreTrajectoryPointMoved(QPointF)),
m_pWellEditorController,
SLOT(slotWellboreTrajectoryPointMoved(QPointF)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigPerforationDragFinished(nmDataPerforation*,double,double)),
m_pWellEditorController,
SLOT(slotPerforationDragFinished(nmDataPerforation*,double,double)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigTryAddNewPerforation(QPointF,double,double,QLineF)),
m_pWellEditorController,
SLOT(slotTryAddNewPerforation(QPointF,double,double,QLineF)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigTryDeletePerforation(nmDataPerforation*)),
m_pWellEditorController,
SLOT(slotDeletePerforation(nmDataPerforation*)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigFractureGeometryDragFinished(double,double)),
m_pWellEditorController,
SLOT(slotFractureGeometryChanged(double,double)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigRequestFractureRectUpdate(qreal,qreal)),
m_pWellEditorController,
SLOT(slotHandleFractureRectUpdate(qreal,qreal)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigFractureDragFinished(const QMap<nmDataPerforation*,QPair<double,double>>&)),
m_pWellEditorController,
SLOT(slotUpdatePerforations(const QMap<nmDataPerforation*,QPair<double,double>>&)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigFractureHalfLengthChanged(double)),
m_pWellEditorController,
SLOT(slotUpdateFractureHalfLength(double)));
connect(m_pTrajectoryDisplay, SIGNAL(sigWellboreDragFinished(QPointF)),
m_pWellEditorController, SLOT(slotUpdateWellborePos(QPointF)));
connect(m_pTrajectoryDisplay,
SIGNAL(sigFractureGeometryChanged(double,double)),
m_pWellEditorController,
SLOT(slotHFWellFractureGeometryChanged(double,double)));
}
bool nmWxWellEditor::validateWellName(QString& sTrimmedName,
QString& sError) const
{
// 第一步:规范化用户输入并检查空值及文件名规则。
sTrimmedName = m_pWellNameLineEdit != nullptr
? m_pWellNameLineEdit->text().trimmed() : QString();
if (sTrimmedName.isEmpty())
{
sError = tr("Well name cannot be empty.");
return false;
}
if (!isLegalFileName(sTrimmedName))
{
sError = tr("Well name contains invalid file name characters.");
return false;
}
// 第二步:只与上下文中的其他井比较,允许当前井保持原名称。
QStringList listOtherNames = m_pSession != nullptr
? m_pSession->otherWellNames() : QStringList();
for (int nIndex = 0; nIndex < listOtherNames.size(); ++nIndex)
{
if (QString::compare(sTrimmedName,
listOtherNames[nIndex].trimmed(),
Qt::CaseInsensitive) == 0)
{
sError = tr("A well with this name already exists.");
return false;
}
}
sError.clear();
return true;
}
bool nmWxWellEditor::isLegalFileName(const QString& sWellName) const
{
// 第一步:拒绝特殊路径片段、非法字符、控制字符和结尾句点。
if (sWellName == "." || sWellName == ".." ||
sWellName.endsWith('.'))
{
return false;
}
if (sWellName.contains(QRegExp("[<>:\"/\\\\|?*]")))
{
return false;
}
for (int nIndex = 0; nIndex < sWellName.size(); ++nIndex)
{
if (sWellName[nIndex].unicode() < 32)
{
return false;
}
}
// 第二步Windows保留设备名即使带扩展名也不能作为井文件名称。
QString sStem = sWellName.section('.', 0, 0).toUpper();
QRegExp oReserved(
"^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$");
return !oReserved.exactMatch(sStem);
}
void nmWxWellEditor::updateAcceptState()
{
if (m_pButtonBox == nullptr)
{
return;
}
// 第一步:汇总井名和当前参数面板状态,统一控制确认入口。
QString sWellName;
QString sNameError;
bool bNameValid = m_pSession != nullptr &&
validateWellName(sWellName, sNameError);
bool bPanelValid = m_pParameterPanel != nullptr &&
m_pParameterPanel->isInputValid();
QPushButton* pOkButton =
m_pButtonBox->button(QDialogButtonBox::Ok);
if (pOkButton != nullptr)
{
pOkButton->setEnabled(
m_bInitialized && bNameValid && bPanelValid);
}
// 第二步:底部只显示最高优先级错误,避免多处提示互相覆盖。
if (!bNameValid)
{
m_pStatusLabel->setText(sNameError);
}
else if (!bPanelValid)
{
m_pStatusLabel->setText(m_sPanelValidationMessage.isEmpty()
? tr("Please correct the invalid parameter values.")
: m_sPanelValidationMessage);
}
else
{
m_pStatusLabel->clear();
}
}