|
|
#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 "nmWellPressureFlowPage.h"
|
|
|
#include "nmWxTimeDependentSkin.h"
|
|
|
#include "nmWxWellboreTrajectoryDisplay.h"
|
|
|
#include "ZxBaseUtil.h"
|
|
|
|
|
|
#include <QCheckBox>
|
|
|
#include <QButtonGroup>
|
|
|
#include <QComboBox>
|
|
|
#include <QCoreApplication>
|
|
|
#include <QDialogButtonBox>
|
|
|
#include <QFrame>
|
|
|
#include <QFont>
|
|
|
#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 <QStackedWidget>
|
|
|
#include <QToolButton>
|
|
|
#include <QVector>
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
nmWxWellEditor::nmWxWellEditor(const nmWellEditContext& oContext,
|
|
|
QWidget* pParent)
|
|
|
: iDlgBase(pParent),
|
|
|
m_pSession(new nmWellEditorSession(oContext)),
|
|
|
m_pCategoryButtonGroup(nullptr),
|
|
|
m_pStackedWidget(nullptr),
|
|
|
m_pPressureFlowPage(nullptr),
|
|
|
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_pFooterHelpButton(nullptr),
|
|
|
m_pButtonBox(nullptr),
|
|
|
m_pStatusLabel(nullptr),
|
|
|
m_pMainSplitter(nullptr),
|
|
|
m_nCurrentPage(NM_WELL_EDITOR_PAGE_PARAMETERS),
|
|
|
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_pStackedWidget;
|
|
|
m_pStackedWidget = nullptr;
|
|
|
m_pPressureFlowPage = nullptr;
|
|
|
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_pTrajectoryDisplay->selectDefaultViewForCurrentWell();
|
|
|
|
|
|
m_bInitialized = true;
|
|
|
m_pPressureFlowPage->setWell(pWell);
|
|
|
m_pStackedWidget->setCurrentIndex(
|
|
|
NM_WELL_EDITOR_PAGE_PARAMETERS);
|
|
|
m_nCurrentPage = NM_WELL_EDITOR_PAGE_PARAMETERS;
|
|
|
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();
|
|
|
m_pPressureFlowPage->setWell(pWell);
|
|
|
updateAcceptState();
|
|
|
}
|
|
|
|
|
|
void nmWxWellEditor::slotCategoryButtonClicked(int nPage)
|
|
|
{
|
|
|
if (!m_bInitialized || m_pStackedWidget == nullptr ||
|
|
|
nPage < 0 || nPage >= NM_WELL_EDITOR_PAGE_COUNT)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (nPage == m_nCurrentPage)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 查看页只读取当前工作副本,不提交或校验参数页中的临时输入。
|
|
|
if (nPage == NM_WELL_EDITOR_PAGE_PRESSURE_FLOW)
|
|
|
{
|
|
|
reloadPressureFlowPage();
|
|
|
}
|
|
|
m_pStackedWidget->setCurrentIndex(nPage);
|
|
|
m_nCurrentPage = nPage;
|
|
|
}
|
|
|
|
|
|
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::reloadPressureFlowPage()
|
|
|
{
|
|
|
if (m_pPressureFlowPage == nullptr || m_pSession == nullptr)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
nmDataWellBase* pWell = m_pSession->currentWell();
|
|
|
m_pPressureFlowPage->setWell(pWell);
|
|
|
m_pPressureFlowPage->refreshData();
|
|
|
}
|
|
|
|
|
|
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(0);
|
|
|
pMainLayout->addWidget(createCategoryBar());
|
|
|
|
|
|
m_pStackedWidget = new QStackedWidget(this);
|
|
|
|
|
|
// 第一步:井参数页完整保留原有参数区、轨迹视图和分割比例。
|
|
|
QWidget* pParameterPage = new QWidget(m_pStackedWidget);
|
|
|
QVBoxLayout* pPageLayout = new QVBoxLayout(pParameterPage);
|
|
|
pPageLayout->setContentsMargins(0, 6, 0, 0);
|
|
|
pPageLayout->setSpacing(8);
|
|
|
|
|
|
m_pMainSplitter = new QSplitter(Qt::Horizontal, pParameterPage);
|
|
|
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_pTrajectoryDisplay->set3DViewVisible(false);
|
|
|
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);
|
|
|
pPageLayout->addWidget(m_pMainSplitter, 1);
|
|
|
|
|
|
// 第二步:只读压力流量页与参数页常驻同一堆栈,切换时不重建控件。
|
|
|
m_pPressureFlowPage = new nmWellPressureFlowPage(m_pStackedWidget);
|
|
|
m_pStackedWidget->addWidget(pParameterPage);
|
|
|
m_pStackedWidget->addWidget(m_pPressureFlowPage);
|
|
|
m_pStackedWidget->setCurrentIndex(
|
|
|
NM_WELL_EDITOR_PAGE_PARAMETERS);
|
|
|
pMainLayout->addWidget(m_pStackedWidget, 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::createCategoryBar()
|
|
|
{
|
|
|
QGroupBox* pCategoryBar = new QGroupBox(this);
|
|
|
QHBoxLayout* pBarLayout = new QHBoxLayout(pCategoryBar);
|
|
|
pBarLayout->setContentsMargins(3, 3, 3, 3);
|
|
|
pBarLayout->setSpacing(0);
|
|
|
|
|
|
m_pCategoryButtonGroup = new QButtonGroup(this);
|
|
|
|
|
|
QHBoxLayout* pBasicLayout = nullptr;
|
|
|
QWidget* pBasicGroup = createRibbonGroup(
|
|
|
tr("Basic"), pCategoryBar, pBasicLayout);
|
|
|
pBasicLayout->insertWidget(0, createCategoryButton(
|
|
|
NM_WELL_EDITOR_PAGE_PARAMETERS,
|
|
|
tr("Well parameters"),
|
|
|
"NmWell",
|
|
|
pBasicGroup));
|
|
|
pBarLayout->addWidget(pBasicGroup);
|
|
|
pBarLayout->addWidget(createRibbonSeparator(pCategoryBar));
|
|
|
|
|
|
QHBoxLayout* pDataLayout = nullptr;
|
|
|
QWidget* pDataGroup = createRibbonGroup(
|
|
|
tr("Data"), pCategoryBar, pDataLayout);
|
|
|
pDataLayout->insertWidget(0, createCategoryButton(
|
|
|
NM_WELL_EDITOR_PAGE_PRESSURE_FLOW,
|
|
|
tr("Pressure and flow"),
|
|
|
"tAllData",
|
|
|
pDataGroup));
|
|
|
pBarLayout->addWidget(pDataGroup);
|
|
|
pBarLayout->addWidget(createRibbonSeparator(pCategoryBar));
|
|
|
|
|
|
QHBoxLayout* pHelpLayout = nullptr;
|
|
|
QWidget* pHelpGroup = createRibbonGroup(
|
|
|
tr("Help"), pCategoryBar, pHelpLayout);
|
|
|
pHelpLayout->insertWidget(0, createHelpButton(pHelpGroup));
|
|
|
pBarLayout->addWidget(pHelpGroup);
|
|
|
pBarLayout->addStretch(1);
|
|
|
|
|
|
connect(m_pCategoryButtonGroup, SIGNAL(buttonClicked(int)),
|
|
|
this, SLOT(slotCategoryButtonClicked(int)));
|
|
|
return pCategoryBar;
|
|
|
}
|
|
|
|
|
|
QWidget* nmWxWellEditor::createRibbonGroup(
|
|
|
const QString& sCaption,
|
|
|
QWidget* pParent,
|
|
|
QHBoxLayout*& pCommandLayout)
|
|
|
{
|
|
|
QWidget* pGroupWidget = new QWidget(pParent);
|
|
|
QVBoxLayout* pGroupLayout = new QVBoxLayout(pGroupWidget);
|
|
|
pGroupLayout->setContentsMargins(11, 2, 11, 1);
|
|
|
pGroupLayout->setSpacing(4);
|
|
|
|
|
|
QWidget* pCommandWidget = new QWidget(pGroupWidget);
|
|
|
pCommandLayout = new QHBoxLayout(pCommandWidget);
|
|
|
pCommandLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
pCommandLayout->setSpacing(6);
|
|
|
pCommandLayout->addStretch();
|
|
|
pGroupLayout->addWidget(pCommandWidget, 1);
|
|
|
|
|
|
QLabel* pCaptionLabel = new QLabel(sCaption, pGroupWidget);
|
|
|
pCaptionLabel->setAlignment(Qt::AlignCenter);
|
|
|
pCaptionLabel->setFixedHeight(16);
|
|
|
QFont oCaptionFont = pCaptionLabel->font();
|
|
|
oCaptionFont.setUnderline(true);
|
|
|
pCaptionLabel->setFont(oCaptionFont);
|
|
|
QPalette oCaptionPalette = pCaptionLabel->palette();
|
|
|
oCaptionPalette.setColor(
|
|
|
QPalette::WindowText,
|
|
|
pGroupWidget->palette().color(QPalette::Mid));
|
|
|
pCaptionLabel->setPalette(oCaptionPalette);
|
|
|
pGroupLayout->addWidget(pCaptionLabel);
|
|
|
return pGroupWidget;
|
|
|
}
|
|
|
|
|
|
QFrame* nmWxWellEditor::createRibbonSeparator(QWidget* pParent)
|
|
|
{
|
|
|
QFrame* pSeparator = new QFrame(pParent);
|
|
|
pSeparator->setFrameShape(QFrame::VLine);
|
|
|
pSeparator->setFrameShadow(QFrame::Plain);
|
|
|
pSeparator->setLineWidth(1);
|
|
|
QPalette oSeparatorPalette = pSeparator->palette();
|
|
|
oSeparatorPalette.setColor(
|
|
|
QPalette::WindowText,
|
|
|
pParent->palette().color(QPalette::Mid));
|
|
|
pSeparator->setPalette(oSeparatorPalette);
|
|
|
pSeparator->setSizePolicy(
|
|
|
QSizePolicy::Fixed, QSizePolicy::Expanding);
|
|
|
return pSeparator;
|
|
|
}
|
|
|
|
|
|
QToolButton* nmWxWellEditor::createCategoryButton(
|
|
|
int nPage,
|
|
|
const QString& sText,
|
|
|
const QString& sIconName,
|
|
|
QWidget* pParent)
|
|
|
{
|
|
|
QToolButton* pButton = new QToolButton(pParent);
|
|
|
pButton->setText(sText);
|
|
|
pButton->setIcon(zxLoadIcon(sIconName));
|
|
|
pButton->setIconSize(QSize(28, 28));
|
|
|
pButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
|
pButton->setCheckable(false);
|
|
|
pButton->setSizePolicy(
|
|
|
QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
|
m_pCategoryButtonGroup->addButton(pButton, nPage);
|
|
|
return pButton;
|
|
|
}
|
|
|
|
|
|
QToolButton* nmWxWellEditor::createHelpButton(QWidget* pParent)
|
|
|
{
|
|
|
QToolButton* pButton = new QToolButton(pParent);
|
|
|
pButton->setText(tr("Help"));
|
|
|
pButton->setIcon(zxLoadIcon("Help"));
|
|
|
pButton->setIconSize(QSize(28, 28));
|
|
|
pButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
|
pButton->setSizePolicy(
|
|
|
QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
|
connect(pButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
|
|
|
return pButton;
|
|
|
}
|
|
|
|
|
|
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, 8);
|
|
|
pInformationLayout->setColumnStretch(2, 5);
|
|
|
pInformationLayout->setColumnMinimumWidth(
|
|
|
1, nmParameterField::editorMinimumWidth());
|
|
|
pInformationLayout->setColumnMinimumWidth(
|
|
|
2, nmParameterField::unitMinimumWidth());
|
|
|
|
|
|
QLabel* pCodeLabel = new QLabel(tr("Well number"), pInformationGroup);
|
|
|
QLabel* pNameLabel = new QLabel(tr("Well name"), pInformationGroup);
|
|
|
QLabel* pTypeLabel = new QLabel(tr("Well type"), pInformationGroup);
|
|
|
QLabel* pTimeDependentLabel = new QLabel(
|
|
|
tr("Time-dependent skin"), pInformationGroup);
|
|
|
pCodeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
pNameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
pTypeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
pTimeDependentLabel->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);
|
|
|
}
|
|
|
|
|
|
// 时间变表皮属于井级配置,开关和详情入口共同放在值列。
|
|
|
QWidget* pTimeDependentEditor = new QWidget(pInformationGroup);
|
|
|
QHBoxLayout* pTimeDependentLayout = new QHBoxLayout(
|
|
|
pTimeDependentEditor);
|
|
|
pTimeDependentLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
pTimeDependentLayout->setSpacing(4);
|
|
|
m_pTimeDependentCheckBox = new QCheckBox(pTimeDependentEditor);
|
|
|
m_pTimeDependentButton = new QToolButton(pTimeDependentEditor);
|
|
|
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);
|
|
|
pTimeDependentLayout->addWidget(m_pTimeDependentCheckBox);
|
|
|
pTimeDependentLayout->addWidget(m_pTimeDependentButton);
|
|
|
pTimeDependentLayout->addStretch(1);
|
|
|
|
|
|
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);
|
|
|
pInformationLayout->addWidget(pTimeDependentLabel, 3, 0);
|
|
|
pInformationLayout->addWidget(pTimeDependentEditor, 3, 1);
|
|
|
|
|
|
connect(m_pTimeDependentCheckBox, SIGNAL(toggled(bool)),
|
|
|
this, SLOT(slotTimeDependentToggled(bool)));
|
|
|
connect(m_pTimeDependentButton, SIGNAL(clicked()),
|
|
|
this, SLOT(slotEditTimeDependentSkin()));
|
|
|
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_pFooterHelpButton = new QToolButton(pFooter);
|
|
|
m_pFooterHelpButton->setText(tr("Help"));
|
|
|
m_pFooterHelpButton->setIcon(zxLoadIcon("Help"));
|
|
|
m_pFooterHelpButton->setToolButtonStyle(
|
|
|
Qt::ToolButtonTextBesideIcon);
|
|
|
m_pFooterHelpButton->setAutoRaise(true);
|
|
|
|
|
|
// 中间状态区使用主题调色板,仅将错误文字标红。
|
|
|
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_pFooterHelpButton);
|
|
|
pFooterLayout->addWidget(m_pStatusLabel, 1);
|
|
|
pFooterLayout->addWidget(m_pButtonBox);
|
|
|
|
|
|
connect(m_pFooterHelpButton, SIGNAL(clicked()),
|
|
|
this, SLOT(slotHelp()));
|
|
|
connect(m_pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
|
|
connect(m_pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
|
|
return pFooter;
|
|
|
}
|
|
|
|
|
|
void nmWxWellEditor::slotHelp()
|
|
|
{
|
|
|
ZxBaseUtil::startHelp();
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
}
|
|
|
}
|