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

948 lines
31 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmWxIncludeOtherWells.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "ZxBaseUtil.h"
#include <QAbstractItemView>
#include <QApplication>
#include <QCheckBox>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QStringList>
#include <QStyle>
#include <QToolButton>
#include <QWidget>
namespace
{
// Include 对话框只展示当前 PEBI 网格能够表达的真实井型。
bool isSupportedNumericalWell(nmDataWellBase* pWellData)
{
if(pWellData == nullptr || pWellData->getWellCode().isEmpty()) {
return false;
}
const NM_WELL_MODEL eWellType = pWellData->getWellType();
return eWellType == NM_WELL_MODEL::Vertical_Well ||
eWellType == NM_WELL_MODEL::Vertical_Fractured_Well ||
eWellType == NM_WELL_MODEL::Horizontal_Fractured_Well;
}
// 从同一条流量记录中取得指定相的只读点集,避免三处分支判断各自漂移。
const QVector<QPointF>& phasePoints(
const nmFlowGaugeRecord& oRecord, NM_PHASE_TYPE ePhase)
{
switch(ePhase) {
case PHASE_Gas:
return oRecord.vecGasPoints;
case PHASE_Water:
return oRecord.vecWaterPoints;
case PHASE_Oil:
default:
return oRecord.vecOilPoints;
}
}
// 下拉项只有在记录可用且该相确有非零产量时才允许选择。
bool isSelectableFlowPhase(
const nmFlowGaugeRecord& oRecord, NM_PHASE_TYPE ePhase)
{
return oRecord.eStatus == NM_GaugeRecord_Usable &&
nmHasNonZeroFlowRate(phasePoints(oRecord, ePhase));
}
// 候选井至少要有一条可选分相记录;压力记录不是主动井候选的必要条件。
bool hasSelectableRateRecord(const QVector<nmFlowGaugeRecord>& vecRecords)
{
for(int nIndex = 0; nIndex < vecRecords.size(); ++nIndex) {
const nmFlowGaugeRecord& oRecord = vecRecords[nIndex];
if(nmIsSelectableFlowRecord(oRecord)) {
return true;
}
}
return false;
}
// Gauge Code 是记录的稳定身份,显示名称和测量时间都不能替代它参与关联。
const nmFlowGaugeRecord* findFlowRecord(
const QVector<nmFlowGaugeRecord>& vecRecords,
const QString& sGaugeCode)
{
if(sGaugeCode.isEmpty()) {
return nullptr;
}
for(int nIndex = 0; nIndex < vecRecords.size(); ++nIndex) {
if(vecRecords[nIndex].sGaugeCode == sGaugeCode) {
return &vecRecords[nIndex];
}
}
return nullptr;
}
// 保留配置只要求 Code 唯一且记录可解析,不要求记录中存在非零产量。
const nmFlowGaugeRecord* findUniqueUsableFlowRecord(
const QVector<nmFlowGaugeRecord>& vecRecords,
const QString& sGaugeCode)
{
if(sGaugeCode.isEmpty()) {
return nullptr;
}
const nmFlowGaugeRecord* pMatchedRecord = nullptr;
for(int nIndex = 0; nIndex < vecRecords.size(); ++nIndex) {
if(vecRecords[nIndex].sGaugeCode != sGaugeCode) {
continue;
}
if(pMatchedRecord != nullptr) {
return nullptr;
}
pMatchedRecord = &vecRecords[nIndex];
}
return pMatchedRecord != nullptr &&
pMatchedRecord->eStatus == NM_GaugeRecord_Usable
? pMatchedRecord : nullptr;
}
nmFlowGaugeRecord* findMutableFlowRecord(
QVector<nmFlowGaugeRecord>& vecRecords,
const QString& sGaugeCode)
{
if(sGaugeCode.isEmpty()) {
return nullptr;
}
for(int nIndex = 0; nIndex < vecRecords.size(); ++nIndex) {
if(vecRecords[nIndex].sGaugeCode == sGaugeCode) {
return &vecRecords[nIndex];
}
}
return nullptr;
}
// 打开对话框时只恢复仍存在且仍可用的压力记录 Code。
bool containsSelectablePressureCode(
const QVector<nmPressureGaugeRecord>& vecRecords,
const QString& sGaugeCode)
{
for(int nIndex = 0; nIndex < vecRecords.size(); ++nIndex) {
if(vecRecords[nIndex].sGaugeCode == sGaugeCode &&
nmIsSelectablePressureRecord(vecRecords[nIndex])) {
return true;
}
}
return false;
}
// 下拉框只显示稳定的 Gauge Code避免名称和测量时间挤占表格列宽。
// 异常旧数据没有 Code 时,才回退到框架名称或“未命名”。
QString gaugeRecordLabel(const QString& sGaugeName,
const QString& sGaugeCode, const QString& sGaugeTime)
{
Q_UNUSED(sGaugeTime);
QString sLabel = sGaugeCode.isEmpty() ? sGaugeName : sGaugeCode;
if(sLabel.isEmpty()) {
sLabel = nmWxIncludeOtherWells::tr("(unnamed)");
}
return sLabel;
}
QString gaugeRecordToolTip(const QString& sGaugeName,
const QString& sGaugeCode, const QString& sGaugeTime)
{
const QString sName = sGaugeName.trimmed().isEmpty()
? nmWxIncludeOtherWells::tr("(unnamed)") : sGaugeName;
const QString sCode = sGaugeCode.trimmed().isEmpty()
? nmWxIncludeOtherWells::tr("None") : sGaugeCode;
const QString sTime = sGaugeTime.trimmed().isEmpty()
? nmWxIncludeOtherWells::tr("None") : sGaugeTime;
QStringList listLines;
listLines << nmWxIncludeOtherWells::tr("Curve name: %1").arg(sName);
listLines << nmWxIncludeOtherWells::tr("Gauge Code: %1").arg(sCode);
listLines << nmWxIncludeOtherWells::tr("Measurement time: %1").arg(sTime);
return listLines.join(QLatin1String("\n"));
}
void appendGaugeRecordItem(QComboBox* pComboBox,
const QString& sGaugeName, const QString& sGaugeCode,
const QString& sGaugeTime)
{
pComboBox->addItem(gaugeRecordLabel(
sGaugeName, sGaugeCode, sGaugeTime), sGaugeCode);
pComboBox->setItemData(pComboBox->count() - 1,
gaugeRecordToolTip(sGaugeName, sGaugeCode, sGaugeTime),
Qt::ToolTipRole);
}
void updateGaugeComboToolTip(QComboBox* pComboBox)
{
if(pComboBox == nullptr || pComboBox->currentIndex() < 0) {
return;
}
QString sToolTip = pComboBox->itemData(
pComboBox->currentIndex(), Qt::ToolTipRole).toString();
if(sToolTip.isEmpty()) {
sToolTip = pComboBox->currentText();
}
pComboBox->setToolTip(sToolTip);
}
// 流动段索引是一基索引;统计段数时必须先排除框架可能写入的公共占位行。
int flowRecordSegmentCount(const nmFlowGaugeRecord& oRecord)
{
const QVector<QPointF>* pPoints = !oRecord.vecOilPoints.isEmpty()
? &oRecord.vecOilPoints : (!oRecord.vecGasPoints.isEmpty()
? &oRecord.vecGasPoints : (!oRecord.vecWaterPoints.isEmpty()
? &oRecord.vecWaterPoints : nullptr));
if(pPoints == nullptr) {
return 0;
}
bool bHasPlaceholder = false;
if(oRecord.bMultiPhase) {
bHasPlaceholder = !oRecord.vecOilPoints.isEmpty() &&
!oRecord.vecGasPoints.isEmpty() &&
!oRecord.vecWaterPoints.isEmpty() &&
oRecord.vecOilPoints.first() == QPointF(0.0, 0.0) &&
oRecord.vecGasPoints.first() == QPointF(0.0, 0.0) &&
oRecord.vecWaterPoints.first() == QPointF(0.0, 0.0);
} else {
bHasPlaceholder = pPoints->first() == QPointF(0.0, 0.0);
}
return pPoints->size() - (bHasPlaceholder ? 1 : 0);
}
// 井别只用于只读展示和默认参考相判断,不由油、气、水下拉选择反推。
QString wellCategoryText(NM_WELL_CATEGORY eWellCategory)
{
switch(eWellCategory) {
case NM_WellCategory_Oil:
return nmWxIncludeOtherWells::tr("Oil well");
case NM_WellCategory_Gas:
return nmWxIncludeOtherWells::tr("Gas well");
case NM_WellCategory_Water:
return nmWxIncludeOtherWells::tr("Water well");
default:
return nmWxIncludeOtherWells::tr("Unknown");
}
}
// WellDataRow 将三个固定相保存为独立开关,这里统一完成枚举到成员的映射。
bool rowPhaseUsed(const WellDataRow& oData, NM_PHASE_TYPE ePhase)
{
switch(ePhase) {
case PHASE_Oil:
return oData.m_bUseOilRate;
case PHASE_Gas:
return oData.m_bUseGasRate;
case PHASE_Water:
return oData.m_bUseWaterRate;
default:
return false;
}
}
void setRowPhaseUsed(
WellDataRow& oData, NM_PHASE_TYPE ePhase, bool bUsed)
{
switch(ePhase) {
case PHASE_Oil:
oData.m_bUseOilRate = bUsed;
break;
case PHASE_Gas:
oData.m_bUseGasRate = bUsed;
break;
case PHASE_Water:
oData.m_bUseWaterRate = bUsed;
break;
default:
break;
}
}
}
nmWxIncludeOtherWells::nmWxIncludeOtherWells(
nmDataAnalyzeManager* pDataManager,
QWidget* pParent)
: iDlgBase(pParent), m_pDataManager(pDataManager), m_pTableWidget(nullptr),
m_pFooterHelpButton(nullptr), m_pButtonBox(nullptr),
m_pOkButton(nullptr), m_pCancelButton(nullptr),
m_pButtonLayout(nullptr), m_pMainLayout(nullptr)
{
this->initUI();
}
nmWxIncludeOtherWells::~nmWxIncludeOtherWells()
{
// Qt 的对象父子关系会自动处理控件释放。
}
void nmWxIncludeOtherWells::initUI()
{
this->setupTable();
this->setupButtons();
this->setupLayouts();
this->setupConnections();
this->setWindowTitle(tr("Include Other Wells"));
this->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// 初始尺寸跟随列宽和井数量,手动缩小时仍由滚动条保护表头及下拉内容。
this->setMinimumSize(720, 240);
this->adjustDialogSizeToTable();
}
void nmWxIncludeOtherWells::setupTable()
{
m_pTableWidget = new QTableWidget(this);
m_pTableWidget->setColumnCount(ColumnCount);
m_pTableWidget->setRowCount(0);
// 本表以复选框和下拉框作为操作入口,不使用表格行选中态。
m_pTableWidget->setSelectionMode(QAbstractItemView::NoSelection);
m_pTableWidget->setFocusPolicy(Qt::NoFocus);
m_pTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_pTableWidget->setSortingEnabled(false);
m_pTableWidget->setDragEnabled(false);
m_pTableWidget->setAcceptDrops(false);
m_pTableWidget->setDropIndicatorShown(false);
m_pTableWidget->setAlternatingRowColors(true);
m_pTableWidget->setWordWrap(false);
m_pTableWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
m_pTableWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
// 与编辑井流量明细表使用相同的调色板、表头和网格边框。
// 表格内下拉框采用透明无边框样式,使交替行色连续显示。
m_pTableWidget->setStyleSheet(
"QTableWidget {"
" background-color: palette(base);"
" alternate-background-color: rgb(232, 232, 232);"
" gridline-color: palette(midlight);"
" border: 1px solid palette(mid);"
"}"
"QHeaderView {"
" background-color: palette(button);"
" color: palette(button-text);"
"}"
"QHeaderView::section {"
" background-color: palette(button);"
" color: palette(button-text);"
" border: none;"
" border-right: 1px solid palette(mid);"
" border-bottom: 1px solid palette(mid);"
"}"
"QTableCornerButton::section {"
" background-color: palette(base);"
" border: none;"
" border-right: 1px solid palette(mid);"
" border-bottom: 1px solid palette(mid);"
"}"
"QTableWidget QComboBox {"
" border: none;"
" background: transparent;"
" padding-left: 6px;"
"}"
"QTableWidget QComboBox::drop-down {"
" border: none;"
"}");
QStringList listHeaders;
listHeaders << tr("Name") << tr("Well category") << tr("Included")
<< tr("Oil production") << tr("Gas production")
<< tr("Water production") << tr("Pressure")
<< tr("Flow segment");
m_pTableWidget->setHorizontalHeaderLabels(listHeaders);
m_pTableWidget->horizontalHeader()->setVisible(true);
m_pTableWidget->horizontalHeader()->setMovable(false);
m_pTableWidget->horizontalHeader()->setMinimumSectionSize(64);
m_pTableWidget->horizontalHeader()->setStretchLastSection(false);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnName, QHeaderView::Stretch);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnWellCategory, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnIncluded, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnOilRate, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnGasRate, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnWaterRate, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnPressure, QHeaderView::ResizeToContents);
m_pTableWidget->horizontalHeader()->setResizeMode(
ColumnFlowSegment, QHeaderView::ResizeToContents);
m_pTableWidget->verticalHeader()->setVisible(true);
m_pTableWidget->verticalHeader()->setMovable(false);
m_pTableWidget->verticalHeader()->setDefaultAlignment(Qt::AlignCenter);
m_pTableWidget->verticalHeader()->setDefaultSectionSize(32);
m_pTableWidget->verticalHeader()->setMinimumSectionSize(28);
QVector<nmDataWellBase*> vecMapWells;
if(m_pDataManager != nullptr) {
vecMapWells = m_pDataManager->getWellDataList();
}
const QString sPrimaryWellCode = m_pDataManager != nullptr
? m_pDataManager->getPrimaryWellCode() : QString();
// 候选来源仍严格限定为 Map 中的其他主动井;只把选择界面迁移到这里。
for(int nIndex = 0; nIndex < vecMapWells.size(); ++nIndex) {
nmDataWellBase* pWellData = vecMapWells[nIndex];
if(!isSupportedNumericalWell(pWellData) ||
pWellData->getWellCode() == sPrimaryWellCode ||
!nmIsValidWellCategory(pWellData->getWellCategory())) {
continue;
}
WellDataRow oWellRow;
oWellRow.m_sWellCode = pWellData->getWellCode();
oWellRow.m_sName = pWellData->getWellName();
oWellRow.m_bIsPrimary = false;
oWellRow.m_eWellCategory = pWellData->getWellCategory();
oWellRow.m_eMode = NM_CaseWell_RateControlled;
oWellRow.m_vecPressureRecords = pWellData->getPressureRecords();
oWellRow.m_vecFlowRecords = pWellData->getFlowRecords();
oWellRow.m_bCanCalculate =
hasSelectableRateRecord(oWellRow.m_vecFlowRecords);
if(!oWellRow.m_bCanCalculate) {
continue;
}
oWellRow.m_sPressureGaugeCode =
pWellData->getSelectedPressureGaugeCode();
if(!containsSelectablePressureCode(
oWellRow.m_vecPressureRecords,
oWellRow.m_sPressureGaugeCode)) {
oWellRow.m_sPressureGaugeCode.clear();
}
oWellRow.m_sFlowGaugeCode =
pWellData->getSelectedFlowGaugeCode();
oWellRow.m_bUseOilRate = pWellData->getUseOilRate();
oWellRow.m_bUseGasRate = pWellData->getUseGasRate();
oWellRow.m_bUseWaterRate = pWellData->getUseWaterRate();
oWellRow.m_nFlowSegmentIndex = pWellData->getIndexF();
const bool bHadRequestedPhase = oWellRow.m_bUseOilRate ||
oWellRow.m_bUseGasRate || oWellRow.m_bUseWaterRate;
const bool bHadValidFlowSelection = findUniqueUsableFlowRecord(
oWellRow.m_vecFlowRecords,
oWellRow.m_sFlowGaugeCode) != nullptr;
normalizeFlowSelection(oWellRow);
// 新井默认启用三相;若框架当前选择失效,回退到第一条有产量记录。
// 用户已明确把三相都设为“无”时不自动恢复。
if(!bHadValidFlowSelection && bHadRequestedPhase) {
for(int nRecordIndex = 0;
nRecordIndex < oWellRow.m_vecFlowRecords.size();
++nRecordIndex) {
const nmFlowGaugeRecord& oRecord =
oWellRow.m_vecFlowRecords[nRecordIndex];
if(!nmIsSelectableFlowRecord(oRecord)) {
continue;
}
oWellRow.m_sFlowGaugeCode = oRecord.sGaugeCode;
oWellRow.m_bUseOilRate =
isSelectableFlowPhase(oRecord, PHASE_Oil);
oWellRow.m_bUseGasRate =
isSelectableFlowPhase(oRecord, PHASE_Gas);
oWellRow.m_bUseWaterRate =
isSelectableFlowPhase(oRecord, PHASE_Water);
normalizeFlowSelection(oWellRow);
if(oWellRow.canCalculate()) {
break;
}
}
}
oWellRow.m_bIsIncluded = oWellRow.canCalculate() &&
m_pDataManager->getNumericalAnalysisCase()->isIncludedWell(
oWellRow.m_sWellCode);
const int nRow = m_vecWellData.size();
m_vecWellData.append(oWellRow);
m_pTableWidget->setRowCount(nRow + 1);
addWellDataToTable(oWellRow, nRow);
}
if(m_vecWellData.isEmpty()) {
m_pTableWidget->setRowCount(1);
m_pTableWidget->setSpan(0, 0, 1, ColumnCount);
QTableWidgetItem* pEmptyItem = new QTableWidgetItem(
tr("No eligible wells"));
pEmptyItem->setFlags(Qt::NoItemFlags);
pEmptyItem->setTextAlignment(Qt::AlignCenter);
m_pTableWidget->setItem(0, 0, pEmptyItem);
// 空状态行不是候选井不显示容易产生误解的行号“1”。
m_pTableWidget->verticalHeader()->setVisible(false);
} else {
// Qt 默认按一基显示纵向表头;宽度随最大行号位数增长。
const int nRowNumberWidth = m_pTableWidget->fontMetrics().width(
QString::number(m_vecWellData.size())) + 18;
m_pTableWidget->verticalHeader()->setFixedWidth(
qMax(32, nRowNumberWidth));
}
// 单元格控件全部创建完成后再按真实表头和下拉内容计算列宽。
m_pTableWidget->resizeColumnsToContents();
}
void nmWxIncludeOtherWells::adjustDialogSizeToTable()
{
if(m_pTableWidget == nullptr || m_pMainLayout == nullptr) {
return;
}
int nTableWidth = m_pTableWidget->frameWidth() * 2;
if(m_pTableWidget->verticalHeader()->isVisible()) {
nTableWidth += m_pTableWidget->verticalHeader()->width();
}
for(int nColumn = 0; nColumn < ColumnCount; ++nColumn) {
nTableWidth += m_pTableWidget->columnWidth(nColumn);
}
const int nVisibleRows = qMin(qMax(1, m_pTableWidget->rowCount()), 10);
int nTableHeight = m_pTableWidget->frameWidth() * 2 +
m_pTableWidget->horizontalHeader()->sizeHint().height() +
nVisibleRows * m_pTableWidget->verticalHeader()->defaultSectionSize();
const int nScrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
if(m_pTableWidget->rowCount() > nVisibleRows) {
nTableWidth += nScrollBarExtent;
}
int nLeft = 0;
int nTop = 0;
int nRight = 0;
int nBottom = 0;
m_pMainLayout->getContentsMargins(&nLeft, &nTop, &nRight, &nBottom);
const int nLayoutWidth = nLeft + nRight;
const int nButtonHeight = qMax(m_pFooterHelpButton->sizeHint().height(),
qMax(m_pOkButton->sizeHint().height(),
m_pCancelButton->sizeHint().height()));
const int nLayoutHeight = nTop + nBottom + nButtonHeight +
m_pMainLayout->spacing();
QRect oAvailableGeometry;
QDesktopWidget* pDesktop = QApplication::desktop();
if(pDesktop != nullptr) {
oAvailableGeometry = pDesktop->availableGeometry(this);
}
if(!oAvailableGeometry.isValid()) {
oAvailableGeometry = QRect(0, 0, 1280, 720);
}
const int nMaximumWidth = qMax(640, oAvailableGeometry.width() * 9 / 10);
const int nMaximumHeight = qMax(260, oAvailableGeometry.height() * 4 / 5);
int nDialogWidth = qMin(nTableWidth + nLayoutWidth, nMaximumWidth);
if(nTableWidth + nLayoutWidth > nDialogWidth) {
nTableHeight += nScrollBarExtent;
}
const int nDialogHeight = qMin(nTableHeight + nLayoutHeight,
nMaximumHeight);
resize(qMax(minimumWidth(), nDialogWidth),
qMax(minimumHeight(), nDialogHeight));
}
void nmWxIncludeOtherWells::addWellDataToTable(
const WellDataRow& data, int row)
{
QTableWidgetItem* pNameItem = new QTableWidgetItem(data.m_sName);
pNameItem->setData(Qt::UserRole, data.m_sWellCode);
pNameItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
pNameItem->setToolTip(data.m_sName);
m_pTableWidget->setItem(row, ColumnName, pNameItem);
QTableWidgetItem* pCategoryItem = new QTableWidgetItem(
wellCategoryText(data.m_eWellCategory));
pCategoryItem->setTextAlignment(Qt::AlignCenter);
m_pTableWidget->setItem(row, ColumnWellCategory, pCategoryItem);
QWidget* pCheckContainer = new QWidget(m_pTableWidget);
QCheckBox* pCheckBox = new QCheckBox(pCheckContainer);
QHBoxLayout* pCheckLayout = new QHBoxLayout(pCheckContainer);
pCheckLayout->setContentsMargins(0, 0, 0, 0);
pCheckLayout->setAlignment(Qt::AlignCenter);
pCheckLayout->addWidget(pCheckBox);
pCheckBox->setProperty("row", row);
connect(pCheckBox, SIGNAL(stateChanged(int)),
this, SLOT(onCheckBoxStateChanged(int)));
m_pTableWidget->setCellWidget(row, ColumnIncluded, pCheckContainer);
const int arrRateColumns[] = {
ColumnOilRate, ColumnGasRate, ColumnWaterRate
};
const NM_PHASE_TYPE arrPhases[] = {
PHASE_Oil, PHASE_Gas, PHASE_Water
};
for(int nIndex = 0; nIndex < 3; ++nIndex) {
QComboBox* pRateCombo = new QComboBox(m_pTableWidget);
pRateCombo->setProperty("row", row);
pRateCombo->setProperty("phase", static_cast<int>(arrPhases[nIndex]));
pRateCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
pRateCombo->setMaxVisibleItems(16);
connect(pRateCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onRateSourceChanged(int)));
m_pTableWidget->setCellWidget(row, arrRateColumns[nIndex], pRateCombo);
}
QComboBox* pPressureCombo = new QComboBox(m_pTableWidget);
pPressureCombo->setProperty("row", row);
pPressureCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
pPressureCombo->setMaxVisibleItems(16);
connect(pPressureCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onPressureSourceChanged(int)));
m_pTableWidget->setCellWidget(row, ColumnPressure, pPressureCombo);
QComboBox* pSegmentCombo = new QComboBox(m_pTableWidget);
pSegmentCombo->setProperty("row", row);
pSegmentCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
connect(pSegmentCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onFlowSegmentChanged(int)));
m_pTableWidget->setCellWidget(row, ColumnFlowSegment, pSegmentCombo);
refreshRowEditors(row);
}
void nmWxIncludeOtherWells::normalizeFlowSelection(WellDataRow& data) const
{
const nmFlowGaugeRecord* pRecord = findUniqueUsableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
if(pRecord == nullptr) {
data.m_sFlowGaugeCode.clear();
data.m_bUseOilRate = false;
data.m_bUseGasRate = false;
data.m_bUseWaterRate = false;
data.m_nFlowSegmentIndex = 0;
return;
}
data.m_bUseOilRate = data.m_bUseOilRate &&
isSelectableFlowPhase(*pRecord, PHASE_Oil);
data.m_bUseGasRate = data.m_bUseGasRate &&
isSelectableFlowPhase(*pRecord, PHASE_Gas);
data.m_bUseWaterRate = data.m_bUseWaterRate &&
isSelectableFlowPhase(*pRecord, PHASE_Water);
const int nSegmentCount = flowRecordSegmentCount(*pRecord);
if(nSegmentCount <= 0) {
data.m_nFlowSegmentIndex = 0;
nmFlowGaugeRecord* pMutableRecord = findMutableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
if(pMutableRecord != nullptr) {
pMutableRecord->nIndexF = 0;
}
return;
}
if(data.m_nFlowSegmentIndex < 1 ||
data.m_nFlowSegmentIndex > nSegmentCount) {
data.m_nFlowSegmentIndex = pRecord->nIndexF;
if(data.m_nFlowSegmentIndex < 1 ||
data.m_nFlowSegmentIndex > nSegmentCount) {
data.m_nFlowSegmentIndex = nSegmentCount;
}
}
nmFlowGaugeRecord* pMutableRecord = findMutableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
if(pMutableRecord != nullptr) {
pMutableRecord->nIndexF = data.m_nFlowSegmentIndex;
}
}
void nmWxIncludeOtherWells::switchRowFlowGaugeCode(
WellDataRow& data, const QString& sGaugeCode) const
{
// 行数据是对话框工作副本,切换前先保存当前记录自己的流动段。
nmFlowGaugeRecord* pOldRecord = findMutableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
if(pOldRecord != nullptr) {
pOldRecord->nIndexF = data.m_nFlowSegmentIndex;
}
data.m_sFlowGaugeCode = sGaugeCode;
nmFlowGaugeRecord* pNewRecord = findMutableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
if(pNewRecord == nullptr ||
pNewRecord->eStatus != NM_GaugeRecord_Usable) {
data.m_nFlowSegmentIndex = 0;
return;
}
const int nSegmentCount = flowRecordSegmentCount(*pNewRecord);
data.m_nFlowSegmentIndex = pNewRecord->nIndexF;
if(data.m_nFlowSegmentIndex < 1 ||
data.m_nFlowSegmentIndex > nSegmentCount) {
data.m_nFlowSegmentIndex = nSegmentCount;
}
}
void nmWxIncludeOtherWells::populateRateCombo(
QComboBox* pComboBox, const WellDataRow& data,
NM_PHASE_TYPE ePhase) const
{
if(pComboBox == nullptr) {
return;
}
const bool bSignalsWereBlocked = pComboBox->blockSignals(true);
pComboBox->clear();
pComboBox->addItem(tr("None"), QString());
pComboBox->setItemData(0, tr("None"), Qt::ToolTipRole);
// 选择控件只展示当前相真正可用的记录。
for(int nIndex = 0; nIndex < data.m_vecFlowRecords.size(); ++nIndex) {
const nmFlowGaugeRecord& oRecord = data.m_vecFlowRecords[nIndex];
if(!isSelectableFlowPhase(oRecord, ePhase)) {
continue;
}
appendGaugeRecordItem(pComboBox,
oRecord.sGaugeName, oRecord.sGaugeCode, oRecord.sGaugeTime);
}
int nCurrentIndex = 0;
if(rowPhaseUsed(data, ePhase)) {
const int nFoundIndex = pComboBox->findData(data.m_sFlowGaugeCode);
if(nFoundIndex > 0) {
nCurrentIndex = nFoundIndex;
}
}
pComboBox->setCurrentIndex(nCurrentIndex);
updateGaugeComboToolTip(pComboBox);
pComboBox->blockSignals(bSignalsWereBlocked);
}
void nmWxIncludeOtherWells::populatePressureCombo(
QComboBox* pComboBox, const WellDataRow& data) const
{
if(pComboBox == nullptr) {
return;
}
const bool bSignalsWereBlocked = pComboBox->blockSignals(true);
pComboBox->clear();
pComboBox->addItem(tr("None"), QString());
pComboBox->setItemData(0, tr("None"), Qt::ToolTipRole);
for(int nIndex = 0; nIndex < data.m_vecPressureRecords.size(); ++nIndex) {
const nmPressureGaugeRecord& oRecord = data.m_vecPressureRecords[nIndex];
if(!nmIsSelectablePressureRecord(oRecord)) {
continue;
}
appendGaugeRecordItem(pComboBox,
oRecord.sGaugeName, oRecord.sGaugeCode, oRecord.sGaugeTime);
}
const int nCurrentIndex = pComboBox->findData(
data.m_sPressureGaugeCode);
pComboBox->setCurrentIndex(nCurrentIndex < 0 ? 0 : nCurrentIndex);
updateGaugeComboToolTip(pComboBox);
pComboBox->blockSignals(bSignalsWereBlocked);
}
void nmWxIncludeOtherWells::populateFlowSegmentCombo(
QComboBox* pComboBox, const WellDataRow& data) const
{
if(pComboBox == nullptr) {
return;
}
const bool bSignalsWereBlocked = pComboBox->blockSignals(true);
pComboBox->clear();
const nmFlowGaugeRecord* pRecord = findUniqueUsableFlowRecord(
data.m_vecFlowRecords, data.m_sFlowGaugeCode);
const int nSegmentCount = pRecord == nullptr
? 0 : flowRecordSegmentCount(*pRecord);
for(int nIndex = 1; nIndex <= nSegmentCount; ++nIndex) {
pComboBox->addItem(tr("Segment %1").arg(nIndex), nIndex);
}
const int nCurrentIndex = pComboBox->findData(
data.m_nFlowSegmentIndex);
if(nCurrentIndex >= 0) {
pComboBox->setCurrentIndex(nCurrentIndex);
}
pComboBox->setEnabled(data.canCalculate());
pComboBox->setToolTip(pComboBox->currentText());
pComboBox->blockSignals(bSignalsWereBlocked);
}
void nmWxIncludeOtherWells::refreshRowEditors(int row)
{
if(row < 0 || row >= m_vecWellData.size()) {
return;
}
const WellDataRow& oData = m_vecWellData[row];
populateRateCombo(qobject_cast<QComboBox*>(
m_pTableWidget->cellWidget(row, ColumnOilRate)),
oData, PHASE_Oil);
populateRateCombo(qobject_cast<QComboBox*>(
m_pTableWidget->cellWidget(row, ColumnGasRate)),
oData, PHASE_Gas);
populateRateCombo(qobject_cast<QComboBox*>(
m_pTableWidget->cellWidget(row, ColumnWaterRate)),
oData, PHASE_Water);
populatePressureCombo(qobject_cast<QComboBox*>(
m_pTableWidget->cellWidget(row, ColumnPressure)), oData);
populateFlowSegmentCombo(qobject_cast<QComboBox*>(
m_pTableWidget->cellWidget(row, ColumnFlowSegment)), oData);
updateIncludeCheckBox(row);
}
void nmWxIncludeOtherWells::updateIncludeCheckBox(int row)
{
if(row < 0 || row >= m_vecWellData.size()) {
return;
}
WellDataRow& oData = m_vecWellData[row];
if(!oData.canCalculate()) {
oData.m_bIsIncluded = false;
}
QWidget* pContainer = m_pTableWidget->cellWidget(row, ColumnIncluded);
QCheckBox* pCheckBox = pContainer == nullptr
? nullptr : pContainer->findChild<QCheckBox*>();
if(pCheckBox == nullptr) {
return;
}
const bool bSignalsWereBlocked = pCheckBox->blockSignals(true);
pCheckBox->setEnabled(oData.m_bCanCalculate);
pCheckBox->setChecked(oData.m_bIsIncluded);
pCheckBox->setToolTip(oData.canCalculate()
? QString() : tr("Select at least one production record first."));
pCheckBox->blockSignals(bSignalsWereBlocked);
}
void nmWxIncludeOtherWells::onCheckBoxStateChanged(int state)
{
QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
if(pCheckBox == nullptr) {
return;
}
const int nRow = pCheckBox->property("row").toInt();
if(nRow < 0 || nRow >= m_vecWellData.size()) {
return;
}
WellDataRow& oData = m_vecWellData[nRow];
if(oData.m_bIsPrimary ||
(state == Qt::Checked && !oData.canCalculate())) {
oData.m_bIsIncluded = false;
updateIncludeCheckBox(nRow);
return;
}
oData.m_bIsIncluded = state == Qt::Checked;
}
void nmWxIncludeOtherWells::onRateSourceChanged(int nIndex)
{
QComboBox* pComboBox = qobject_cast<QComboBox*>(sender());
if(pComboBox == nullptr || nIndex < 0) {
return;
}
const int nRow = pComboBox->property("row").toInt();
const NM_PHASE_TYPE ePhase = static_cast<NM_PHASE_TYPE>(
pComboBox->property("phase").toInt());
if(nRow < 0 || nRow >= m_vecWellData.size()) {
return;
}
WellDataRow& oData = m_vecWellData[nRow];
// 可见文本只用于展示,真正写回始终读取 itemData 中的 Gauge Code。
const QString sGaugeCode = pComboBox->itemData(nIndex).toString();
if(sGaugeCode.isEmpty()) {
setRowPhaseUsed(oData, ePhase, false);
} else {
const nmFlowGaugeRecord* pRecord = findFlowRecord(
oData.m_vecFlowRecords, sGaugeCode);
if(pRecord == nullptr || !isSelectableFlowPhase(*pRecord, ePhase)) {
refreshRowEditors(nRow);
return;
}
if(oData.m_sFlowGaugeCode != sGaugeCode) {
switchRowFlowGaugeCode(oData, sGaugeCode);
}
setRowPhaseUsed(oData, ePhase, true);
}
// PEBI 每口井只有一条 Rate.t。切换任一相的记录后其他已启用相
// 自动使用同一记录;新记录没有的相自动回到“无”。
normalizeFlowSelection(oData);
refreshRowEditors(nRow);
}
void nmWxIncludeOtherWells::onPressureSourceChanged(int nIndex)
{
QComboBox* pComboBox = qobject_cast<QComboBox*>(sender());
if(pComboBox == nullptr || nIndex < 0) {
return;
}
const int nRow = pComboBox->property("row").toInt();
if(nRow < 0 || nRow >= m_vecWellData.size()) {
return;
}
m_vecWellData[nRow].m_sPressureGaugeCode =
pComboBox->itemData(nIndex).toString();
updateGaugeComboToolTip(pComboBox);
}
void nmWxIncludeOtherWells::onFlowSegmentChanged(int nIndex)
{
QComboBox* pComboBox = qobject_cast<QComboBox*>(sender());
if(pComboBox == nullptr || nIndex < 0) {
return;
}
const int nRow = pComboBox->property("row").toInt();
if(nRow < 0 || nRow >= m_vecWellData.size()) {
return;
}
WellDataRow& oData = m_vecWellData[nRow];
oData.m_nFlowSegmentIndex = pComboBox->itemData(nIndex).toInt();
nmFlowGaugeRecord* pRecord = findMutableFlowRecord(
oData.m_vecFlowRecords, oData.m_sFlowGaugeCode);
if(pRecord != nullptr) {
pRecord->nIndexF = oData.m_nFlowSegmentIndex;
}
pComboBox->setToolTip(pComboBox->currentText());
}
QVector<WellDataRow> nmWxIncludeOtherWells::getWellData() const
{
return m_vecWellData;
}
void nmWxIncludeOtherWells::setupButtons()
{
m_pFooterHelpButton = new QToolButton(this);
m_pFooterHelpButton->setText(tr("Help"));
m_pFooterHelpButton->setIcon(zxLoadIcon("Help"));
m_pFooterHelpButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_pFooterHelpButton->setAutoRaise(true);
m_pButtonBox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal, this);
m_pOkButton = m_pButtonBox->button(QDialogButtonBox::Ok);
m_pCancelButton = m_pButtonBox->button(QDialogButtonBox::Cancel);
if(m_pOkButton != nullptr) {
m_pOkButton->setIcon(zxLoadIcon("OK"));
m_pOkButton->setText(tr("OK"));
}
if(m_pCancelButton != nullptr) {
m_pCancelButton->setIcon(zxLoadIcon("Cancel"));
m_pCancelButton->setText(tr("Cancel"));
}
}
void nmWxIncludeOtherWells::setupLayouts()
{
m_pButtonLayout = new QHBoxLayout();
m_pButtonLayout->addWidget(m_pFooterHelpButton);
m_pButtonLayout->addStretch();
m_pButtonLayout->addWidget(m_pButtonBox);
m_pMainLayout = new QVBoxLayout(this);
m_pMainLayout->addWidget(m_pTableWidget, 1);
m_pMainLayout->addLayout(m_pButtonLayout);
setLayout(m_pMainLayout);
}
void nmWxIncludeOtherWells::setupConnections()
{
connect(m_pFooterHelpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));
connect(m_pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
void nmWxIncludeOtherWells::slotHelp()
{
ZxBaseUtil::startHelp();
}