|
|
|
|
|
#include "nmReservoirParameterPage.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "nmReservoirParameterField.h"
|
|
|
|
|
|
#include "nmReservoirPropertiesSession.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
|
#include <QGridLayout>
|
|
|
|
|
|
#include <QGroupBox>
|
|
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
|
#include <QSizePolicy>
|
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
#include <QtGlobal>
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirParameterPage::nmReservoirParameterPage(
|
|
|
|
|
|
nmReservoirPropertiesCategory eCategory,
|
|
|
|
|
|
nmReservoirPropertiesSession* pSession,
|
|
|
|
|
|
nmIReservoirParameterUnitService* pUnitService,
|
|
|
|
|
|
QWidget* pParent)
|
|
|
|
|
|
: QWidget(pParent),
|
|
|
|
|
|
m_eCategory(eCategory),
|
|
|
|
|
|
m_pSession(pSession),
|
|
|
|
|
|
m_pUnitService(pUnitService),
|
|
|
|
|
|
m_nCurrentObjectIndex(-1),
|
|
|
|
|
|
m_bUpdatingObject(false),
|
|
|
|
|
|
m_bBuildingFields(false),
|
|
|
|
|
|
m_pObjectDisplayGroup(nullptr),
|
|
|
|
|
|
m_pObjectLabel(nullptr),
|
|
|
|
|
|
m_pObjectComboBox(nullptr),
|
|
|
|
|
|
m_pGroupsWidget(nullptr),
|
|
|
|
|
|
m_pGroupsLayout(nullptr),
|
|
|
|
|
|
m_pMainLayout(nullptr),
|
|
|
|
|
|
m_pEmptyLabel(nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
createUi();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirParameterPage::~nmReservoirParameterPage()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_listFields.clear();
|
|
|
|
|
|
m_mapFields.clear();
|
|
|
|
|
|
m_mapEditorFields.clear();
|
|
|
|
|
|
m_pSession = nullptr;
|
|
|
|
|
|
m_pUnitService = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::createUi()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 第一步:创建单行对象显示控制区,储层页自动隐藏该分组。
|
|
|
|
|
|
m_pMainLayout = new QVBoxLayout(this);
|
|
|
|
|
|
m_pMainLayout->setContentsMargins(8, 6, 8, 8);
|
|
|
|
|
|
m_pMainLayout->setSpacing(8);
|
|
|
|
|
|
|
|
|
|
|
|
m_pObjectDisplayGroup = new QGroupBox(tr("Object display"), this);
|
|
|
|
|
|
m_pObjectDisplayGroup->setSizePolicy(
|
|
|
|
|
|
QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
|
|
|
|
QHBoxLayout* pObjectLayout = new QHBoxLayout(m_pObjectDisplayGroup);
|
|
|
|
|
|
pObjectLayout->setContentsMargins(8, 15, 8, 8);
|
|
|
|
|
|
pObjectLayout->setSpacing(9);
|
|
|
|
|
|
|
|
|
|
|
|
m_pObjectLabel = new QLabel(tr("Display:"), m_pObjectDisplayGroup);
|
|
|
|
|
|
m_pObjectLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
|
|
|
m_pObjectComboBox = new QComboBox(m_pObjectDisplayGroup);
|
|
|
|
|
|
m_pObjectComboBox->setMinimumWidth(260);
|
|
|
|
|
|
m_pObjectComboBox->setMaximumWidth(420);
|
|
|
|
|
|
m_pObjectComboBox->setMinimumHeight(27);
|
|
|
|
|
|
pObjectLayout->addStretch(1);
|
|
|
|
|
|
pObjectLayout->addWidget(m_pObjectLabel);
|
|
|
|
|
|
pObjectLayout->addWidget(m_pObjectComboBox);
|
|
|
|
|
|
pObjectLayout->addStretch(1);
|
|
|
|
|
|
m_pMainLayout->addWidget(m_pObjectDisplayGroup);
|
|
|
|
|
|
m_pObjectDisplayGroup->setVisible(
|
|
|
|
|
|
m_eCategory != NM_RESERVOIR_PAGE_RESERVOIR);
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:分组载体没有边框,仅用于实现原型中的两列网格。
|
|
|
|
|
|
m_pGroupsWidget = new QWidget(this);
|
|
|
|
|
|
m_pGroupsLayout = new QGridLayout(m_pGroupsWidget);
|
|
|
|
|
|
m_pGroupsLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
|
m_pGroupsLayout->setHorizontalSpacing(14);
|
|
|
|
|
|
m_pGroupsLayout->setVerticalSpacing(14);
|
|
|
|
|
|
m_pGroupsLayout->setColumnStretch(0, 1);
|
|
|
|
|
|
m_pGroupsLayout->setColumnStretch(1, 1);
|
|
|
|
|
|
m_pMainLayout->addWidget(m_pGroupsWidget);
|
|
|
|
|
|
m_pMainLayout->addStretch(1);
|
|
|
|
|
|
|
|
|
|
|
|
connect(m_pObjectComboBox, SIGNAL(currentIndexChanged(int)),
|
|
|
|
|
|
this, SLOT(slotObjectChanged(int)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::reloadObjects(QString& sError)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 第一步:重新取得会话对象描述,并把稳定对象code放入UserRole。
|
|
|
|
|
|
m_listObjectInfos = m_pSession != nullptr
|
|
|
|
|
|
? m_pSession->objectInfos(m_eCategory)
|
|
|
|
|
|
: QList<nmReservoirPropertyObjectInfo>();
|
|
|
|
|
|
m_bUpdatingObject = true;
|
|
|
|
|
|
m_pObjectComboBox->clear();
|
|
|
|
|
|
for (int nIndex = 0; nIndex < m_listObjectInfos.size(); ++nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
const nmReservoirPropertyObjectInfo& oInfo =
|
|
|
|
|
|
m_listObjectInfos[nIndex];
|
|
|
|
|
|
m_pObjectComboBox->addItem(oInfo.m_sDisplayName,
|
|
|
|
|
|
oInfo.m_sObjectCode);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_bUpdatingObject = false;
|
|
|
|
|
|
|
|
|
|
|
|
bool bShowSelector = m_eCategory != NM_RESERVOIR_PAGE_RESERVOIR;
|
|
|
|
|
|
m_pObjectDisplayGroup->setVisible(bShowSelector);
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:构建首个对象;空分类显示无额外面板的空状态。
|
|
|
|
|
|
return buildObject(m_listObjectInfos.isEmpty() ? -1 : 0, sError);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::hasEditableObjects() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return !m_listObjectInfos.isEmpty();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::slotObjectChanged(int nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_bUpdatingObject || nIndex == m_nCurrentObjectIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:离开旧对象前校验并保存,非法输入时回退对象选择。
|
|
|
|
|
|
int nPreviousIndex = m_nCurrentObjectIndex;
|
|
|
|
|
|
if (nPreviousIndex >= 0 && !commitPendingEdits())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bUpdatingObject = true;
|
|
|
|
|
|
m_pObjectComboBox->setCurrentIndex(nPreviousIndex);
|
|
|
|
|
|
m_bUpdatingObject = false;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:构建新对象;目录已在初始化阶段验证,正常切换不会失败。
|
|
|
|
|
|
QString sError;
|
|
|
|
|
|
if (!buildObject(nIndex, sError))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bUpdatingObject = true;
|
|
|
|
|
|
m_pObjectComboBox->setCurrentIndex(nPreviousIndex);
|
|
|
|
|
|
m_bUpdatingObject = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::buildObject(int nObjectIndex,
|
|
|
|
|
|
QString& sError)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bBuildingFields = true;
|
|
|
|
|
|
clearObjectEditors();
|
|
|
|
|
|
m_nCurrentObjectIndex = nObjectIndex;
|
|
|
|
|
|
|
|
|
|
|
|
if (nObjectIndex < 0 || nObjectIndex >= m_listObjectInfos.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pEmptyLabel = new QLabel(
|
|
|
|
|
|
tr("No editable objects in this category."),
|
|
|
|
|
|
m_pGroupsWidget);
|
|
|
|
|
|
m_pEmptyLabel->setAlignment(Qt::AlignCenter);
|
|
|
|
|
|
m_pEmptyLabel->setMinimumHeight(260);
|
|
|
|
|
|
m_pGroupsLayout->addWidget(m_pEmptyLabel, 0, 0, 1, 2);
|
|
|
|
|
|
m_bBuildingFields = false;
|
|
|
|
|
|
sError.clear();
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:按目录直接创建分组,页面不再包含对象类型专用布局代码。
|
|
|
|
|
|
const nmReservoirPropertyObjectInfo& oObjectInfo =
|
|
|
|
|
|
m_listObjectInfos[nObjectIndex];
|
|
|
|
|
|
for (int nGroupIndex = 0;
|
|
|
|
|
|
nGroupIndex < oObjectInfo.m_listGroups.size();
|
|
|
|
|
|
++nGroupIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!buildGroup(oObjectInfo.m_listGroups[nGroupIndex], sError))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bBuildingFields = false;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:加载工作副本,随后只调整行可见性,不重建页面。
|
|
|
|
|
|
for (int nFieldIndex = 0;
|
|
|
|
|
|
nFieldIndex < m_listFields.size();
|
|
|
|
|
|
++nFieldIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
loadFieldValue(m_listFields[nFieldIndex]);
|
|
|
|
|
|
}
|
|
|
|
|
|
applyVisibilityRules();
|
|
|
|
|
|
m_bBuildingFields = false;
|
|
|
|
|
|
sError.clear();
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::clearObjectEditors()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_listFields.clear();
|
|
|
|
|
|
m_mapFields.clear();
|
|
|
|
|
|
m_mapEditorFields.clear();
|
|
|
|
|
|
m_pEmptyLabel = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// 分组载体本身保留,只删除其直接子控件和布局项。
|
|
|
|
|
|
while (m_pGroupsLayout->count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
QLayoutItem* pItem = m_pGroupsLayout->takeAt(0);
|
|
|
|
|
|
if (pItem->widget() != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
delete pItem->widget();
|
|
|
|
|
|
}
|
|
|
|
|
|
delete pItem;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::buildGroup(
|
|
|
|
|
|
const nmReservoirParameterGroupInfo& oGroupInfo,
|
|
|
|
|
|
QString& sError)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 承载器始终横向铺满网格单元;只通过内部弹簧控制垂直位置,
|
|
|
|
|
|
// 避免直接设置对齐标志后分组框退回建议宽度。
|
|
|
|
|
|
QWidget* pGroupContainer = new QWidget(m_pGroupsWidget);
|
|
|
|
|
|
pGroupContainer->setSizePolicy(QSizePolicy::Expanding,
|
|
|
|
|
|
QSizePolicy::Expanding);
|
|
|
|
|
|
QVBoxLayout* pGroupContainerLayout =
|
|
|
|
|
|
new QVBoxLayout(pGroupContainer);
|
|
|
|
|
|
pGroupContainerLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
|
pGroupContainerLayout->setSpacing(0);
|
|
|
|
|
|
|
|
|
|
|
|
QGroupBox* pGroupBox = new QGroupBox(
|
|
|
|
|
|
oGroupInfo.m_sTitle, pGroupContainer);
|
|
|
|
|
|
// 参数框只在水平方向随页面宽度调整,垂直方向始终采用内容建议高度,
|
|
|
|
|
|
// 避免跨行分组被网格拉伸成大面积空白框。
|
|
|
|
|
|
pGroupBox->setSizePolicy(QSizePolicy::Expanding,
|
|
|
|
|
|
QSizePolicy::Fixed);
|
|
|
|
|
|
QGridLayout* pFieldLayout = new QGridLayout(pGroupBox);
|
|
|
|
|
|
pFieldLayout->setContentsMargins(8, 15, 8, 10);
|
|
|
|
|
|
pFieldLayout->setHorizontalSpacing(6);
|
|
|
|
|
|
pFieldLayout->setVerticalSpacing(6);
|
|
|
|
|
|
int nFieldColumnOffset = 0;
|
|
|
|
|
|
// 字段较少的通栏分组使用独立的左右弹性列,
|
|
|
|
|
|
// 使参数区域保持居中,输入列仍可随窗口宽度适度伸展。
|
|
|
|
|
|
if (oGroupInfo.m_bFieldsCentered)
|
|
|
|
|
|
{
|
|
|
|
|
|
nFieldColumnOffset = 1;
|
|
|
|
|
|
pFieldLayout->setColumnStretch(0, 1);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(1, 0);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(2, 1);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(3, 0);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(4, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 常规分组由最长标签决定标签列宽,数值列和单位列按比例伸展。
|
|
|
|
|
|
pFieldLayout->setColumnStretch(0, 0);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(1, 8);
|
|
|
|
|
|
pFieldLayout->setColumnStretch(2, 5);
|
|
|
|
|
|
}
|
|
|
|
|
|
pFieldLayout->setColumnMinimumWidth(
|
|
|
|
|
|
nFieldColumnOffset + 1,
|
|
|
|
|
|
nmReservoirParameterField::editorMinimumWidth());
|
|
|
|
|
|
pFieldLayout->setColumnMinimumWidth(
|
|
|
|
|
|
nFieldColumnOffset + 2,
|
|
|
|
|
|
nmReservoirParameterField::unitMinimumWidth());
|
|
|
|
|
|
|
|
|
|
|
|
// 每个字段只把三个直接控件放入此网格,不产生字段外框或子面板。
|
|
|
|
|
|
for (int nFieldIndex = 0;
|
|
|
|
|
|
nFieldIndex < oGroupInfo.m_listFields.size();
|
|
|
|
|
|
++nFieldIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
new nmReservoirParameterField(
|
|
|
|
|
|
oGroupInfo.m_listFields[nFieldIndex],
|
|
|
|
|
|
m_pUnitService,
|
|
|
|
|
|
pGroupBox);
|
|
|
|
|
|
if (!pField->initialize(pFieldLayout,
|
|
|
|
|
|
nFieldIndex,
|
|
|
|
|
|
nFieldColumnOffset,
|
|
|
|
|
|
sError))
|
|
|
|
|
|
{
|
|
|
|
|
|
delete pGroupContainer;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
pField->setValueRightAligned(
|
|
|
|
|
|
oGroupInfo.m_bValueRightAligned);
|
|
|
|
|
|
if (pField->valueEditor() != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
connect(pField->valueEditor(), SIGNAL(textChanged(QString)),
|
|
|
|
|
|
this, SLOT(slotFieldValueEdited()));
|
|
|
|
|
|
m_mapEditorFields.insert(pField->valueEditor(), pField);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pField->enumEditor() != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
connect(pField->enumEditor(), SIGNAL(currentIndexChanged(int)),
|
|
|
|
|
|
this, SLOT(slotEnumIndexChanged(int)));
|
|
|
|
|
|
m_mapEditorFields.insert(pField->enumEditor(), pField);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_listFields.append(pField);
|
|
|
|
|
|
m_mapFields.insert(pField->parameterId(), pField);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跨越多行的分组在承载区域垂直居中,普通分组保持顶部排列。
|
|
|
|
|
|
if (oGroupInfo.m_nRowSpan > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
pGroupContainerLayout->addStretch(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
pGroupContainerLayout->addWidget(pGroupBox);
|
|
|
|
|
|
pGroupContainerLayout->addStretch(1);
|
|
|
|
|
|
|
|
|
|
|
|
m_pGroupsLayout->addWidget(
|
|
|
|
|
|
pGroupContainer,
|
|
|
|
|
|
oGroupInfo.m_nRow,
|
|
|
|
|
|
oGroupInfo.m_nColumn,
|
|
|
|
|
|
oGroupInfo.m_nRowSpan,
|
|
|
|
|
|
oGroupInfo.m_nColumnSpan);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::loadFieldValue(
|
|
|
|
|
|
nmReservoirParameterField* pField)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pField == nullptr || m_pSession == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pField->isEnum())
|
|
|
|
|
|
{
|
|
|
|
|
|
pField->setEnumCode(m_pSession->enumCode(
|
|
|
|
|
|
pField->parameterId()));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
pField->setBaseValue(m_pSession->value(
|
|
|
|
|
|
pField->parameterId()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::commitPendingEdits()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pSession == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:先完整校验,避免部分字段已写入而后续字段失败。
|
|
|
|
|
|
if (!isInputValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:逐行按编辑器指针获取基准值,再统一写入工作副本。
|
|
|
|
|
|
QMap<QString, QVariant> mapValues;
|
|
|
|
|
|
for (int nFieldIndex = 0;
|
|
|
|
|
|
nFieldIndex < m_listFields.size();
|
|
|
|
|
|
++nFieldIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
m_listFields[nFieldIndex];
|
|
|
|
|
|
if (pField == nullptr || pField->isEnum() ||
|
|
|
|
|
|
!pField->isFieldVisible())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
bool bValid = false;
|
|
|
|
|
|
QVariant oValue = pField->baseValue(bValid);
|
|
|
|
|
|
if (!bValid || !oValue.isValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
mapValues.insert(pField->parameterId(), oValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pSession->setValues(mapValues);
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmReservoirParameterPage::isInputValid()
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pSoiField =
|
|
|
|
|
|
m_mapFields.value("Soi", nullptr);
|
|
|
|
|
|
nmReservoirParameterField* pSwiField =
|
|
|
|
|
|
m_mapFields.value("Swi", nullptr);
|
|
|
|
|
|
if (pSoiField != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
pSoiField->setExternalValidationError(QString());
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pSwiField != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
pSwiField->setExternalValidationError(QString());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool bAllValid = true;
|
|
|
|
|
|
for (int nFieldIndex = 0;
|
|
|
|
|
|
nFieldIndex < m_listFields.size();
|
|
|
|
|
|
++nFieldIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
m_listFields[nFieldIndex];
|
|
|
|
|
|
if (pField != nullptr && pField->isFieldVisible() &&
|
|
|
|
|
|
!pField->validate())
|
|
|
|
|
|
{
|
|
|
|
|
|
bAllValid = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 油水两相同时显示两个初始饱和度时,两者之和必须为1。
|
|
|
|
|
|
if (pSoiField != nullptr && pSwiField != nullptr &&
|
|
|
|
|
|
pSoiField->isFieldVisible() &&
|
|
|
|
|
|
pSwiField->isFieldVisible())
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bSoiValid = false;
|
|
|
|
|
|
bool bSwiValid = false;
|
|
|
|
|
|
QVariant oSoi = pSoiField->baseValue(bSoiValid);
|
|
|
|
|
|
QVariant oSwi = pSwiField->baseValue(bSwiValid);
|
|
|
|
|
|
const double dTolerance = 1.0e-6;
|
|
|
|
|
|
if (bSoiValid && bSwiValid &&
|
|
|
|
|
|
qAbs(oSoi.toDouble() + oSwi.toDouble() - 1.0) >
|
|
|
|
|
|
dTolerance)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString sError = tr(
|
|
|
|
|
|
"Initial oil and water saturations must sum to 1.");
|
|
|
|
|
|
pSoiField->setExternalValidationError(sError);
|
|
|
|
|
|
pSwiField->setExternalValidationError(sError);
|
|
|
|
|
|
bAllValid = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return bAllValid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::slotFieldValueEdited()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bBuildingFields)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
m_mapEditorFields.value(sender(), nullptr);
|
|
|
|
|
|
if (pField != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
pField->validate();
|
|
|
|
|
|
}
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::slotEnumIndexChanged(int nIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_UNUSED(nIndex);
|
|
|
|
|
|
if (m_bBuildingFields || m_pSession == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
m_mapEditorFields.value(sender(), nullptr);
|
|
|
|
|
|
if (pField == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
QString sParameterId = pField->parameterId();
|
|
|
|
|
|
|
|
|
|
|
|
// 第一步:联动前保存当前可见数值;非法时回滚枚举code。
|
|
|
|
|
|
QString sPreviousCode = m_pSession->enumCode(sParameterId);
|
|
|
|
|
|
if (!commitPendingEdits())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bBuildingFields = true;
|
|
|
|
|
|
pField->setEnumCode(sPreviousCode);
|
|
|
|
|
|
m_bBuildingFields = false;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第二步:只用稳定code更新工作副本,显示文字不参与业务判断。
|
|
|
|
|
|
if (!m_pSession->setEnumCode(sParameterId, pField->enumCode()))
|
|
|
|
|
|
{
|
|
|
|
|
|
m_bBuildingFields = true;
|
|
|
|
|
|
pField->setEnumCode(sPreviousCode);
|
|
|
|
|
|
m_bBuildingFields = false;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 第三步:仅显示或隐藏行,隐藏参数继续保留在工作副本中。
|
|
|
|
|
|
applyVisibilityRules();
|
|
|
|
|
|
updateValidity();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::applyVisibilityRules()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pSession == nullptr || m_nCurrentObjectIndex < 0 ||
|
|
|
|
|
|
m_nCurrentObjectIndex >= m_listObjectInfos.size())
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const nmReservoirPropertyObjectInfo& oInfo =
|
|
|
|
|
|
m_listObjectInfos[m_nCurrentObjectIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// 区域标记为均质储层时隐藏双重介质参数。
|
|
|
|
|
|
if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION_MARK)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString sModelId = oInfo.m_sObjectCode +
|
|
|
|
|
|
"_RM_ReservoirType";
|
|
|
|
|
|
bool bDual = m_pSession->enumCode(sModelId) != "homogeneous";
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_RM_ComW", bDual);
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_RM_ComKr", bDual);
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_RM_NetToGross", bDual);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 无限导流裂缝不显示有限导流能力和裂缝宽度参数。
|
|
|
|
|
|
if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FRACTURE)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString sModelId = oInfo.m_sObjectCode + "_F_FlowModel";
|
|
|
|
|
|
bool bFinite = m_pSession->enumCode(sModelId) !=
|
|
|
|
|
|
"infinite_conductivity";
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_F_FC", bFinite);
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_F_DW", bFinite);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 非泄漏断层或复合区不显示泄漏系数。
|
|
|
|
|
|
if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_FAULT)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bLeaky = m_pSession->enumCode(
|
|
|
|
|
|
oInfo.m_sObjectCode + "_FT_FlowModel") == "leaky";
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_FT_Leakage", bLeaky);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (oInfo.m_eObjectType == NM_RESERVOIR_OBJECT_REGION)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bLeaky = m_pSession->enumCode(
|
|
|
|
|
|
oInfo.m_sObjectCode + "_R_FlowModel") == "leaky";
|
|
|
|
|
|
setFieldVisible(oInfo.m_sObjectCode + "_R_Leakage", bLeaky);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::setFieldVisible(
|
|
|
|
|
|
const QString& sParameterId,
|
|
|
|
|
|
bool bVisible)
|
|
|
|
|
|
{
|
|
|
|
|
|
nmReservoirParameterField* pField =
|
|
|
|
|
|
m_mapFields.value(sParameterId, nullptr);
|
|
|
|
|
|
if (pField != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
pField->setFieldVisible(bVisible);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmReservoirParameterPage::updateValidity()
|
|
|
|
|
|
{
|
|
|
|
|
|
emit sigValidityChanged(isInputValid());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmReservoirPropertiesCategory nmReservoirParameterPage::category() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_eCategory;
|
|
|
|
|
|
}
|