|
|
#include "nmWxPerforationClosing.h"
|
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
#include <QHBoxLayout>
|
|
|
#include <QSplitter>
|
|
|
#include <QTreeWidgetItem>
|
|
|
#include <QHeaderView>
|
|
|
#include <QLabel>
|
|
|
#include <QSpacerItem>
|
|
|
#include <QIcon>
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
#include "nmDataAnalyzeManager.h"
|
|
|
|
|
|
nmWxPerforationClosing::nmWxPerforationClosing(nmDataWellBase* pWellData, QWidget *parent)
|
|
|
: iDlgBase(parent)
|
|
|
{
|
|
|
setWindowTitle(tr("Perforation closing intervals"));
|
|
|
setMinimumSize(500, 625);
|
|
|
|
|
|
// 初始化成员变量
|
|
|
m_currentTimeUnit = "hr";
|
|
|
m_perforationCounter = 1;
|
|
|
m_timeEntryCounter = 0;
|
|
|
m_showDatesMode = false;
|
|
|
m_hasBaseTime = false;
|
|
|
m_pPerforationRoot = 0;
|
|
|
m_pCurrentPerforationItem = 0;
|
|
|
|
|
|
m_currentWell = pWellData;
|
|
|
|
|
|
if(m_currentWell != nullptr) {
|
|
|
int perforationCount = m_currentWell->getPerforationCount();
|
|
|
// 选择操作的射孔段索引
|
|
|
m_currentPerforationIndex = perforationCount - 1;
|
|
|
m_perforationData = m_currentWell->getPerforationCopy(m_currentPerforationIndex);
|
|
|
|
|
|
// 从副本中读取封堵数据
|
|
|
m_baseTimeValues = m_perforationData.getTimeValues();
|
|
|
m_baseTime = m_perforationData.getBaseTime();
|
|
|
m_hasBaseTime = m_baseTime.isValid();
|
|
|
}
|
|
|
|
|
|
// 初始化UI
|
|
|
initUI();
|
|
|
|
|
|
// 连接信号
|
|
|
connect(m_pAddBtn, SIGNAL(clicked()), this, SLOT(onAddClicked()));
|
|
|
connect(m_pRemoveBtn, SIGNAL(clicked()), this, SLOT(onRemoveClicked()));
|
|
|
connect(m_pShowDatesCheckBox, SIGNAL(toggled(bool)), this, SLOT(onShowDatesToggled(bool)));
|
|
|
connect(m_pTimeUnitComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(onTimeUnitChanged(QString)));
|
|
|
connect(m_pAllComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(onAllComboChanged(QString)));
|
|
|
connect(m_pOkBtn, SIGNAL(clicked()), this, SLOT(onOkClicked()));
|
|
|
connect(m_pCancelBtn, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
|
|
|
connect(m_pTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(onItemChanged(QTreeWidgetItem*, int)));
|
|
|
loadDataFromModel();
|
|
|
}
|
|
|
|
|
|
nmWxPerforationClosing::~nmWxPerforationClosing()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::initUI()
|
|
|
{
|
|
|
// 创建主布局
|
|
|
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
|
|
|
|
|
QString appDir = QCoreApplication::applicationDirPath();
|
|
|
appDir = appDir.section('/', 0, -2); // 获取上一级目录
|
|
|
|
|
|
// 创建工具栏容器
|
|
|
QWidget* toolbarContainer = new QWidget(this);
|
|
|
toolbarContainer->setFixedHeight(70);
|
|
|
QHBoxLayout* toolbarLayout = new QHBoxLayout(toolbarContainer);
|
|
|
|
|
|
// 创建Add按钮组合
|
|
|
QWidget* addButtonContainer = new QWidget(this);
|
|
|
QVBoxLayout* addContainerLayout = new QVBoxLayout(addButtonContainer);
|
|
|
addContainerLayout->setSpacing(0);
|
|
|
addContainerLayout->setContentsMargins(2, 2, 2, 2);
|
|
|
|
|
|
m_pAddBtn = new QPushButton(addButtonContainer);
|
|
|
m_pAddBtn->setIcon(QIcon(appDir + "/Res/Icon/nmTimeDepSkin2.png"));
|
|
|
m_pAddBtn->setIconSize(QSize(36, 36));
|
|
|
m_pAddBtn->setFixedSize(40, 40);
|
|
|
|
|
|
QLabel* addTextLabel = new QLabel(tr("Add"), addButtonContainer);
|
|
|
addTextLabel->setAlignment(Qt::AlignCenter);
|
|
|
|
|
|
addContainerLayout->addWidget(m_pAddBtn, 0, Qt::AlignHCenter);
|
|
|
addContainerLayout->addWidget(addTextLabel);
|
|
|
addButtonContainer->setFixedSize(100, 70);
|
|
|
toolbarLayout->addWidget(addButtonContainer);
|
|
|
|
|
|
// 创建Remove按钮组合
|
|
|
QWidget* removeButtonContainer = new QWidget(this);
|
|
|
QVBoxLayout* removeContainerLayout = new QVBoxLayout(removeButtonContainer);
|
|
|
removeContainerLayout->setSpacing(0);
|
|
|
removeContainerLayout->setContentsMargins(2, 2, 2, 2);
|
|
|
|
|
|
m_pRemoveBtn = new QPushButton(removeButtonContainer);
|
|
|
m_pRemoveBtn->setIcon(QIcon(appDir + "/Res/Icon/nmTimeDepSkin3.png"));
|
|
|
m_pRemoveBtn->setIconSize(QSize(36, 36));
|
|
|
m_pRemoveBtn->setFixedSize(40, 40);
|
|
|
|
|
|
QLabel* removeTextLabel = new QLabel(tr("Remove"), removeButtonContainer);
|
|
|
removeTextLabel->setAlignment(Qt::AlignCenter);
|
|
|
|
|
|
removeContainerLayout->addWidget(m_pRemoveBtn, 0, Qt::AlignHCenter);
|
|
|
removeContainerLayout->addWidget(removeTextLabel);
|
|
|
removeButtonContainer->setFixedSize(100, 70);
|
|
|
toolbarLayout->addWidget(removeButtonContainer);
|
|
|
|
|
|
// 添加复选框和时间单位控件组
|
|
|
m_pShowDatesCheckBox = new QCheckBox(tr("Show dates"));
|
|
|
toolbarLayout->addWidget(m_pShowDatesCheckBox);
|
|
|
|
|
|
toolbarLayout->addSpacing(15); // 复选框和时间单位之间的固定间距
|
|
|
|
|
|
m_pTimeUnitLabel = new QLabel(tr("Time unit:")); // 保存指针以便隐藏/显示
|
|
|
toolbarLayout->addWidget(m_pTimeUnitLabel);
|
|
|
|
|
|
toolbarLayout->addSpacing(5); // 标签和下拉框之间的小间距
|
|
|
|
|
|
m_pTimeUnitComboBox = new QComboBox();
|
|
|
m_pTimeUnitComboBox->addItem("ms");
|
|
|
m_pTimeUnitComboBox->addItem("sec");
|
|
|
m_pTimeUnitComboBox->addItem("min");
|
|
|
m_pTimeUnitComboBox->addItem("hr");
|
|
|
m_pTimeUnitComboBox->addItem("day");
|
|
|
m_pTimeUnitComboBox->addItem("week");
|
|
|
m_pTimeUnitComboBox->addItem("month");
|
|
|
m_pTimeUnitComboBox->addItem("year");
|
|
|
m_pTimeUnitComboBox->setCurrentIndex(3); // "hr"
|
|
|
m_pTimeUnitComboBox->setFixedWidth(60);
|
|
|
toolbarLayout->addWidget(m_pTimeUnitComboBox);
|
|
|
|
|
|
// 避免控件贴边
|
|
|
toolbarLayout->addSpacing(10);
|
|
|
|
|
|
// 将工具栏添加到主布局
|
|
|
mainLayout->addWidget(toolbarContainer);
|
|
|
|
|
|
// 创建单个树形表格控件
|
|
|
m_pTreeWidget = new QTreeWidget(this);
|
|
|
m_pTreeWidget->setColumnCount(3);
|
|
|
|
|
|
// 设置表头
|
|
|
QStringList headers;
|
|
|
headers << "" << "" << "";
|
|
|
m_pTreeWidget->setHeaderLabels(headers);
|
|
|
m_pTreeWidget->setHeaderHidden(false); // 显示表头
|
|
|
|
|
|
// 设置列宽
|
|
|
m_pTreeWidget->setColumnWidth(0, 200); // 树形结构列
|
|
|
m_pTreeWidget->setColumnWidth(1, 120); // 时间列
|
|
|
m_pTreeWidget->setColumnWidth(2, 120); // 状态列
|
|
|
|
|
|
// 设置表头拉伸策略
|
|
|
m_pTreeWidget->header()->setStretchLastSection(true);
|
|
|
|
|
|
// 设置树形控件的其他属性
|
|
|
m_pTreeWidget->setRootIsDecorated(true); // 显示根节点的展开/折叠图标
|
|
|
m_pTreeWidget->setAlternatingRowColors(true); // 交替行颜色
|
|
|
m_pTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择
|
|
|
m_pTreeWidget->setIndentation(20); // 设置缩进距离
|
|
|
m_pTreeWidget->setStyleSheet(
|
|
|
"QTreeWidget::branch {"
|
|
|
"background: transparent;"
|
|
|
"border: none;"
|
|
|
"width: 0px;"
|
|
|
"}"
|
|
|
);
|
|
|
|
|
|
// 将树形控件添加到主布局
|
|
|
mainLayout->addWidget(m_pTreeWidget);
|
|
|
|
|
|
if(m_currentWell != nullptr) {
|
|
|
int perforationCount = m_currentWell->getPerforationCount();
|
|
|
|
|
|
// 添加表头行
|
|
|
m_pPerforationRoot = new QTreeWidgetItem(m_pTreeWidget);
|
|
|
m_pPerforationRoot->setText(0, tr("Perforation"));
|
|
|
m_pPerforationRoot->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
|
|
|
|
|
|
// 为每个射孔段添加树形项目
|
|
|
for(int i = 0; i < perforationCount; ++i) {
|
|
|
nmDataPerforation* perforation = m_currentWell->getPerforation(i);
|
|
|
if(perforation) {
|
|
|
QString perforationName = perforation->getName().getValue().toString();
|
|
|
if(perforationName.isEmpty()) {
|
|
|
perforationName = tr("Perforation #%1").arg(i + 1);
|
|
|
}
|
|
|
|
|
|
QTreeWidgetItem* perforationItem = new QTreeWidgetItem(m_pTreeWidget);
|
|
|
perforationItem->setText(0, perforationName);
|
|
|
perforationItem->setExpanded(false); // 默认收起
|
|
|
|
|
|
// 如果是当前选中的射孔段,保存引用
|
|
|
if(i == m_currentPerforationIndex) {
|
|
|
m_pCurrentPerforationItem = perforationItem;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//// 添加第一行"Perforation"
|
|
|
//m_pPerforationRoot = new QTreeWidgetItem(m_pTreeWidget);
|
|
|
//m_pPerforationRoot->setText(0, tr("Perforation"));
|
|
|
//// 设置第一行不可展开(通过设置ChildIndicatorPolicy)
|
|
|
//m_pPerforationRoot->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
|
|
|
|
|
|
//// 添加第二行"Perforation #1"
|
|
|
//m_pCurrentPerforationItem = new QTreeWidgetItem(m_pTreeWidget);
|
|
|
//m_pCurrentPerforationItem->setText(0, tr("Perforation #%1").arg(m_perforationCounter));
|
|
|
//m_pCurrentPerforationItem->setExpanded(false); // 默认收起
|
|
|
////m_pCurrentPerforationItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); // 隐藏展开箭头
|
|
|
|
|
|
// 创建底部按钮区域
|
|
|
QHBoxLayout* bottomLayout = new QHBoxLayout();
|
|
|
bottomLayout->setSpacing(8);
|
|
|
|
|
|
// All下拉框
|
|
|
m_pAllComboBox = new QComboBox();
|
|
|
m_pAllComboBox->addItem(tr("All"));
|
|
|
|
|
|
if(m_currentWell != nullptr) {
|
|
|
int perforationCount = m_currentWell->getPerforationCount();
|
|
|
for(int i = 0; i < perforationCount; ++i) {
|
|
|
nmDataPerforation* perforation = m_currentWell->getPerforation(i);
|
|
|
if(perforation) {
|
|
|
QString perforationName = perforation->getName().getValue().toString();
|
|
|
if(perforationName.isEmpty()) {
|
|
|
perforationName = tr("Perforation #%1").arg(i + 1);
|
|
|
}
|
|
|
m_pAllComboBox->addItem(perforationName);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
m_pAllComboBox->setFixedWidth(120); // 增加宽度以适应射孔段名称
|
|
|
//m_pAllComboBox = new QComboBox();
|
|
|
//m_pAllComboBox->addItem(tr("All"));
|
|
|
//m_pAllComboBox->addItem(tr("Option 1"));
|
|
|
//m_pAllComboBox->addItem(tr("Option 2"));
|
|
|
//m_pAllComboBox->setFixedWidth(80);
|
|
|
|
|
|
bottomLayout->addWidget(m_pAllComboBox);
|
|
|
bottomLayout->addStretch();
|
|
|
|
|
|
// OK和Cancel按钮
|
|
|
m_pOkBtn = new QPushButton(tr("OK"));
|
|
|
m_pCancelBtn = new QPushButton(tr("Cancel"));
|
|
|
|
|
|
m_pOkBtn->setFixedWidth(75);
|
|
|
m_pCancelBtn->setFixedWidth(75);
|
|
|
|
|
|
bottomLayout->addWidget(m_pOkBtn);
|
|
|
bottomLayout->addWidget(m_pCancelBtn);
|
|
|
|
|
|
// 将底部布局添加到主布局
|
|
|
mainLayout->addLayout(bottomLayout);
|
|
|
|
|
|
// 设置主布局的边距和间距
|
|
|
mainLayout->setContentsMargins(10, 10, 10, 10);
|
|
|
mainLayout->setSpacing(5);
|
|
|
}
|
|
|
|
|
|
QString nmWxPerforationClosing::formatNumber(double value)
|
|
|
{
|
|
|
// 如果数值很大或很小,使用科学计数法
|
|
|
if(qAbs(value) >= 1000000.0 || (qAbs(value) < 0.001 && value != 0.0)) {
|
|
|
return QString::number(value, 'e', 5); // 科学计数法,5位小数
|
|
|
} else {
|
|
|
return QString::number(value, 'f', 5); // 固定小数点格式,5位小数
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onAddClicked()
|
|
|
{
|
|
|
if(!m_pCurrentPerforationItem)
|
|
|
return;
|
|
|
|
|
|
// 只在第一次Add时记录基准时间
|
|
|
if(!m_hasBaseTime) {
|
|
|
m_baseTime = QDateTime::currentDateTime();
|
|
|
m_hasBaseTime = true;
|
|
|
}
|
|
|
|
|
|
// 直接基于 m_baseTimeValues 来决定要添加的值
|
|
|
QList<double> newValuesInHr;
|
|
|
|
|
|
if(m_baseTimeValues.isEmpty()) {
|
|
|
// 第一次Add:添加100.0小时
|
|
|
newValuesInHr.append(100.0);
|
|
|
} else if(m_baseTimeValues.size() == 1) {
|
|
|
// 第二次Add:添加200.0小时
|
|
|
newValuesInHr.append(200.0);
|
|
|
} else {
|
|
|
// 第三次及以后:只在第一个区间中插入两个点
|
|
|
QList<double> sortedValues = m_baseTimeValues;
|
|
|
std::sort(sortedValues.begin(), sortedValues.end());
|
|
|
|
|
|
// 只在第一个区间插入两个均匀分布的点
|
|
|
if(sortedValues.size() >= 2) {
|
|
|
double start = sortedValues[0];
|
|
|
double end = sortedValues[1];
|
|
|
double interval = (end - start) / 3.0;
|
|
|
|
|
|
newValuesInHr.append(start + interval);
|
|
|
newValuesInHr.append(start + 2 * interval);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 合并原有数值和新数值,然后排序
|
|
|
m_baseTimeValues.append(newValuesInHr);
|
|
|
std::sort(m_baseTimeValues.begin(), m_baseTimeValues.end());
|
|
|
|
|
|
// 刷新显示
|
|
|
refreshDisplay();
|
|
|
|
|
|
// 展开Perforation #1项目以显示新添加的内容
|
|
|
m_pCurrentPerforationItem->setExpanded(true);
|
|
|
|
|
|
// 更新计数器
|
|
|
m_timeEntryCounter = m_baseTimeValues.size();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onRemoveClicked()
|
|
|
{
|
|
|
if(!m_pCurrentPerforationItem)
|
|
|
return;
|
|
|
|
|
|
QTreeWidgetItem* selectedItem = m_pTreeWidget->currentItem();
|
|
|
bool hasSelection = false;
|
|
|
int selectedIndex = -1;
|
|
|
|
|
|
// 在日期模式和数值模式下都能正确识别有效行
|
|
|
if(selectedItem && selectedItem->parent() == m_pCurrentPerforationItem &&
|
|
|
selectedItem->text(0) != tr("Start time")) {
|
|
|
// 检查是否是有效的数据行
|
|
|
bool isValidDataRow = false;
|
|
|
|
|
|
if(m_showDatesMode) {
|
|
|
// 日期模式下检查第0列是否有时间数据
|
|
|
isValidDataRow = !selectedItem->text(0).isEmpty() &&
|
|
|
QDateTime::fromString(selectedItem->text(0), "yyyy-MM-dd hh:mm:ss").isValid();
|
|
|
} else {
|
|
|
// 数值模式下检查第1列是否有数值数据
|
|
|
isValidDataRow = !selectedItem->text(1).isEmpty();
|
|
|
}
|
|
|
|
|
|
if(isValidDataRow) {
|
|
|
// 计算选中项在数据中的索引
|
|
|
int dataIndex = 0;
|
|
|
|
|
|
for(int i = 0; i < m_pCurrentPerforationItem->childCount(); i++) {
|
|
|
QTreeWidgetItem* child = m_pCurrentPerforationItem->child(i);
|
|
|
if(child == nullptr) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if(child == selectedItem) {
|
|
|
selectedIndex = dataIndex;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if(child->text(0) != tr("Start time")) {
|
|
|
dataIndex++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
hasSelection = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QList<double> timeValuesInHr = m_baseTimeValues;
|
|
|
|
|
|
if(timeValuesInHr.isEmpty())
|
|
|
return;
|
|
|
|
|
|
qSort(timeValuesInHr.begin(), timeValuesInHr.end());
|
|
|
|
|
|
if(hasSelection && selectedIndex >= 0 && selectedIndex < timeValuesInHr.size()) {
|
|
|
timeValuesInHr.removeAt(selectedIndex);
|
|
|
} else if(!timeValuesInHr.isEmpty()) {
|
|
|
timeValuesInHr.removeLast();
|
|
|
}
|
|
|
|
|
|
m_baseTimeValues = timeValuesInHr;
|
|
|
|
|
|
if(m_baseTimeValues.isEmpty()) {
|
|
|
m_hasBaseTime = false;
|
|
|
}
|
|
|
|
|
|
refreshDisplay();
|
|
|
m_timeEntryCounter = timeValuesInHr.size();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::refreshDisplay()
|
|
|
{
|
|
|
if(!m_pCurrentPerforationItem) return;
|
|
|
|
|
|
m_pTreeWidget->blockSignals(true);
|
|
|
|
|
|
// 清理除“Start time”外的子行
|
|
|
for(int i = m_pCurrentPerforationItem->childCount() - 1; i >= 0; --i) {
|
|
|
QTreeWidgetItem* it = m_pCurrentPerforationItem->child(i);
|
|
|
if(it == nullptr) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if(it->text(0) != tr("Start time")) {
|
|
|
m_pCurrentPerforationItem->removeChild(it);
|
|
|
delete it;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如有数据,确保有“Start time”行
|
|
|
if(!m_baseTimeValues.isEmpty()) {
|
|
|
bool hasStart = false;
|
|
|
|
|
|
for(int i = 0; i < m_pCurrentPerforationItem->childCount(); ++i) {
|
|
|
QTreeWidgetItem* child = m_pCurrentPerforationItem->child(i);
|
|
|
if(child != nullptr && child->text(0) == tr("Start time")) {
|
|
|
hasStart = true; break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(!hasStart) {
|
|
|
QTreeWidgetItem* startTimeItem = new QTreeWidgetItem(m_pCurrentPerforationItem);
|
|
|
startTimeItem->setText(0, tr("Start time"));
|
|
|
startTimeItem->setText(2, tr("Perforation state"));
|
|
|
startTimeItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for(int i = 0; i < m_baseTimeValues.size(); ++i) {
|
|
|
QTreeWidgetItem* row = new QTreeWidgetItem(m_pCurrentPerforationItem);
|
|
|
|
|
|
// 先把 “小时” -> “秒”
|
|
|
const double secQuant = toSecondsQuantized(m_baseTimeValues[i], "hr");
|
|
|
|
|
|
if(m_showDatesMode && m_hasBaseTime) {
|
|
|
// 用整数秒 + 基准时间显示;
|
|
|
const auto dt = m_baseTime.addSecs(static_cast<qint64>(secQuant));
|
|
|
row->setText(0, dt.toString("yyyy-MM-dd hh:mm:ss"));
|
|
|
row->setText(1, "");
|
|
|
row->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
row->setFlags(row->flags() | Qt::ItemIsEditable);
|
|
|
} else {
|
|
|
// 数值模式:整数秒 -> 当前显示单位
|
|
|
const double dispVal = fromSeconds(secQuant, m_currentTimeUnit);
|
|
|
row->setText(0, "");
|
|
|
row->setText(1, formatNumber(dispVal));
|
|
|
row->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
|
|
|
row->setFlags(row->flags() | Qt::ItemIsEditable);
|
|
|
}
|
|
|
|
|
|
const QString state = (i % 2 == 0) ? tr("Closed") : tr("Open");
|
|
|
row->setText(2, state);
|
|
|
row->setTextAlignment(2, Qt::AlignCenter | Qt::AlignVCenter);
|
|
|
row->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
|
|
|
}
|
|
|
|
|
|
m_pTreeWidget->blockSignals(false);
|
|
|
|
|
|
if(!m_baseTimeValues.isEmpty()) {
|
|
|
m_pCurrentPerforationItem->setExpanded(true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onTimeUnitChanged(const QString &unit)
|
|
|
{
|
|
|
// 更新当前时间单位
|
|
|
m_currentTimeUnit = unit;
|
|
|
|
|
|
// 刷新显示
|
|
|
refreshDisplay();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onShowDatesToggled(bool checked)
|
|
|
{
|
|
|
m_showDatesMode = checked;
|
|
|
|
|
|
// 根据复选框状态隐藏/显示时间单位相关控件
|
|
|
m_pTimeUnitLabel->setVisible(!checked);
|
|
|
m_pTimeUnitComboBox->setVisible(!checked);
|
|
|
|
|
|
// 刷新显示
|
|
|
refreshDisplay();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onAllComboChanged(const QString &text)
|
|
|
{
|
|
|
if(!m_currentWell) return;
|
|
|
|
|
|
if(text == tr("All")) {
|
|
|
// 显示所有射孔段的树形项目
|
|
|
showAllPerforationItems();
|
|
|
} else {
|
|
|
// 显示特定射孔段的树形项目
|
|
|
int perforationIndex = findPerforationIndexByName(text);
|
|
|
if(perforationIndex >= 0) {
|
|
|
showSpecificPerforationItem(perforationIndex);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::showAllPerforationItems()
|
|
|
{
|
|
|
if(!m_pTreeWidget) return;
|
|
|
|
|
|
// 显示所有射孔段项目
|
|
|
for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); ++i) {
|
|
|
QTreeWidgetItem* item = m_pTreeWidget->topLevelItem(i);
|
|
|
if(item && item != m_pPerforationRoot) {
|
|
|
item->setHidden(false);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::showSpecificPerforationItem(int perforationIndex)
|
|
|
{
|
|
|
if(!m_pTreeWidget || !m_currentWell) return;
|
|
|
|
|
|
// 隐藏所有射孔段项目
|
|
|
for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); ++i) {
|
|
|
QTreeWidgetItem* item = m_pTreeWidget->topLevelItem(i);
|
|
|
if(item && item != m_pPerforationRoot) {
|
|
|
item->setHidden(true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 只显示指定的射孔段项目
|
|
|
int itemIndex = perforationIndex + 1; // +1是因为第0项是表头
|
|
|
if(itemIndex < m_pTreeWidget->topLevelItemCount()) {
|
|
|
QTreeWidgetItem* item = m_pTreeWidget->topLevelItem(itemIndex);
|
|
|
if(item) {
|
|
|
item->setHidden(false);
|
|
|
item->setExpanded(true); // 展开显示内容
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int nmWxPerforationClosing::findPerforationIndexByName(const QString& name)
|
|
|
{
|
|
|
if(!m_currentWell) return -1;
|
|
|
|
|
|
int perforationCount = m_currentWell->getPerforationCount();
|
|
|
for(int i = 0; i < perforationCount; ++i) {
|
|
|
nmDataPerforation* perforation = m_currentWell->getPerforation(i);
|
|
|
if(perforation) {
|
|
|
QString perforationName = perforation->getName().getValue().toString();
|
|
|
if(perforationName.isEmpty()) {
|
|
|
perforationName = tr("Perforation #%1").arg(i + 1);
|
|
|
}
|
|
|
if(perforationName == name) {
|
|
|
return i;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onOkClicked()
|
|
|
{
|
|
|
saveDataToModel();
|
|
|
// 验证数据并接受对话框
|
|
|
accept();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onCancelClicked()
|
|
|
{
|
|
|
// 取消对话框
|
|
|
reject();
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::onItemChanged(QTreeWidgetItem* item, int column)
|
|
|
{
|
|
|
// 添加一个静态变量防止递归调用
|
|
|
static bool isProcessingItemChange = false;
|
|
|
|
|
|
if(isProcessingItemChange) return;
|
|
|
|
|
|
// 只处理数值行的编辑(排除Start time行)
|
|
|
if(!item || item->text(0) == tr("Start time")) return;
|
|
|
|
|
|
// 确保是子项
|
|
|
if(item->parent() != m_pCurrentPerforationItem) return;
|
|
|
|
|
|
// 根据显示模式处理不同列的编辑
|
|
|
if(m_showDatesMode && column == 0) {
|
|
|
// 日期模式下编辑第0列(时间字符串)
|
|
|
processDateEdit(item);
|
|
|
} else if(!m_showDatesMode && column == 1) {
|
|
|
// 数值模式下编辑第1列(数值)
|
|
|
processValueEdit(item);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::processDateEdit(QTreeWidgetItem* item)
|
|
|
{
|
|
|
static bool guard = false;
|
|
|
|
|
|
if(guard) return;
|
|
|
|
|
|
guard = true;
|
|
|
|
|
|
const QString s = item->text(0);
|
|
|
const QDateTime dt = QDateTime::fromString(s, "yyyy-MM-dd hh:mm:ss");
|
|
|
|
|
|
if(!dt.isValid()) {
|
|
|
guard = false;
|
|
|
refreshDisplay();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// Qt 返回整数秒差(内部是 qint64),我们直接转 double 使用,不声明 qint64 变量
|
|
|
const double newHr = static_cast<double>(m_baseTime.secsTo(dt)) / 3600.0;
|
|
|
|
|
|
// 定位该项索引
|
|
|
int itemIndex = -1, dataIdx = 0;
|
|
|
|
|
|
for(int i = 0; i < m_pCurrentPerforationItem->childCount(); ++i) {
|
|
|
QTreeWidgetItem* ch = m_pCurrentPerforationItem->child(i);
|
|
|
if(ch == nullptr) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if(ch == item) {
|
|
|
itemIndex = dataIdx;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if(ch->text(0) != tr("Start time")) dataIdx++;
|
|
|
}
|
|
|
|
|
|
if(itemIndex >= 0 && itemIndex < m_baseTimeValues.size()) {
|
|
|
QList<double> sorted = m_baseTimeValues;
|
|
|
std::sort(sorted.begin(), sorted.end());
|
|
|
|
|
|
const double currentHr = m_baseTimeValues[itemIndex];
|
|
|
int sortedIndex = -1;
|
|
|
|
|
|
for(int i = 0; i < sorted.size(); ++i) {
|
|
|
if(qAbs(sorted[i] - currentHr) < 1e-6) {
|
|
|
sortedIndex = i;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(sortedIndex >= 0) {
|
|
|
const double minAllowed = (sortedIndex > 0) ? sorted[sortedIndex - 1] : -std::numeric_limits<double>::max();
|
|
|
const double maxAllowed = (sortedIndex < sorted.size() - 1) ? sorted[sortedIndex + 1] : std::numeric_limits<double>::max();
|
|
|
|
|
|
if(newHr <= minAllowed || newHr >= maxAllowed) {
|
|
|
guard = false; refreshDisplay(); return;
|
|
|
}
|
|
|
|
|
|
m_baseTimeValues[itemIndex] = newHr;
|
|
|
std::sort(m_baseTimeValues.begin(), m_baseTimeValues.end());
|
|
|
refreshDisplay();
|
|
|
} else {
|
|
|
guard = false; refreshDisplay(); return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
guard = false;
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::processValueEdit(QTreeWidgetItem* item)
|
|
|
{
|
|
|
static bool guard = false;
|
|
|
|
|
|
if(guard) return;
|
|
|
|
|
|
guard = true;
|
|
|
|
|
|
bool ok = false;
|
|
|
const double newDisp = item->text(1).toDouble(&ok);
|
|
|
|
|
|
if(!ok) {
|
|
|
guard = false;
|
|
|
refreshDisplay();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 显示单位 -> “秒(四舍五入为整数秒,double)” -> “小时”
|
|
|
const double secQuant = toSecondsQuantized(newDisp, m_currentTimeUnit);
|
|
|
const double newHr = fromSeconds(secQuant, "hr");
|
|
|
|
|
|
// 找到该行对应的数据索引(跳过 Start time 行)
|
|
|
int itemIndex = -1, dataIdx = 0;
|
|
|
|
|
|
for(int i = 0; i < m_pCurrentPerforationItem->childCount(); ++i) {
|
|
|
QTreeWidgetItem* ch = m_pCurrentPerforationItem->child(i);
|
|
|
if(ch == nullptr) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if(ch == item) {
|
|
|
itemIndex = dataIdx;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if(ch->text(0) != tr("Start time")) dataIdx++;
|
|
|
}
|
|
|
|
|
|
if(itemIndex >= 0 && itemIndex < m_baseTimeValues.size()) {
|
|
|
// 相邻不越界检查(基于排序副本)
|
|
|
QList<double> sorted = m_baseTimeValues;
|
|
|
std::sort(sorted.begin(), sorted.end());
|
|
|
|
|
|
const double currentHr = m_baseTimeValues[itemIndex];
|
|
|
int sortedIndex = -1;
|
|
|
|
|
|
for(int i = 0; i < sorted.size(); ++i) {
|
|
|
if(qAbs(sorted[i] - currentHr) < 1e-6) {
|
|
|
sortedIndex = i;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(sortedIndex >= 0) {
|
|
|
const double minAllowed = (sortedIndex > 0) ? sorted[sortedIndex - 1] : -std::numeric_limits<double>::max();
|
|
|
const double maxAllowed = (sortedIndex < sorted.size() - 1) ? sorted[sortedIndex + 1] : std::numeric_limits<double>::max();
|
|
|
|
|
|
if(newHr <= minAllowed || newHr >= maxAllowed) {
|
|
|
guard = false; refreshDisplay(); return;
|
|
|
}
|
|
|
|
|
|
m_baseTimeValues[itemIndex] = newHr;
|
|
|
std::sort(m_baseTimeValues.begin(), m_baseTimeValues.end());
|
|
|
refreshDisplay();
|
|
|
} else {
|
|
|
guard = false; refreshDisplay(); return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
guard = false;
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::saveDataToModel()
|
|
|
{
|
|
|
// 将界面数据保存到副本中
|
|
|
m_perforationData.setTimeValues(m_baseTimeValues);
|
|
|
|
|
|
// 生成状态数组
|
|
|
QStringList states;
|
|
|
|
|
|
for(int i = 0; i < m_baseTimeValues.size(); ++i) {
|
|
|
QString state = (i % 2 == 0) ? tr("Closed") : tr("Open");
|
|
|
states.append(state);
|
|
|
}
|
|
|
|
|
|
m_perforationData.setTimeStates(states);
|
|
|
|
|
|
// 保存基准时间(如果有的话)
|
|
|
if(m_hasBaseTime && m_baseTime.isValid()) {
|
|
|
m_perforationData.setBaseTime(m_baseTime);
|
|
|
}
|
|
|
|
|
|
m_currentWell->updatePerforation(m_currentPerforationIndex, m_perforationData);
|
|
|
|
|
|
}
|
|
|
|
|
|
void nmWxPerforationClosing::loadDataFromModel()
|
|
|
{
|
|
|
// 直接获取时间值数据
|
|
|
m_baseTimeValues = m_perforationData.getTimeValues();
|
|
|
|
|
|
// 恢复基准时间
|
|
|
QDateTime savedBaseTime = m_perforationData.getBaseTime();
|
|
|
|
|
|
if(savedBaseTime.isValid()) {
|
|
|
m_baseTime = savedBaseTime;
|
|
|
m_hasBaseTime = true;
|
|
|
} else {
|
|
|
m_hasBaseTime = false;
|
|
|
}
|
|
|
|
|
|
// 更新计数器
|
|
|
m_timeEntryCounter = m_baseTimeValues.size();
|
|
|
|
|
|
// 刷新界面显示
|
|
|
refreshDisplay();
|
|
|
}
|
|
|
|
|
|
double nmWxPerforationClosing::convertTime(double value, const QString& fromUnit, const QString& toUnit) const
|
|
|
{
|
|
|
nmDataAttribute a;
|
|
|
a.setAttributeUnitType(UNIT_TYPE_TIME);
|
|
|
return a.convertValueByUnitType(value, fromUnit, toUnit);
|
|
|
}
|
|
|
|
|
|
double nmWxPerforationClosing::roundToSecondDouble(double sec) const
|
|
|
{
|
|
|
return (sec >= 0.0) ? std::floor(sec + 0.5) : std::ceil(sec - 0.5);
|
|
|
}
|
|
|
|
|
|
double nmWxPerforationClosing::toSecondsQuantized(double value, const QString& unit) const
|
|
|
{
|
|
|
const double sec = convertTime(value, unit, "sec");
|
|
|
return roundToSecondDouble(sec); // 量化
|
|
|
}
|
|
|
|
|
|
double nmWxPerforationClosing::fromSeconds(double sec, const QString& unit) const
|
|
|
{
|
|
|
return convertTime(sec, "sec", unit);
|
|
|
}
|