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

1183 lines
42 KiB
C++

#include "nmWxForecast.h"
#include <QApplication>
#include <QStyle>
#include <QSpacerItem>
#include <QSizePolicy>
#include <QLabel>
nmWxForecast::nmWxForecast(QWidget *parent)
: iDlgBase(parent)
, m_initialPressureComponent(nullptr)
, m_abandonmentRateComponent(nullptr)
, m_maximumRateComponent(nullptr)
, m_forecastDurationComponent(nullptr)
, m_producingPressureComponent(nullptr)
, m_producingPressureEndComponent(nullptr)
, m_pressureChangePeriodComponent(nullptr)
, m_pressureTableWidget(nullptr)
, m_pDurationUnitCombo(nullptr)
, m_pPressureUnitCombo(nullptr)
, m_rateTableWidget(nullptr)
, m_rDurationUnitCombo(nullptr)
, m_rRateUnitCombo(nullptr)
, m_extMultiR(nullptr)
, m_extStackedWidget(nullptr)
, m_extEmpty(nullptr)
{
setWindowTitle("Forecast");
setFixedSize(520, 560);
PressureRow tempDefaults;
m_currentDurationUnit = tempDefaults.duration.getUnit();
m_currentPressureUnit = tempDefaults.pressure.getUnit();
FlowRow tempFlowDefaults;
m_currentRateUnit = tempFlowDefaults.q0.getUnit();
// 先构建UI
setupUI();
setupConnections();
// 从数据中心加载数据
loadDataFromManager();
// 根据加载的数据更新界面
updateParametersForOption();
}
nmWxForecast::~nmWxForecast()
{
}
void nmWxForecast::loadDataFromManager()
{
// 从数据中心获取预测数据的副本
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
if(pManager) {
m_forecastData = pManager->getForecastDataCopy();
// 根据数据设置单选按钮
nmDataForecast::ForecastOption option = m_forecastData.getForecastOption();
switch(option) {
case nmDataForecast::ConstantPressureOption:
m_constantPressureRadio->setChecked(true);
break;
case nmDataForecast::DecliningPressureOption:
m_decliningPressureRadio->setChecked(true);
break;
case nmDataForecast::MultiplePressuresOption:
m_multiplePressuresRadio->setChecked(true);
break;
case nmDataForecast::MultipleRatesOption:
m_multipleRatesRadio->setChecked(true);
break;
}
} else {
// 如果数据中心不存在,使用默认数据
m_constantPressureRadio->setChecked(true);
m_forecastData.setForecastOption(nmDataForecast::ConstantPressureOption);
}
}
void nmWxForecast::saveDataToManager()
{
// 先从界面更新数据
updateDataFromUI();
// 保存到数据中心
nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance();
if(pManager) {
pManager->updateForecastData(m_forecastData);
}
}
void nmWxForecast::setupUI()
{
m_mainLayout = new QVBoxLayout(this);
// ========== Forecast options ==========
m_forecastOptionsGroup = new QGroupBox("Forecast options", this);
m_forecastOptionsLayout = new QVBoxLayout(m_forecastOptionsGroup);
m_constantPressureRadio = new QRadioButton("Constant pressure", this);
m_decliningPressureRadio = new QRadioButton("Declining pressure (ramp)", this);
m_multiplePressuresRadio = new QRadioButton("Multiple pressures", this);
m_multipleRatesRadio = new QRadioButton("Multiple rates", this);
m_forecastButtonGroup = new QButtonGroup(this);
m_forecastButtonGroup->addButton(m_constantPressureRadio, 0);
m_forecastButtonGroup->addButton(m_decliningPressureRadio, 1);
m_forecastButtonGroup->addButton(m_multiplePressuresRadio, 2);
m_forecastButtonGroup->addButton(m_multipleRatesRadio, 3);
m_usePastHistoryCheck = new QCheckBox("Use past history", this);
m_surfacePressuresCheck = new QCheckBox("Surface pressures", this);
m_usePastHistoryCheck->setEnabled(false);
m_surfacePressuresCheck->setEnabled(false);
m_forecastOptionsLayout->addWidget(m_constantPressureRadio);
m_forecastOptionsLayout->addWidget(m_decliningPressureRadio);
m_forecastOptionsLayout->addWidget(m_multiplePressuresRadio);
m_forecastOptionsLayout->addWidget(m_multipleRatesRadio);
QHBoxLayout *checkBoxLayout = new QHBoxLayout();
checkBoxLayout->addWidget(m_usePastHistoryCheck);
checkBoxLayout->addWidget(m_surfacePressuresCheck);
checkBoxLayout->addStretch();
m_forecastOptionsLayout->addLayout(checkBoxLayout);
// ========== Parameters ==========
m_parametersGroup = new QGroupBox("Parameters", this);
QVBoxLayout *parametersOuterLayout = new QVBoxLayout(m_parametersGroup);
parametersOuterLayout->setContentsMargins(6, 6, 6, 6);
// 基础区
QWidget *baseWidget = new QWidget(this);
m_parametersLayout = new QGridLayout(baseWidget);
m_parametersLayout->setHorizontalSpacing(8);
m_parametersLayout->setVerticalSpacing(8);
m_parametersLayout->setColumnStretch(0, 0); // 复选框列
m_parametersLayout->setColumnStretch(1, 1); // 组件列(会自动扩展)
int row = 0;
// 1. 创建一个“占位符” (strut)用于永久撑开第0列
QWidget* column0Strut = new QWidget(this);
// 2. 将占位符添加到 (row 0, col 0)
m_parametersLayout->addWidget(column0Strut, row, 0);
// (row 0) Initial pressure
ConstantPressure& constantPressureData = m_forecastData.getConstantPressureData();
m_initialPressureComponent = new nmGUIComponentLineEdit(
&constantPressureData.getInitialPressure(),
true,
this
);
m_parametersLayout->addWidget(m_initialPressureComponent, row, 1);
row++;
// (row 1) Abandonment rate
m_abandonmentRateCheck = new QCheckBox(this);
m_abandonmentRateComponent = new nmGUIComponentLineEdit(&constantPressureData.getAbandonmentRate(), true, this);
// 创建 QStackedWidget 来包裹 组件
m_abandonmentStack = new QStackedWidget(this);
m_abandonmentSpacer = new QWidget(this);
// 使用组件的高度来设置占位符高度
m_abandonmentSpacer->setFixedHeight(m_abandonmentRateComponent->sizeHint().height());
m_abandonmentStack->addWidget(m_abandonmentRateComponent); // 第 0 页 (组件)
m_abandonmentStack->addWidget(m_abandonmentSpacer); // 第 1 页 (占位符)
m_parametersLayout->addWidget(m_abandonmentRateCheck, row, 0); // 将复选框添加到第 0 列
m_parametersLayout->addWidget(m_abandonmentStack, row, 1); // 将堆栈(内含组件)添加到第 1 列
row++;
// (row 2) Maximum rate
m_maximumRateCheck = new QCheckBox(this);
m_maximumRateComponent = new nmGUIComponentLineEdit(&m_forecastData.getConstantPressureData().getMaximumRate(), true, this);
// 创建 QStackedWidget 来包裹组件
m_maximumStack = new QStackedWidget(this);
m_maximumSpacer = new QWidget(this);
m_maximumSpacer->setFixedHeight(m_maximumRateComponent->sizeHint().height());
m_maximumStack->addWidget(m_maximumRateComponent); // 第 0 页 (组件)
m_maximumStack->addWidget(m_maximumSpacer); // 第 1 页 (占位符)
m_parametersLayout->addWidget(m_maximumRateCheck, row, 0); // 将复选框添加到第 0 列
m_parametersLayout->addWidget(m_maximumStack, row, 1); // 将堆栈(内含组件)添加到第 1 列
row++;
// (row 3) Forecast duration
m_forecastDurationComponent = new nmGUIComponentLineEdit(&m_forecastData.getConstantPressureData().getForecastDuration(), true, this);
m_parametersLayout->addWidget(m_forecastDurationComponent, row, 1);
row++;
// 设置占位符的固定宽度,使其等于复选框的宽度
int chkBoxWidth = m_abandonmentRateCheck->minimumSizeHint().width();
column0Strut->setFixedWidth(chkBoxWidth);
// (row 4) Producing pressure
m_producingPressureComponent = new nmGUIComponentLineEdit(&m_forecastData.getConstantPressureData().getProducingPressure(), true, this);
m_parametersLayout->addWidget(m_producingPressureComponent, row, 1);
row++;
// ========== 扩展区:固定位置添加所有扩展组件 ==========
// --- 1. 先构建所有扩展页面 ---
// (row 5) Ramp 扩展组件 (原row 5)
m_extRamp = buildExtRampPage();
// (row 6) Multiple Pressures 表格 (原row 6)
m_extMultiP = buildExtMultiPressurePage();
m_extMultiP->setMinimumHeight(80);
// (row 7) Multiple Rates 表格
m_extMultiR = buildExtMultiRatePage();
m_extMultiR->setMinimumHeight(80);
// --- 2. 创建一个空页面---
m_extEmpty = buildExtEmptyPage("");
// --- 3. 创建 QStackedWidget 并添加所有页面 ---
m_extStackedWidget = new QStackedWidget(this);
m_extStackedWidget->addWidget(m_extEmpty); // 页面 0
m_extStackedWidget->addWidget(m_extRamp); // 页面 1
m_extStackedWidget->addWidget(m_extMultiP); // 页面 2
m_extStackedWidget->addWidget(m_extMultiR); // 页面 3
// --- 4. 将 QStackedWidget 添加到布局的固定位置 (row 5) ---
m_parametersLayout->addWidget(m_extStackedWidget, row, 1);
row++; // row 变为 6
parametersOuterLayout->addWidget(baseWidget);
//parametersOuterLayout->addWidget(m_extStackedWidget);
// ========== Buttons ==========
m_buttonLayout = new QHBoxLayout();
m_loadDataButton = new QPushButton("Load data", this);
m_generateButton = new QPushButton("Generate", this);
m_cancelButton = new QPushButton("Cancel", this);
m_loadDataButton->setEnabled(false);
m_buttonLayout->addWidget(m_loadDataButton);
m_buttonLayout->addStretch();
m_buttonLayout->addWidget(m_generateButton);
m_buttonLayout->addWidget(m_cancelButton);
// ========== Main ==========
m_mainLayout->addWidget(m_forecastOptionsGroup);
m_mainLayout->addWidget(m_parametersGroup);
m_mainLayout->addStretch();
m_mainLayout->addLayout(m_buttonLayout);
// 收集所有组件
QList<nmGUIComponentLineEdit*> allComponents;
allComponents.append(m_initialPressureComponent);
allComponents.append(m_abandonmentRateComponent);
allComponents.append(m_maximumRateComponent);
allComponents.append(m_forecastDurationComponent);
allComponents.append(m_producingPressureComponent);
allComponents.append(m_producingPressureEndComponent);
allComponents.append(m_pressureChangePeriodComponent);
// 计算最大标签宽度
int maxLabelWidth = 0;
for(int i = 0; i < allComponents.size(); ++i) {
if(allComponents.at(i)) {
// 获取标签控件(假设是第一个子控件)
QLabel* label = allComponents.at(i)->findChild<QLabel*>();
if(label) {
int w = label->sizeHint().width();
if(w > maxLabelWidth) {
maxLabelWidth = w;
}
}
}
}
// 设置统一的标签宽度(+10 像素余量)
for(int i = 0; i < allComponents.size(); ++i) {
if(allComponents.at(i)) {
QLabel* label = allComponents.at(i)->findChild<QLabel*>();
if(label) {
label->setMinimumWidth(maxLabelWidth + 10);
label->setMaximumWidth(maxLabelWidth + 10);
}
}
}
}
QWidget* nmWxForecast::buildExtEmptyPage(const QString& text)
{
QWidget *root = new QWidget(this);
QVBoxLayout *v = new QVBoxLayout(root);
v->setContentsMargins(0, 0, 0, 0);
if(!text.isEmpty()) {
QLabel *lbl = new QLabel(text, root);
lbl->setAlignment(Qt::AlignCenter);
v->addStretch();
v->addWidget(lbl);
v->addStretch();
} else {
v->addSpacing(1);
}
root->setMinimumHeight(80);
return root;
}
QWidget* nmWxForecast::buildExtMultiPressurePage()
{
QWidget *root = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout(root);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(8);
// 创建表格
m_pressureTableWidget = new QTableWidget(0, 2);
m_pressureTableWidget->setHorizontalHeaderLabels(QStringList() << "Duration" << "Pressure");
m_pressureTableWidget->verticalHeader()->setVisible(false);
m_pressureTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
// 表头下的“单位”行
m_pressureTableWidget->insertRow(0);
m_pressureTableWidget->setRowHeight(0, 24); // 设置一个合适的高度
PressureRow tempDefaults; // 用于获取单位列表
QStringList durationUnits = tempDefaults.duration.getListUnitSelections();
QStringList pressureUnits = tempDefaults.pressure.getListUnitSelections();
// --- 第0列Duration 单位下拉框 ---
m_pDurationUnitCombo = new QComboBox(m_pressureTableWidget);
if(!durationUnits.isEmpty()) {
m_pDurationUnitCombo->addItems(durationUnits);
}
m_pDurationUnitCombo->setCurrentIndex(m_pDurationUnitCombo->findText(m_currentDurationUnit)); // 设置当前单位
// 设置样式
m_pDurationUnitCombo->setEditable(true);
m_pDurationUnitCombo->lineEdit()->setAlignment(Qt::AlignCenter);
m_pDurationUnitCombo->lineEdit()->setReadOnly(true);
m_pDurationUnitCombo->setStyleSheet(
"QComboBox { border: none; background: transparent; padding-left: 4px; }"
"QComboBox::drop-down { border: none; }"
);
m_pressureTableWidget->setCellWidget(0, 0, m_pDurationUnitCombo);
// --- 第1列Pressure 单位下拉框 ---
m_pPressureUnitCombo = new QComboBox(m_pressureTableWidget);
if(!pressureUnits.isEmpty()) {
m_pPressureUnitCombo->addItems(pressureUnits);
}
m_pPressureUnitCombo->setCurrentIndex(m_pPressureUnitCombo->findText(m_currentPressureUnit)); // 设置当前单位
// 设置样式
m_pPressureUnitCombo->setEditable(true);
m_pPressureUnitCombo->lineEdit()->setAlignment(Qt::AlignCenter);
m_pPressureUnitCombo->lineEdit()->setReadOnly(true);
m_pPressureUnitCombo->setStyleSheet(
"QComboBox { border: none; background: transparent; padding-left: 4px; }"
"QComboBox::drop-down { border: none; }"
);
m_pressureTableWidget->setCellWidget(0, 1, m_pPressureUnitCombo);
layout->addWidget(m_pressureTableWidget);
return root;
}
QTableWidgetItem* nmWxForecast::makeCenteredEmptyItem()
{
QTableWidgetItem* it = new QTableWidgetItem();
it->setTextAlignment(Qt::AlignCenter);
return it;
}
QWidget* nmWxForecast::buildExtMultiRatePage()
{
QWidget *root = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout(root);
layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(8);
// 创建表格
m_rateTableWidget = new QTableWidget(0, 2);
// 根据截图设置表头
m_rateTableWidget->setHorizontalHeaderLabels(QStringList() << "Duration" << "Qo");
m_rateTableWidget->verticalHeader()->setVisible(false);
m_rateTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
// 表头下的“单位”行
m_rateTableWidget->insertRow(0);
m_rateTableWidget->setRowHeight(0, 24);
FlowRow tempDefaults; // 使用 FlowRow 获取单位
QStringList durationUnits = tempDefaults.duration.getListUnitSelections();
QStringList rateUnits = tempDefaults.q0.getListUnitSelections(); // 获取速率单位
// --- 第0列Duration 单位下拉框 ---
m_rDurationUnitCombo = new QComboBox(m_rateTableWidget);
if(!durationUnits.isEmpty()) {
m_rDurationUnitCombo->addItems(durationUnits);
}
m_rDurationUnitCombo->setCurrentIndex(m_rDurationUnitCombo->findText(m_currentDurationUnit));
m_rDurationUnitCombo->setEditable(true);
m_rDurationUnitCombo->lineEdit()->setAlignment(Qt::AlignCenter);
m_rDurationUnitCombo->lineEdit()->setReadOnly(true);
m_rDurationUnitCombo->setStyleSheet(
"QComboBox { border: none; background: transparent; padding-left: 4px; }"
"QComboBox::drop-down { border: none; }"
);
m_rateTableWidget->setCellWidget(0, 0, m_rDurationUnitCombo);
// --- 第1列Rate (Qo) 单位下拉框 ---
m_rRateUnitCombo = new QComboBox(m_rateTableWidget);
if(!rateUnits.isEmpty()) {
m_rRateUnitCombo->addItems(rateUnits);
}
m_rRateUnitCombo->setCurrentIndex(m_rRateUnitCombo->findText(m_currentRateUnit)); // 设置当前速率单位
m_rRateUnitCombo->setEditable(true);
m_rRateUnitCombo->lineEdit()->setAlignment(Qt::AlignCenter);
m_rRateUnitCombo->lineEdit()->setReadOnly(true);
m_rRateUnitCombo->setStyleSheet(
"QComboBox { border: none; background: transparent; padding-left: 4px; }"
"QComboBox::drop-down { border: none; }"
);
m_rateTableWidget->setCellWidget(0, 1, m_rRateUnitCombo);
layout->addWidget(m_rateTableWidget);
return root;
}
QWidget* nmWxForecast::buildExtRampPage()
{
QWidget *root = new QWidget(this);
root->setContentsMargins(0, 0, 0, 0);
QVBoxLayout *layout = new QVBoxLayout(root);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(8); // 与基础区一致
// Producing pressure at end
m_producingPressureEndComponent = new nmGUIComponentLineEdit(
&m_forecastData.getDecliningPressureData().getProducingPressureEnd(),
true,
root
);
layout->addWidget(m_producingPressureEndComponent);
// Pressure change period
m_pressureChangePeriodComponent = new nmGUIComponentLineEdit(
&m_forecastData.getDecliningPressureData().getPressureChangePeriod(),
true,
root
);
layout->addWidget(m_pressureChangePeriodComponent);
layout->addStretch(); // 底部弹性空间
root->setMinimumHeight(80);
return root;
}
void nmWxForecast::setupConnections()
{
// Forecast option connections
connect(m_constantPressureRadio, SIGNAL(clicked()), this, SLOT(onConstantPressureSelected()));
connect(m_decliningPressureRadio, SIGNAL(clicked()), this, SLOT(onDecliningPressureSelected()));
connect(m_multiplePressuresRadio, SIGNAL(clicked()), this, SLOT(onMultiplePressuresSelected()));
connect(m_multipleRatesRadio, SIGNAL(clicked()), this, SLOT(onMultipleRatesSelected()));
connect(m_usePastHistoryCheck, SIGNAL(toggled(bool)), this, SLOT(onUsePastHistoryToggled(bool)));
connect(m_surfacePressuresCheck, SIGNAL(toggled(bool)), this, SLOT(onSurfacePressuresToggled(bool)));
// 复选框联动
connect(m_abandonmentRateCheck, SIGNAL(toggled(bool)), this, SLOT(onAbandonmentRateCheckToggled(bool)));
connect(m_maximumRateCheck, SIGNAL(toggled(bool)), this, SLOT(onMaximumRateCheckToggled(bool)));
// Buttons
connect(m_loadDataButton, SIGNAL(clicked()), this, SLOT(onLoadDataClicked()));
connect(m_generateButton, SIGNAL(clicked()), this, SLOT(onGenerateClicked()));
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
// Pressure Table
if(m_pressureTableWidget) {
connect(m_pressureTableWidget, SIGNAL(cellChanged(int, int)), this, SLOT(onPressureCellChanged(int, int)));
}
if(m_pDurationUnitCombo) {
connect(m_pDurationUnitCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onSharedDurationUnitChanged(const QString &)));
}
if(m_pPressureUnitCombo) {
connect(m_pPressureUnitCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onPressureUnitChanged(const QString &)));
}
// Rate Table Connections
if(m_rateTableWidget) {
connect(m_rateTableWidget, SIGNAL(cellChanged(int, int)), this, SLOT(onRateCellChanged(int, int)));
}
if(m_rDurationUnitCombo) {
connect(m_rDurationUnitCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onSharedDurationUnitChanged(const QString &)));
}
if(m_rRateUnitCombo) {
connect(m_rRateUnitCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onRateUnitChanged(const QString &)));
}
}
void nmWxForecast::onAbandonmentRateCheckToggled(bool checked)
{
if(m_abandonmentRateComponent) {
m_abandonmentRateComponent->setEnabled(checked);
}
// 同步到数据模型
nmDataForecast::ForecastOption option = m_forecastData.getForecastOption(); // Get current option
if(option == nmDataForecast::ConstantPressureOption) {
m_forecastData.getConstantPressureData().setIsAbandonmentRate(checked);
} else if(option == nmDataForecast::DecliningPressureOption) {
m_forecastData.getDecliningPressureData().setIsAbandonmentRate(checked);
} else if(option == nmDataForecast::MultiplePressuresOption) {
m_forecastData.getMultiplePressuresData().setIsAbandonmentRate(checked);
}
}
void nmWxForecast::onMaximumRateCheckToggled(bool checked)
{
if(m_maximumRateComponent) {
m_maximumRateComponent->setEnabled(checked);
}
// 同步到数据模型
nmDataForecast::ForecastOption option = m_forecastData.getForecastOption(); // Get current option
if(option == nmDataForecast::ConstantPressureOption) {
m_forecastData.getConstantPressureData().setIsMaximumRate(checked);
} else if(option == nmDataForecast::DecliningPressureOption) {
m_forecastData.getDecliningPressureData().setIsMaximumRate(checked);
} else if(option == nmDataForecast::MultiplePressuresOption) {
m_forecastData.getMultiplePressuresData().setIsMaximumRate(checked);
}
}
void nmWxForecast::onConstantPressureSelected()
{
updateDataFromUI(); // 保存当前界面数据
m_forecastData.setForecastOption(nmDataForecast::ConstantPressureOption);
updateParametersForOption();
}
void nmWxForecast::onDecliningPressureSelected()
{
updateDataFromUI(); // 保存当前界面数据
m_forecastData.setForecastOption(nmDataForecast::DecliningPressureOption);
updateParametersForOption();
}
void nmWxForecast::onMultiplePressuresSelected()
{
updateDataFromUI(); // 保存当前界面数据
m_forecastData.setForecastOption(nmDataForecast::MultiplePressuresOption);
updateParametersForOption();
}
void nmWxForecast::onMultipleRatesSelected()
{
updateDataFromUI(); // 保存当前界面数据
m_forecastData.setForecastOption(nmDataForecast::MultipleRatesOption);
updateParametersForOption();
}
void nmWxForecast::onUsePastHistoryToggled(bool checked)
{
Q_UNUSED(checked);
}
void nmWxForecast::onSurfacePressuresToggled(bool checked)
{
Q_UNUSED(checked);
}
void nmWxForecast::updateParametersForOption()
{
this->setUpdatesEnabled(false);
const nmDataForecast::ForecastOption option = m_forecastData.getForecastOption();
// 默认显示所有基本组件
if (m_abandonmentRateCheck) m_abandonmentRateCheck->setVisible(true);
if (m_abandonmentStack) m_abandonmentStack->setCurrentIndex(0);
if (m_maximumRateCheck) m_maximumRateCheck->setVisible(true);
if (m_maximumStack) m_maximumStack->setCurrentIndex(0);
if (m_forecastDurationComponent) m_forecastDurationComponent->setVisible(true);
if (m_producingPressureComponent) m_producingPressureComponent->setVisible(true);
// 更新各组件的数据源指针并控制显示
if(option == nmDataForecast::ConstantPressureOption) {
ConstantPressure& cpData = m_forecastData.getConstantPressureData();
if(m_initialPressureComponent)
m_initialPressureComponent->setOriginValue(&cpData.getInitialPressure());
if(m_abandonmentRateComponent)
m_abandonmentRateComponent->setOriginValue(&cpData.getAbandonmentRate());
if(m_maximumRateComponent)
m_maximumRateComponent->setOriginValue(&cpData.getMaximumRate());
if(m_forecastDurationComponent)
m_forecastDurationComponent->setOriginValue(&cpData.getForecastDuration());
if(m_producingPressureComponent)
m_producingPressureComponent->setOriginValue(&cpData.getProducingPressure());
if (m_extStackedWidget) m_extStackedWidget->setCurrentWidget(m_extEmpty);
} else if(option == nmDataForecast::DecliningPressureOption) {
DecliningPressure& dpData = m_forecastData.getDecliningPressureData();
if(m_initialPressureComponent)
m_initialPressureComponent->setOriginValue(&dpData.getInitialPressure());
if(m_abandonmentRateComponent)
m_abandonmentRateComponent->setOriginValue(&dpData.getAbandonmentRate());
if(m_maximumRateComponent)
m_maximumRateComponent->setOriginValue(&dpData.getMaximumRate());
if(m_forecastDurationComponent)
m_forecastDurationComponent->setOriginValue(&dpData.getForecastDuration());
if(m_producingPressureComponent)
m_producingPressureComponent->setOriginValue(&dpData.getProducingPressureStart());
if (m_extStackedWidget) m_extStackedWidget->setCurrentWidget(m_extRamp);
} else if(option == nmDataForecast::MultiplePressuresOption) {
MultiplePressures& mpData = m_forecastData.getMultiplePressuresData();
if(m_initialPressureComponent)
m_initialPressureComponent->setOriginValue(&mpData.getInitialPressure());
if(m_abandonmentRateComponent)
m_abandonmentRateComponent->setOriginValue(&mpData.getAbandonmentRate());
if(m_maximumRateComponent)
m_maximumRateComponent->setOriginValue(&mpData.getMaximumRate());
if(m_abandonmentStack) m_abandonmentStack->setCurrentIndex(0);
if(m_maximumStack) m_maximumStack->setCurrentIndex(0);
// 隐藏"Duration"和"Pressure"输入框
if(m_forecastDurationComponent)
m_forecastDurationComponent->setVisible(false);
if(m_producingPressureComponent)
m_producingPressureComponent->setVisible(false);
if (m_extStackedWidget) m_extStackedWidget->setCurrentWidget(m_extMultiP);
} else if(option == nmDataForecast::MultipleRatesOption) {
MultipleRates& mrData = m_forecastData.getMultipleRatesData();
if(m_initialPressureComponent)
m_initialPressureComponent->setOriginValue(&mrData.getInitialPressure());
if (m_abandonmentRateCheck) m_abandonmentRateCheck->setVisible(false);
if (m_abandonmentStack) m_abandonmentStack->setCurrentIndex(1);
if (m_maximumRateCheck) m_maximumRateCheck->setVisible(false);
if (m_maximumStack) m_maximumStack->setCurrentIndex(1);
if (m_forecastDurationComponent) m_forecastDurationComponent->setVisible(false);
if (m_producingPressureComponent) m_producingPressureComponent->setVisible(false);
if (m_extStackedWidget) m_extStackedWidget->setCurrentWidget(m_extMultiR);
}
// 更新界面显示
updateUIFromData();
this->setUpdatesEnabled(true);
this->update();
}
void nmWxForecast::updateUIFromData()
{
const nmDataForecast::ForecastOption option = m_forecastData.getForecastOption();
// 更新复选框状态
// 更新复选框状态
if(option == nmDataForecast::ConstantPressureOption) {
const ConstantPressure& cpData = m_forecastData.getConstantPressureData();
bool isAbandoned = cpData.getIsAbandonmentRate();
bool isMaxRate = cpData.getIsMaximumRate();
m_abandonmentRateCheck->setChecked(isAbandoned);
m_maximumRateCheck->setChecked(isMaxRate);
// 手动设置初始状态
if (m_abandonmentRateComponent) m_abandonmentRateComponent->setEnabled(isAbandoned);
if (m_maximumRateComponent) m_maximumRateComponent->setEnabled(isMaxRate);
} else if(option == nmDataForecast::DecliningPressureOption) {
const DecliningPressure& dpData = m_forecastData.getDecliningPressureData();
bool isAbandoned = dpData.getIsAbandonmentRate();
bool isMaxRate = dpData.getIsMaximumRate();
m_abandonmentRateCheck->setChecked(isAbandoned);
m_maximumRateCheck->setChecked(isMaxRate);
// 手动设置初始状态
if (m_abandonmentRateComponent) m_abandonmentRateComponent->setEnabled(isAbandoned);
if (m_maximumRateComponent) m_maximumRateComponent->setEnabled(isMaxRate);
} else if(option == nmDataForecast::MultiplePressuresOption) {
const MultiplePressures& mpData = m_forecastData.getMultiplePressuresData();
bool isAbandoned = mpData.getIsAbandonmentRate();
bool isMaxRate = mpData.getIsMaximumRate();
m_abandonmentRateCheck->setChecked(isAbandoned);
m_maximumRateCheck->setChecked(isMaxRate);
// 手动设置初始状态
if (m_abandonmentRateComponent) m_abandonmentRateComponent->setEnabled(isAbandoned);
if (m_maximumRateComponent) m_maximumRateComponent->setEnabled(isMaxRate);
}
// 刷新所有组件的显示值
if(m_initialPressureComponent)
m_initialPressureComponent->updateValueFromOrigin();
if(m_abandonmentRateComponent)
m_abandonmentRateComponent->updateValueFromOrigin();
if(m_maximumRateComponent)
m_maximumRateComponent->updateValueFromOrigin();
if(m_forecastDurationComponent)
m_forecastDurationComponent->updateValueFromOrigin();
if(m_producingPressureComponent)
m_producingPressureComponent->updateValueFromOrigin();
if(option == nmDataForecast::DecliningPressureOption) {
if(m_producingPressureEndComponent)
m_producingPressureEndComponent->updateValueFromOrigin();
if(m_pressureChangePeriodComponent)
m_pressureChangePeriodComponent->updateValueFromOrigin();
} else if(option == nmDataForecast::MultiplePressuresOption) {
// 填充压力表格
if(m_pressureTableWidget) {
m_pressureTableWidget->blockSignals(true);
if(m_pDurationUnitCombo) m_pDurationUnitCombo->blockSignals(true);
if(m_pPressureUnitCombo) m_pPressureUnitCombo->blockSignals(true);
// 清空数据行 (保留第0行单位行)
while(m_pressureTableWidget->rowCount() > 1) {
m_pressureTableWidget->removeRow(1);
}
const QVector<PressureRow>& tableData = m_forecastData.getMultiplePressuresData().getPressureTable();
PressureRow tempDefaults; // 用于获取单位列表和默认值
int dataSize = tableData.size();
// 如果数据为空至少显示1行使用默认值否则显示所有数据
int displayRowCount = (dataSize == 0) ? 1 : dataSize;
m_pressureTableWidget->setRowCount(1 + displayRowCount + 1);
if(m_pDurationUnitCombo) m_pDurationUnitCombo->setCurrentIndex(m_pDurationUnitCombo->findText(m_currentDurationUnit));
if(m_pPressureUnitCombo) m_pPressureUnitCombo->setCurrentIndex(m_pPressureUnitCombo->findText(m_currentPressureUnit));
for(int i = 0; i < displayRowCount; ++i) {
// 如果i < dataSize使用加载的数据否则 (即 dataSize==0) 使用默认值
const PressureRow& rowData = (i < dataSize) ? tableData.at(i) : tempDefaults;
int tableRow = i + 1;
// 转换值:从 "数据的基础单位" 转换为 "当前显示的单位"
double baseDurValue = rowData.duration.getValue().toDouble();
QString baseDurUnit = rowData.duration.getUnit();
double displayDurValue = tempDefaults.duration.convertValueByUnitType(baseDurValue, baseDurUnit, m_currentDurationUnit);
double basePresValue = rowData.pressure.getValue().toDouble();
QString basePresUnit = rowData.pressure.getUnit();
double displayPresValue = tempDefaults.pressure.convertValueByUnitType(basePresValue, basePresUnit, m_currentPressureUnit);
QTableWidgetItem* durationItem = new QTableWidgetItem(QString::number(displayDurValue));
durationItem->setTextAlignment(Qt::AlignCenter);
m_pressureTableWidget->setItem(tableRow, 0, durationItem);
QTableWidgetItem* pressureItem = new QTableWidgetItem(QString::number(displayPresValue));
pressureItem->setTextAlignment(Qt::AlignCenter);
m_pressureTableWidget->setItem(tableRow, 1, pressureItem);
}
if (m_pDurationUnitCombo) m_pDurationUnitCombo->blockSignals(false);
if (m_pPressureUnitCombo) m_pPressureUnitCombo->blockSignals(false);
m_pressureTableWidget->blockSignals(false);
}
}
else if(option == nmDataForecast::MultipleRatesOption) {
// 填充速率表格
if(m_rateTableWidget) {
// 锁定信号
m_rateTableWidget->blockSignals(true);
if(m_rDurationUnitCombo) m_rDurationUnitCombo->blockSignals(true);
if(m_rRateUnitCombo) m_rRateUnitCombo->blockSignals(true);
// 清空数据行 (保留第0行单位行)
while(m_rateTableWidget->rowCount() > 1) {
m_rateTableWidget->removeRow(1);
}
const QVector<FlowRow>& tableData = m_forecastData.getMultipleRatesData().getFlowTable();
FlowRow tempDefaults; // 用于获取单位列表和默认值
int dataSize = tableData.size();
int displayRowCount = (dataSize == 0) ? 1 : dataSize;
// 设置行数: 1(单位) + N(数据) + 1(空白)
m_rateTableWidget->setRowCount(1 + displayRowCount + 1);
// 设置下拉框为当前单位
if(m_rDurationUnitCombo) m_rDurationUnitCombo->setCurrentIndex(m_rDurationUnitCombo->findText(m_currentDurationUnit));
if(m_rRateUnitCombo) m_rRateUnitCombo->setCurrentIndex(m_rRateUnitCombo->findText(m_currentRateUnit));
for(int i = 0; i < displayRowCount; ++i) {
// 如果i < dataSize使用加载的数据否则 (即 dataSize==0) 使用默认值
const FlowRow& rowData = (i < dataSize) ? tableData.at(i) : tempDefaults;
int tableRow = i + 1;
// 转换值:从 "数据的基础单位" 转换为 "当前显示的单位"
double baseDurValue = rowData.duration.getValue().toDouble();
QString baseDurUnit = rowData.duration.getUnit();
double displayDurValue = tempDefaults.duration.convertValueByUnitType(baseDurValue, baseDurUnit, m_currentDurationUnit);
double baseRateValue = rowData.q0.getValue().toDouble();
QString baseRateUnit = rowData.q0.getUnit();
double displayRateValue = tempDefaults.q0.convertValueByUnitType(baseRateValue, baseRateUnit, m_currentRateUnit);
QTableWidgetItem* durationItem = new QTableWidgetItem(QString::number(displayDurValue));
durationItem->setTextAlignment(Qt::AlignCenter);
m_rateTableWidget->setItem(tableRow, 0, durationItem);
QTableWidgetItem* rateItem = new QTableWidgetItem(QString::number(displayRateValue));
rateItem->setTextAlignment(Qt::AlignCenter);
m_rateTableWidget->setItem(tableRow, 1, rateItem);
}
// 解锁信号
if (m_rDurationUnitCombo) m_rDurationUnitCombo->blockSignals(false);
if (m_rRateUnitCombo) m_rRateUnitCombo->blockSignals(false);
m_rateTableWidget->blockSignals(false);
}
}
}
void nmWxForecast::updateDataFromUI()
{
// 将界面数据写回到数据模型
if(m_initialPressureComponent)
m_initialPressureComponent->updateValueToOrigin();
if(m_abandonmentRateComponent)
m_abandonmentRateComponent->updateValueToOrigin();
if(m_maximumRateComponent)
m_maximumRateComponent->updateValueToOrigin();
if(m_forecastDurationComponent)
m_forecastDurationComponent->updateValueToOrigin();
if(m_producingPressureComponent)
m_producingPressureComponent->updateValueToOrigin();
const nmDataForecast::ForecastOption option = m_forecastData.getForecastOption();
if(option == nmDataForecast::DecliningPressureOption) {
if(m_producingPressureEndComponent)
m_producingPressureEndComponent->updateValueToOrigin();
if(m_pressureChangePeriodComponent)
m_pressureChangePeriodComponent->updateValueToOrigin();
} else if(option == nmDataForecast::MultiplePressuresOption) {
// 从表格保存数据
if(m_pressureTableWidget) {
QVector<PressureRow>& tableData = m_forecastData.getMultiplePressuresData().getPressureTable();
tableData.clear();
PressureRow tempDefaults;
QString baseDurUnit = tempDefaults.duration.getUnit();
QString basePresUnit = tempDefaults.pressure.getUnit();
// 循环到 rowCount() - 1 来跳过最后那个空白行
for(int i = 1; i < m_pressureTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* durationItem = m_pressureTableWidget->item(i, 0);
QTableWidgetItem* pressureItem = m_pressureTableWidget->item(i, 1);
bool durationEmpty = (durationItem == NULL || durationItem->text().trimmed().isEmpty());
bool pressureEmpty = (pressureItem == NULL || pressureItem->text().trimmed().isEmpty());
if(durationEmpty && pressureEmpty) {
continue;
}
PressureRow newRow; // newRow 包含基础单位 (hr, psia)
if(!durationEmpty) {
double displayVal = durationItem->text().toDouble();
// 转换值:从 "当前显示的单位" 转换回 "数据的基础单位"
double storageVal = tempDefaults.duration.convertValueByUnitType(displayVal, m_currentDurationUnit, baseDurUnit);
newRow.duration.setValue(storageVal);
}
if(!pressureEmpty) {
double displayVal = pressureItem->text().toDouble();
double storageVal = tempDefaults.pressure.convertValueByUnitType(displayVal, m_currentPressureUnit, basePresUnit);
newRow.pressure.setValue(storageVal);
}
tableData.append(newRow);
}
}
}
else if (option == nmDataForecast::MultipleRatesOption) {
// 从速率表格保存数据
if(m_rateTableWidget) {
// 获取数据模型的引用
QVector<FlowRow>& tableData = m_forecastData.getMultipleRatesData().getFlowTable();
tableData.clear();
FlowRow tempDefaults;
// 获取数据模型的基础单位
QString baseDurUnit = tempDefaults.duration.getUnit();
QString baseRateUnit = tempDefaults.q0.getUnit();
// 循环到 rowCount() - 1 来跳过最后那个空白行
for(int i = 1; i < m_rateTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* durationItem = m_rateTableWidget->item(i, 0);
QTableWidgetItem* rateItem = m_rateTableWidget->item(i, 1);
bool durationEmpty = (durationItem == NULL || durationItem->text().trimmed().isEmpty());
bool rateEmpty = (rateItem == NULL || rateItem->text().trimmed().isEmpty());
// 如果两个单元格都为空,则跳过该行
if(durationEmpty && rateEmpty) {
continue;
}
FlowRow newRow; // newRow 将使用基础单位
if(!durationEmpty) {
double displayVal = durationItem->text().toDouble();
// 转换值:从 "当前显示的单位" 转换回 "数据的基础单位"
double storageVal = tempDefaults.duration.convertValueByUnitType(displayVal, m_currentDurationUnit, baseDurUnit);
newRow.duration.setValue(storageVal);
}
if(!rateEmpty) {
double displayVal = rateItem->text().toDouble();
double storageVal = tempDefaults.q0.convertValueByUnitType(displayVal, m_currentRateUnit, baseRateUnit);
newRow.q0.setValue(storageVal);
}
tableData.append(newRow);
}
}
}
}
void nmWxForecast::onLoadDataClicked()
{
// TODO: Implement load data functionality
}
void nmWxForecast::onGenerateClicked()
{
// 确保最新的界面数据写回到模型
updateDataFromUI();
// 保存数据到数据中心
saveDataToManager();
// TODO: 使用数据中心的数据进行预测计算
accept();
}
void nmWxForecast::onCancelClicked()
{
reject();
}
void nmWxForecast::onPressureCellChanged(int row, int column)
{
Q_UNUSED(column);
if (!m_pressureTableWidget) return;
if (row == 0) return; // 忽略单位行
// 让被编辑行的两列都居中
QTableWidgetItem* it0 = m_pressureTableWidget->item(row, 0);
if (it0) it0->setTextAlignment(Qt::AlignCenter);
QTableWidgetItem* it1 = m_pressureTableWidget->item(row, 1);
if (it1) it1->setTextAlignment(Qt::AlignCenter);
// 如果编辑的是最后一行,追加一个新的空白行,并预置居中 item
int lastRow = m_pressureTableWidget->rowCount() - 1;
if (row == lastRow) {
m_pressureTableWidget->blockSignals(true);
int newRow = m_pressureTableWidget->rowCount();
m_pressureTableWidget->insertRow(newRow);
// 给新行两列预置空 item这样用户一输入就居中
m_pressureTableWidget->setItem(newRow, 0, makeCenteredEmptyItem());
m_pressureTableWidget->setItem(newRow, 1, makeCenteredEmptyItem());
m_pressureTableWidget->blockSignals(false);
}
}
void nmWxForecast::onPressureUnitChanged(const QString& unit)
{
if(unit == m_currentPressureUnit) return; // 单位没变
QString oldUnit = m_currentPressureUnit;
m_currentPressureUnit = unit;
// 锁定信号
m_pressureTableWidget->blockSignals(true);
PressureRow tempDefaults; // 用于获取转换函数
// 遍历所有数据行 (从 1 到 rowCount - 2)
for(int i = 1; i < m_pressureTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* dataItem = m_pressureTableWidget->item(i, 1); // 第1列
if(dataItem && !dataItem->text().isEmpty()) {
double oldDisplayValue = dataItem->text().toDouble();
double newDisplayValue = tempDefaults.pressure.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
dataItem->setText(QString::number(newDisplayValue));
}
}
// 解锁信号
m_pressureTableWidget->blockSignals(false);
}
void nmWxForecast::onRateCellChanged(int row, int column)
{
Q_UNUSED(column);
if (!m_rateTableWidget) return;
if (row == 0) return; // 忽略单位行
// 让被编辑行的两列都居中
QTableWidgetItem* it0 = m_rateTableWidget->item(row, 0);
if (it0) it0->setTextAlignment(Qt::AlignCenter);
QTableWidgetItem* it1 = m_rateTableWidget->item(row, 1);
if (it1) it1->setTextAlignment(Qt::AlignCenter);
// 若编辑的是最后一行,则在末尾追加一个新的空白行,并预置居中 item
int lastRow = m_rateTableWidget->rowCount() - 1;
if (row == lastRow) {
m_rateTableWidget->blockSignals(true);
int newRow = m_rateTableWidget->rowCount();
m_rateTableWidget->insertRow(newRow);
m_rateTableWidget->setItem(newRow, 0, makeCenteredEmptyItem());
m_rateTableWidget->setItem(newRow, 1, makeCenteredEmptyItem());
m_rateTableWidget->blockSignals(false);
}
}
void nmWxForecast::onSharedDurationUnitChanged(const QString& unit)
{
// 检查单位是否真的改变了
if(unit.isEmpty() || unit == m_currentDurationUnit) return;
QString oldUnit = m_currentDurationUnit;
m_currentDurationUnit = unit; // 更新全局的当前单位
// --- 1. 更新 Pressure 表格 ---
if(m_pressureTableWidget) {
// 锁定信号防止在setText时触发 cellChanged
m_pressureTableWidget->blockSignals(true);
PressureRow tempDefaults; // 用于获取转换函数
// 遍历所有数据行 (从 1 到 rowCount - 2跳过单位行和最后空白行)
for(int i = 1; i < m_pressureTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* dataItem = m_pressureTableWidget->item(i, 0); // 第0列 (Duration)
if(dataItem && !dataItem->text().isEmpty()) {
double oldDisplayValue = dataItem->text().toDouble();
// 转换值
double newDisplayValue = tempDefaults.duration.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
dataItem->setText(QString::number(newDisplayValue));
}
}
m_pressureTableWidget->blockSignals(false);
}
// --- 2. 更新 Rate 表格 ---
if(m_rateTableWidget) {
// 锁定信号
m_rateTableWidget->blockSignals(true);
FlowRow tempDefaults; // 用于获取转换函数
// 遍历所有数据行
for(int i = 1; i < m_rateTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* dataItem = m_rateTableWidget->item(i, 0); // 第0列 (Duration)
if(dataItem && !dataItem->text().isEmpty()) {
double oldDisplayValue = dataItem->text().toDouble();
// 转换值
double newDisplayValue = tempDefaults.duration.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
dataItem->setText(QString::number(newDisplayValue));
}
}
m_rateTableWidget->blockSignals(false);
}
if(m_pDurationUnitCombo) {
m_pDurationUnitCombo->blockSignals(true);
m_pDurationUnitCombo->setCurrentIndex(m_pDurationUnitCombo->findText(unit));
m_pDurationUnitCombo->blockSignals(false);
}
if(m_rDurationUnitCombo) {
m_rDurationUnitCombo->blockSignals(true);
m_rDurationUnitCombo->setCurrentIndex(m_rDurationUnitCombo->findText(unit));
m_rDurationUnitCombo->blockSignals(false);
}
}
void nmWxForecast::onRateUnitChanged(const QString& unit)
{
if(unit == m_currentRateUnit) return; // 单位没变
QString oldUnit = m_currentRateUnit;
m_currentRateUnit = unit;
// 锁定信号
m_rateTableWidget->blockSignals(true);
FlowRow tempDefaults; // 用于获取转换函数
// 遍历所有数据行 (从 1 到 rowCount - 2)
for(int i = 1; i < m_rateTableWidget->rowCount() - 1; ++i) {
QTableWidgetItem* dataItem = m_rateTableWidget->item(i, 1); // 第1列
if(dataItem && !dataItem->text().isEmpty()) {
double oldDisplayValue = dataItem->text().toDouble();
// 使用 q0 (FlowRate) 进行单位转换
double newDisplayValue = tempDefaults.q0.convertValueByUnitType(oldDisplayValue, oldUnit, unit);
dataItem->setText(QString::number(newDisplayValue));
}
}
// 解锁信号
m_rateTableWidget->blockSignals(false);
}