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

825 lines
27 KiB
C++

#include "nmWellParameterPanel.h"
#include "nmDataAttribute.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataPerforation.h"
#include "nmDataWellBase.h"
#include "nmParameterField.h"
#include "nmWellParameterCatalog.h"
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLayoutItem>
#include <QLineEdit>
#include <QPalette>
#include <QtGlobal>
#include <QVBoxLayout>
#include <QVector>
namespace
{
struct PerforationCandidate
{
QString m_sName;
double m_dStart;
double m_dEnd;
double m_dSkin;
};
}
nmWellParameterPanel::nmWellParameterPanel(
nmIParameterUnitService* pUnitService,
QWidget* pParent)
: QWidget(pParent),
m_pUnitService(pUnitService),
m_pWell(nullptr),
m_pMainLayout(new QVBoxLayout(this)),
m_pPerforationComboBox(nullptr),
m_listFields(),
m_mapFields(),
m_nCurrentPerforationIndex(0),
m_bReloading(false),
m_bUpdatingModel(false)
{
// 参数分组使用透明背景,由面板统一填充主题基础色。
setAutoFillBackground(true);
setBackgroundRole(QPalette::Base);
m_pMainLayout->setContentsMargins(8, 8, 8, 8);
m_pMainLayout->setSpacing(10);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
}
nmWellParameterPanel::~nmWellParameterPanel()
{
// 井对象由会话拥有,析构时只解除连接,不在面板中释放。
if (m_pWell != nullptr)
{
disconnect(m_pWell, nullptr, this, nullptr);
}
m_pUnitService = nullptr;
m_pWell = nullptr;
}
bool nmWellParameterPanel::setWellData(nmDataWellBase* pWell,
QString& sError)
{
if (pWell == nullptr)
{
sError = tr("The well working copy is unavailable.");
return false;
}
if (m_pWell != nullptr)
{
disconnect(m_pWell, nullptr, this, nullptr);
}
// 第一步:井型切换时只重建一次目录分组。
m_pWell = pWell;
m_nCurrentPerforationIndex = 0;
clearGroups();
QList<nmWellParameterGroupInfo> listGroups =
nmWellParameterCatalog::createGroups(m_pWell->getWellType());
for (int nIndex = 0; nIndex < listGroups.size(); ++nIndex)
{
if (!buildGroup(listGroups[nIndex], sError))
{
return false;
}
}
m_pMainLayout->addStretch(1);
// 第二步:数据交互和字段刷新复用现有控件,不重复创建窗口对象。
connect(m_pWell, SIGNAL(sigWellDataChanged()),
this, SLOT(slotWellDataChanged()));
connect(m_pWell, SIGNAL(sigParameterChanged()),
this, SLOT(slotWellDataChanged()));
reloadPerforationSelector();
reloadFromWell();
sError.clear();
return true;
}
bool nmWellParameterPanel::commitPendingEdits(QString& sError)
{
// 第一步:先收集并校验全部字段,任何错误都不能产生部分写入。
QMap<QString, QVariant> mapValues;
QVector<nmDataPerforation> vecPerforations;
if (!collectValues(mapValues, sError, &vecPerforations))
{
emit sigValidityChanged(false);
emit sigValidationMessageChanged(sError);
return false;
}
// 第二步:普通属性直接更新;井筒范围和射孔留给同一次批量提交。
QString sBottomholeMdId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_BOTTOMHOLE_MD);
QString sWellLengthId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_LENGTH);
bool bWellboreSnapshotChanged = false;
m_bUpdatingModel = true;
for (int nIndex = 0; nIndex < m_listFields.size(); ++nIndex)
{
nmParameterField* pField = m_listFields[nIndex];
if (pField == nullptr || pField->isEnum())
{
continue;
}
nmDataAttribute* pAttribute = nmWellParameterCatalog::attribute(
m_pWell,
pField->parameterId(),
m_nCurrentPerforationIndex);
if (pAttribute == nullptr)
{
continue;
}
QVariant oValue = mapValues.value(pField->parameterId());
if (pField->isText())
{
oValue = oValue.toString().trimmed();
}
bool bChanged = pField->isText()
? pAttribute->getValue().toString() != oValue.toString()
: qAbs(pAttribute->getValue().toDouble() - oValue.toDouble()) >
qMax(1.0, qAbs(oValue.toDouble())) * 1.0e-12;
if (bChanged)
{
QString sParameterId = pField->parameterId();
if (sParameterId == sBottomholeMdId ||
sParameterId == sWellLengthId ||
nmWellParameterCatalog::isPerforationParameter(
sParameterId))
{
bWellboreSnapshotChanged = true;
}
else
{
pAttribute->setValue(oValue);
}
}
}
// 第三步:模型跳过井长隐式缩放,原子写入刚刚校验通过的完整快照。
if (bWellboreSnapshotChanged)
{
double dBottomholeMd = mapValues.value(
sBottomholeMdId,
m_pWell->getBottomholeMD().getValue()).toDouble();
double dWellLength = mapValues.value(
sWellLengthId,
m_pWell->getWellLength().getValue()).toDouble();
if (!m_pWell->applyWellboreEdit(
dBottomholeMd, dWellLength, vecPerforations))
{
m_bUpdatingModel = false;
sError = tr("Failed to apply the validated wellbore parameters.");
emit sigValidityChanged(false);
emit sigValidationMessageChanged(sError);
return false;
}
}
m_bUpdatingModel = false;
// 第四步:只更新当前射孔名称,避免提交时重建选择器吞掉切换操作。
updateCurrentPerforationItem();
sError.clear();
emit sigValidityChanged(true);
emit sigValidationMessageChanged(QString());
return true;
}
bool nmWellParameterPanel::isInputValid()
{
QMap<QString, QVariant> mapValues;
QString sError;
return collectValues(mapValues, sError);
}
void nmWellParameterPanel::focusFirstInvalid()
{
// 按界面显示顺序定位错误,使用户无需自行查找红色字段。
for (int nIndex = 0; nIndex < m_listFields.size(); ++nIndex)
{
nmParameterField* pField = m_listFields[nIndex];
if (pField != nullptr && !pField->validate() &&
pField->valueEditor() != nullptr)
{
pField->valueEditor()->setFocus();
pField->valueEditor()->selectAll();
return;
}
}
// 非当前射孔出错时保留未提交输入,仅将焦点移到射孔选择器供用户定位。
if (m_pPerforationComboBox != nullptr &&
!m_pPerforationComboBox->toolTip().isEmpty())
{
m_pPerforationComboBox->setFocus();
}
}
void nmWellParameterPanel::reloadFromWell()
{
if (m_pWell == nullptr || m_bUpdatingModel)
{
return;
}
// 程序回填期间屏蔽编辑槽,避免刷新再次触发模型提交。
m_bReloading = true;
for (int nIndex = 0; nIndex < m_listFields.size(); ++nIndex)
{
nmParameterField* pField = m_listFields[nIndex];
nmDataAttribute* pAttribute = pField != nullptr
? nmWellParameterCatalog::attribute(
m_pWell,
pField->parameterId(),
m_nCurrentPerforationIndex)
: nullptr;
// 目录可复用于多个派生井型,不存在的数据属性直接隐藏。
if (pField != nullptr)
{
pField->setFieldVisible(pAttribute != nullptr);
}
if (pField != nullptr && pAttribute != nullptr)
{
pField->setExternalValidationError(QString());
pField->setBaseValue(pAttribute->getValue());
}
}
m_bReloading = false;
emit sigValidityChanged(isInputValid());
}
void nmWellParameterPanel::slotFieldValueEdited()
{
if (m_bReloading)
{
return;
}
// 输入过程中只更新状态,避免每个按键都重建裂缝或刷新轨迹。
bool bValid = isInputValid();
emit sigValidityChanged(bValid);
if (bValid)
{
emit sigValidationMessageChanged(QString());
}
}
void nmWellParameterPanel::slotFieldEditingFinished()
{
if (m_bReloading)
{
return;
}
// 失去焦点时一次性写工作副本,轨迹只响应最终有效值。
QString sError;
if (!commitPendingEdits(sError))
{
focusFirstInvalid();
}
}
void nmWellParameterPanel::slotPerforationChanged(int nIndex)
{
if (m_bReloading || m_pPerforationComboBox == nullptr || nIndex < 0)
{
return;
}
QVariant oPerforationIndex =
m_pPerforationComboBox->itemData(nIndex);
if (!oPerforationIndex.isValid())
{
return;
}
int nTargetPerforationIndex = oPerforationIndex.toInt();
if (nTargetPerforationIndex == m_nCurrentPerforationIndex)
{
return;
}
// 第一步:离开当前射孔前提交输入,失败则恢复原选择。
int nPreviousPerforationIndex = m_nCurrentPerforationIndex;
QString sError;
if (!commitPendingEdits(sError))
{
int nPreviousComboIndex =
m_pPerforationComboBox->findData(
nPreviousPerforationIndex);
m_bReloading = true;
if (nPreviousComboIndex >= 0)
{
m_pPerforationComboBox->setCurrentIndex(
nPreviousComboIndex);
}
m_bReloading = false;
focusFirstInvalid();
return;
}
// 第二步:切换成功后复用现有字段显示目标射孔数据。
m_nCurrentPerforationIndex = nTargetPerforationIndex;
reloadFromWell();
}
void nmWellParameterPanel::slotWellDataChanged()
{
if (m_bUpdatingModel)
{
return;
}
// 轨迹控制器可能修改射孔集合,选择器和字段必须一起同步。
reloadPerforationSelector();
reloadFromWell();
}
void nmWellParameterPanel::clearGroups()
{
m_listFields.clear();
m_mapFields.clear();
m_pPerforationComboBox = nullptr;
// 字段对象以分组为QObject父对象删除分组即可统一释放字段和控件。
while (m_pMainLayout->count() > 0)
{
QLayoutItem* pItem = m_pMainLayout->takeAt(0);
if (pItem->widget() != nullptr)
{
delete pItem->widget();
}
delete pItem;
}
}
bool nmWellParameterPanel::buildGroup(
const nmWellParameterGroupInfo& oGroupInfo,
QString& sError)
{
// 第一步:建立与通用参数字段一致的标签、值和单位三列布局。
QGroupBox* pGroupBox = new QGroupBox(oGroupInfo.m_sTitle, this);
pGroupBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QGridLayout* pFieldLayout = new QGridLayout(pGroupBox);
pFieldLayout->setContentsMargins(8, 15, 8, 10);
pFieldLayout->setHorizontalSpacing(6);
pFieldLayout->setVerticalSpacing(6);
pFieldLayout->setColumnStretch(0, 0);
pFieldLayout->setColumnStretch(1, 8);
pFieldLayout->setColumnStretch(2, 5);
pFieldLayout->setColumnMinimumWidth(
1, nmParameterField::editorMinimumWidth());
pFieldLayout->setColumnMinimumWidth(
2, nmParameterField::unitMinimumWidth());
// 第二步:射孔选择器只占第二列,不侵入单位列。
int nRowOffset = 0;
if (oGroupInfo.m_bPerforationGroup)
{
QLabel* pSelectorLabel = new QLabel(tr("Perforation"), pGroupBox);
pSelectorLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_pPerforationComboBox = new QComboBox(pGroupBox);
m_pPerforationComboBox->setFixedHeight(
nmParameterField::editorHeight());
pFieldLayout->addWidget(pSelectorLabel, 0, 0);
pFieldLayout->addWidget(m_pPerforationComboBox, 0, 1);
connect(m_pPerforationComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(slotPerforationChanged(int)));
nRowOffset = 1;
}
// 第三步按目录顺序创建字段并建立稳定ID到字段对象的索引。
for (int nIndex = 0; nIndex < oGroupInfo.m_listFields.size(); ++nIndex)
{
nmParameterField* pField = new nmParameterField(
oGroupInfo.m_listFields[nIndex],
m_pUnitService,
pGroupBox);
if (!pField->initialize(pFieldLayout,
nIndex + nRowOffset,
0,
sError))
{
delete pGroupBox;
return false;
}
pField->setValueRightAligned(!pField->isText());
if (pField->valueEditor() != nullptr)
{
connect(pField->valueEditor(), SIGNAL(textChanged(QString)),
this, SLOT(slotFieldValueEdited()));
connect(pField->valueEditor(), SIGNAL(editingFinished()),
this, SLOT(slotFieldEditingFinished()));
}
m_listFields.append(pField);
m_mapFields.insert(pField->parameterId(), pField);
}
m_pMainLayout->addWidget(pGroupBox);
return true;
}
void nmWellParameterPanel::reloadPerforationSelector()
{
if (m_pPerforationComboBox == nullptr || m_pWell == nullptr)
{
return;
}
// 第一步:增量同步列表,避免清空控件导致焦点切换和点击事件失效。
bool bWasReloading = m_bReloading;
m_bReloading = true;
int nPerforationCount = m_pWell->getPerforationCount();
if (nPerforationCount <= 0)
{
while (m_pPerforationComboBox->count() > 1)
{
m_pPerforationComboBox->removeItem(
m_pPerforationComboBox->count() - 1);
}
if (m_pPerforationComboBox->count() <= 0)
{
m_pPerforationComboBox->addItem(tr("No perforations"));
}
else
{
m_pPerforationComboBox->setItemText(
0, tr("No perforations"));
m_pPerforationComboBox->setItemData(0, QVariant());
}
m_pPerforationComboBox->setEnabled(false);
m_nCurrentPerforationIndex = -1;
m_pPerforationComboBox->setCurrentIndex(0);
}
else
{
while (m_pPerforationComboBox->count() > nPerforationCount)
{
m_pPerforationComboBox->removeItem(
m_pPerforationComboBox->count() - 1);
}
for (int nIndex = 0; nIndex < nPerforationCount; ++nIndex)
{
QString sName = perforationDisplayName(nIndex);
if (nIndex >= m_pPerforationComboBox->count())
{
m_pPerforationComboBox->addItem(sName, nIndex);
}
else
{
if (m_pPerforationComboBox->itemText(nIndex) != sName)
{
m_pPerforationComboBox->setItemText(nIndex, sName);
}
QVariant oItemData =
m_pPerforationComboBox->itemData(nIndex);
if (!oItemData.isValid() || oItemData.toInt() != nIndex)
{
m_pPerforationComboBox->setItemData(nIndex, nIndex);
}
}
}
// 第二步集合变化后约束业务索引再通过itemData定位界面项。
m_pPerforationComboBox->setEnabled(true);
m_nCurrentPerforationIndex = qBound(
0, m_nCurrentPerforationIndex, nPerforationCount - 1);
int nCurrentComboIndex = m_pPerforationComboBox->findData(
m_nCurrentPerforationIndex);
if (nCurrentComboIndex >= 0 &&
m_pPerforationComboBox->currentIndex() !=
nCurrentComboIndex)
{
m_pPerforationComboBox->setCurrentIndex(nCurrentComboIndex);
}
}
m_bReloading = bWasReloading;
}
QString nmWellParameterPanel::perforationDisplayName(
int nPerforationIndex) const
{
nmDataPerforation* pPerforation = m_pWell != nullptr
? m_pWell->getPerforation(nPerforationIndex)
: nullptr;
QString sName = pPerforation != nullptr
? pPerforation->getName().getValue().toString().trimmed()
: QString();
// 旧工程可能没有射孔名称,界面提供稳定的序号回退文本。
return sName.isEmpty()
? tr("Perforation %1").arg(nPerforationIndex + 1)
: sName;
}
void nmWellParameterPanel::updateCurrentPerforationItem()
{
if (m_pPerforationComboBox == nullptr || m_pWell == nullptr ||
m_nCurrentPerforationIndex < 0)
{
return;
}
int nComboIndex = m_pPerforationComboBox->findData(
m_nCurrentPerforationIndex);
if (nComboIndex < 0)
{
return;
}
QString sName = perforationDisplayName(
m_nCurrentPerforationIndex);
if (m_pPerforationComboBox->itemText(nComboIndex) == sName)
{
return;
}
// 只修改文本并屏蔽选择信号,不改变当前索引和弹出列表状态。
bool bWasReloading = m_bReloading;
m_bReloading = true;
m_pPerforationComboBox->setItemText(nComboIndex, sName);
m_bReloading = bWasReloading;
}
bool nmWellParameterPanel::collectValues(
QMap<QString, QVariant>& mapValues,
QString& sError,
QVector<nmDataPerforation>* pVecPerforations)
{
// 第一步:清除上一次跨字段校验留下的错误,重新计算完整状态。
mapValues.clear();
if (m_pPerforationComboBox != nullptr)
{
m_pPerforationComboBox->setToolTip(QString());
}
for (int nIndex = 0; nIndex < m_listFields.size(); ++nIndex)
{
if (m_listFields[nIndex] != nullptr)
{
m_listFields[nIndex]->setExternalValidationError(QString());
}
}
// 第二步:字段统一转换为业务基准单位后写入临时映射。
for (int nIndex = 0; nIndex < m_listFields.size(); ++nIndex)
{
nmParameterField* pField = m_listFields[nIndex];
if (pField == nullptr || !pField->isFieldVisible() ||
pField->isEnum())
{
continue;
}
bool bValid = false;
QVariant oValue = pField->baseValue(bValid);
if (!bValid || !oValue.isValid())
{
sError = tr("Please correct the invalid parameter values.");
return false;
}
mapValues.insert(pField->parameterId(), oValue);
}
// 第三步:单字段合法后再执行依赖多个参数的射孔规则。
if (!validatePerforationValues(
mapValues, sError, pVecPerforations))
{
return false;
}
sError.clear();
return true;
}
bool nmWellParameterPanel::validatePerforationValues(
const QMap<QString, QVariant>& mapValues,
QString& sError,
QVector<nmDataPerforation>* pVecPerforations)
{
if (pVecPerforations != nullptr)
{
pVecPerforations->clear();
}
if (m_pWell == nullptr)
{
return true;
}
// 使用稳定ID读取临时值校验逻辑不依赖界面语言和XML显示名称。
QString sNameId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_NAME);
QString sStartId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_MD_START);
QString sEndId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_MD_END);
QString sSkinId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_SKIN);
QString sBottomholeMdId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_BOTTOMHOLE_MD);
QString sWellLengthId = nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_LENGTH);
int nPerforationCount = m_pWell->getPerforationCount();
if (nPerforationCount <= 0)
{
if (dynamic_cast<nmDataHorizontalFracturedWell*>(m_pWell) != nullptr)
{
sError = tr(
"A multistage fractured horizontal well requires at least one perforation.");
if (m_pPerforationComboBox != nullptr)
{
m_pPerforationComboBox->setToolTip(sError);
}
return false;
}
return true;
}
// 第一步:输入过程只构造轻量候选值,正式提交时才按需深拷贝完整射孔。
QVector<PerforationCandidate> vecCandidates;
vecCandidates.reserve(nPerforationCount);
if (pVecPerforations != nullptr)
{
pVecPerforations->reserve(nPerforationCount);
}
for (int nIndex = 0; nIndex < nPerforationCount; ++nIndex)
{
nmDataPerforation* pPerforation = m_pWell->getPerforation(nIndex);
if (pPerforation == nullptr)
{
sError = tr("Please correct the invalid parameter values.");
return false;
}
PerforationCandidate oCandidate;
oCandidate.m_sName =
pPerforation->getName().getValue().toString().trimmed();
oCandidate.m_dStart =
pPerforation->getMdStart().getValue().toDouble();
oCandidate.m_dEnd =
pPerforation->getMdEnd().getValue().toDouble();
oCandidate.m_dSkin =
pPerforation->getSkin().getValue().toDouble();
if (nIndex == m_nCurrentPerforationIndex)
{
oCandidate.m_sName = mapValues.value(
sNameId, oCandidate.m_sName).toString().trimmed();
oCandidate.m_dStart = mapValues.value(
sStartId, oCandidate.m_dStart).toDouble();
oCandidate.m_dEnd = mapValues.value(
sEndId, oCandidate.m_dEnd).toDouble();
oCandidate.m_dSkin = mapValues.value(
sSkinId, oCandidate.m_dSkin).toDouble();
}
vecCandidates.append(oCandidate);
if (pVecPerforations != nullptr)
{
nmDataPerforation oPerforationSnapshot(*pPerforation);
oPerforationSnapshot.getName().setValue(oCandidate.m_sName);
oPerforationSnapshot.getMdStart().setValue(oCandidate.m_dStart);
oPerforationSnapshot.getMdEnd().setValue(oCandidate.m_dEnd);
oPerforationSnapshot.getSkin().setValue(oCandidate.m_dSkin);
pVecPerforations->append(oPerforationSnapshot);
}
}
// 第二步逐项检查名称和MD顺序错误文字带序号便于定位非当前射孔。
for (int nIndex = 0; nIndex < vecCandidates.size(); ++nIndex)
{
const PerforationCandidate& oCandidate = vecCandidates[nIndex];
if (oCandidate.m_sName.isEmpty())
{
QString sRuleError = tr("Perforation name cannot be empty.");
sError = perforationErrorText(nIndex, sRuleError);
if (nIndex == m_nCurrentPerforationIndex)
{
nmParameterField* pNameField = field(sNameId);
if (pNameField != nullptr)
{
pNameField->setExternalValidationError(sError);
}
}
else if (m_pPerforationComboBox != nullptr)
{
m_pPerforationComboBox->setToolTip(sError);
}
return false;
}
if (oCandidate.m_dStart > oCandidate.m_dEnd)
{
QString sRuleError = tr(
"Perforation start MD cannot exceed end MD.");
sError = perforationErrorText(nIndex, sRuleError);
setPerforationError(nIndex, sError);
return false;
}
}
// 第三步:以候选井身参数检查全部射孔;水平井从第一段射孔起点延伸。
double dWellTop = mapValues.value(
sBottomholeMdId,
m_pWell->getBottomholeMD().getValue()).toDouble();
double dWellLength = mapValues.value(
sWellLengthId,
m_pWell->getWellLength().getValue()).toDouble();
nmDataHorizontalFracturedWell* pHorizontal =
dynamic_cast<nmDataHorizontalFracturedWell*>(m_pWell);
if (pHorizontal != nullptr && !vecCandidates.isEmpty())
{
dWellTop = vecCandidates[0].m_dStart;
}
double dWellBottom = dWellTop + dWellLength;
double dBoundaryTolerance = qMax(
1.0, qMax(qAbs(dWellTop), qAbs(dWellBottom))) * 1.0e-10;
for (int nIndex = 0; nIndex < vecCandidates.size(); ++nIndex)
{
const PerforationCandidate& oCandidate = vecCandidates[nIndex];
if (oCandidate.m_dStart < dWellTop - dBoundaryTolerance ||
oCandidate.m_dEnd > dWellBottom + dBoundaryTolerance)
{
QString sRuleError = tr(
"The perforation interval is outside the wellbore.");
sError = perforationErrorText(nIndex, sRuleError);
setPerforationError(nIndex, sError);
return false;
}
}
// 第四步:两两检查全部候选区间,端点相接允许但区间不能相交。
for (int nFirstIndex = 0;
nFirstIndex < vecCandidates.size();
++nFirstIndex)
{
for (int nSecondIndex = nFirstIndex + 1;
nSecondIndex < vecCandidates.size();
++nSecondIndex)
{
const PerforationCandidate& oFirst =
vecCandidates[nFirstIndex];
const PerforationCandidate& oSecond =
vecCandidates[nSecondIndex];
if (oFirst.m_dStart < oSecond.m_dEnd - dBoundaryTolerance &&
oFirst.m_dEnd > oSecond.m_dStart + dBoundaryTolerance)
{
int nErrorIndex =
nFirstIndex == m_nCurrentPerforationIndex
? nFirstIndex : nSecondIndex;
QString sRuleError = tr(
"Perforation intervals cannot overlap.");
sError = perforationErrorText(nErrorIndex, sRuleError);
setPerforationError(nErrorIndex, sError);
return false;
}
}
}
return true;
}
nmParameterField* nmWellParameterPanel::field(
const QString& sParameterId) const
{
return m_mapFields.value(sParameterId, nullptr);
}
QString nmWellParameterPanel::perforationErrorText(
int nPerforationIndex,
const QString& sRuleError) const
{
return QString("%1 %2: %3")
.arg(tr("Perforation"))
.arg(nPerforationIndex + 1)
.arg(sRuleError);
}
void nmWellParameterPanel::setPerforationError(
int nPerforationIndex,
const QString& sError)
{
if (m_pPerforationComboBox != nullptr)
{
m_pPerforationComboBox->setToolTip(sError);
}
if (nPerforationIndex != m_nCurrentPerforationIndex)
{
return;
}
nmParameterField* pStartField = field(
nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_MD_START));
nmParameterField* pEndField = field(
nmWellParameterCatalog::parameterId(
NM_WELL_PARAMETER_PERFORATION_MD_END));
if (pStartField != nullptr)
{
pStartField->setExternalValidationError(sError);
}
if (pEndField != nullptr)
{
pEndField->setExternalValidationError(sError);
}
}