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++

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 "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);
}