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

1361 lines
48 KiB
C++

#include "nmWxPebiResultViewWidget.h"
#include "iUnitGroup.h"
#include "iUnitHelper.h"
#include "nmDataAnalyzeManager.h"
#include "nmFFmpegVideoWriter.h"
#include "nmPebiResultAnimationExporter.h"
#include "nmPebiResultDisplaySettings.h"
#include "nmPebiResultPlaybackController.h"
#include "nmPebiResultPropertyCatalog.h"
#include "nmPebiResultPropertyDisplayText.h"
#include "nmPebiResultSceneController.h"
#include "nmPebiResultSnapshot.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKViewCommandController.h"
#include "nmWxPebiResultControlBar.h"
#include "nmWxPebiResultAnimationExportDlg.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QAction>
#include <QAtomicInt>
#include <QCheckBox>
#include <QComboBox>
#include <QCoreApplication>
#include <QDir>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QLocale>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QProgressDialog>
#include <QPushButton>
#include <QSize>
#include <QSizePolicy>
#include <QThread>
#include <QToolBar>
#include <QVBoxLayout>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <math.h>
#if !defined(_MSC_VER)
#include <cmath>
#endif
namespace {
QAtomicInt g_nPebiAnimationExportActive(0);
QString resultViewIconPath(const QString& sFileName)
{
const QString sApplicationDir = QCoreApplication::applicationDirPath();
return sApplicationDir.section('/', 0, -2) +
"/Res/Icon/" + sFileName;
}
bool isResultViewGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == nullptr ||
pApplication->thread() == QThread::currentThread();
}
void setActionCheckedWithoutSignal(QAction* pAction, bool bChecked)
{
if(pAction == nullptr) {
return;
}
const bool bBlocked = pAction->blockSignals(true);
pAction->setChecked(bChecked);
pAction->blockSignals(bBlocked);
}
bool isFiniteFilterEditorValue(double dValue)
{
#if defined(_MSC_VER)
return _finite(dValue) != 0;
#else
return std::isfinite(dValue);
#endif
}
class AnimationExportGuard
{
public:
explicit AnimationExportGuard(nmWxPebiResultControlBar* pControlBar)
: m_pControlBar(pControlBar),
m_bAcquired(g_nPebiAnimationExportActive.testAndSetOrdered(0, 1))
{
if(m_bAcquired && m_pControlBar != nullptr) {
m_pControlBar->setExportInProgress(true);
}
}
~AnimationExportGuard()
{
release();
}
void release()
{
if(!m_bAcquired) {
return;
}
if(m_pControlBar != nullptr) {
m_pControlBar->setExportInProgress(false);
}
g_nPebiAnimationExportActive.fetchAndStoreOrdered(0);
m_bAcquired = false;
}
bool isAcquired() const
{
return m_bAcquired;
}
private:
QPointer<nmWxPebiResultControlBar> m_pControlBar;
bool m_bAcquired;
};
}
nmWxPebiResultFilterSettingsDlg::nmWxPebiResultFilterSettingsDlg(
nmPebiResultSceneController* pSceneController,
nmWxPebiResultControlBar* pControlBar,
QWidget* pParent)
: iDlgBase(pParent),
m_pSceneController(pSceneController),
m_pControlBar(pControlBar),
m_nExpectedBindingRevision(0),
m_nExpectedDisplayFrameIndex(-1),
m_pUnitGroup(nullptr),
m_bInitialized(false),
m_pEnableCheck(nullptr),
m_pPropertyCombo(nullptr),
m_pMinimumCheck(nullptr),
m_pMinimumEdit(nullptr),
m_pMaximumCheck(nullptr),
m_pMaximumEdit(nullptr),
m_pUnitCombo(nullptr),
m_pApplyButton(nullptr),
m_pOkButton(nullptr)
{
createUi();
m_bInitialized = initializeFromScene();
if(!m_bInitialized) {
m_pApplyButton->setEnabled(false);
m_pOkButton->setEnabled(false);
QMessageBox::warning(
this, tr("Filtering settings"),
tr("Unable to read the current result filter settings."));
}
}
nmWxPebiResultFilterSettingsDlg::~nmWxPebiResultFilterSettingsDlg()
{
}
void nmWxPebiResultFilterSettingsDlg::createUi()
{
setWindowTitle(tr("Filtering settings"));
setModal(true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_pEnableCheck = new QCheckBox(tr("Enable filtering"), this);
m_pPropertyCombo = new QComboBox(this);
m_pPropertyCombo->setSizeAdjustPolicy(
QComboBox::AdjustToContentsOnFirstShow);
m_pPropertyCombo->setMinimumWidth(220);
m_pMinimumCheck = new QCheckBox(tr("Above min (>=)"), this);
m_pMinimumEdit = new QLineEdit(this);
m_pMinimumEdit->setAlignment(Qt::AlignRight);
m_pMaximumCheck = new QCheckBox(tr("Below max (<=)"), this);
m_pMaximumEdit = new QLineEdit(this);
m_pMaximumEdit->setAlignment(Qt::AlignRight);
m_pUnitCombo = new QComboBox(this);
m_pUnitCombo->setMinimumWidth(80);
m_pUnitCombo->setMaximumWidth(140);
m_pUnitCombo->hide();
m_pMinimumEdit->setMinimumWidth(150);
m_pMaximumEdit->setMinimumWidth(150);
QGridLayout* pFieldsLayout = new QGridLayout();
pFieldsLayout->setContentsMargins(0, 0, 0, 0);
pFieldsLayout->setHorizontalSpacing(8);
pFieldsLayout->setVerticalSpacing(6);
pFieldsLayout->addWidget(m_pEnableCheck, 0, 0, 1, 3);
QLabel* pPropertyLabel = new QLabel(tr("Filter on"), this);
pPropertyLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pFieldsLayout->addWidget(pPropertyLabel, 1, 0);
pFieldsLayout->addWidget(m_pPropertyCombo, 1, 1, 1, 2);
pFieldsLayout->addWidget(m_pMinimumCheck, 2, 0);
pFieldsLayout->addWidget(m_pMinimumEdit, 2, 1);
pFieldsLayout->addWidget(m_pUnitCombo, 2, 2, 2, 1,
Qt::AlignVCenter);
pFieldsLayout->addWidget(m_pMaximumCheck, 3, 0);
pFieldsLayout->addWidget(m_pMaximumEdit, 3, 1);
pFieldsLayout->setColumnStretch(1, 1);
// 普通布局不受平台按钮顺序策略影响,始终保持应用、确定、取消。
QHBoxLayout* pButtonLayout = new QHBoxLayout();
pButtonLayout->addStretch();
m_pApplyButton = new QPushButton(tr("Apply"), this);
m_pOkButton = new QPushButton(tr("OK"), this);
QPushButton* pCancelButton = new QPushButton(tr("Cancel"), this);
const QSize oFooterIconSize(16, 16);
m_pOkButton->setIcon(QIcon(resultViewIconPath("OK.png")));
pCancelButton->setIcon(QIcon(resultViewIconPath("Cancel.png")));
m_pOkButton->setIconSize(oFooterIconSize);
pCancelButton->setIconSize(oFooterIconSize);
m_pApplyButton->setMinimumWidth(72);
m_pOkButton->setMinimumWidth(72);
pCancelButton->setMinimumWidth(72);
m_pApplyButton->setAutoDefault(false);
m_pOkButton->setDefault(true);
pCancelButton->setAutoDefault(false);
pButtonLayout->setContentsMargins(4, 2, 4, 5);
pButtonLayout->setSpacing(6);
pButtonLayout->addWidget(m_pApplyButton);
pButtonLayout->addWidget(m_pOkButton);
pButtonLayout->addWidget(pCancelButton);
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(12, 10, 12, 0);
pMainLayout->setSpacing(8);
pMainLayout->addLayout(pFieldsLayout);
pMainLayout->addLayout(pButtonLayout);
setMinimumWidth(430);
connect(m_pApplyButton, SIGNAL(clicked()),
this, SLOT(onApplyClicked()));
connect(m_pOkButton, SIGNAL(clicked()),
this, SLOT(onOkClicked()));
connect(pCancelButton, SIGNAL(clicked()),
this, SLOT(reject()));
connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onPropertyChanged(int)));
connect(m_pUnitCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onDisplayUnitChanged(int)));
connect(m_pEnableCheck, SIGNAL(toggled(bool)),
this, SLOT(refreshEditorEnabledState()));
connect(m_pMinimumCheck, SIGNAL(toggled(bool)),
this, SLOT(refreshEditorEnabledState()));
connect(m_pMaximumCheck, SIGNAL(toggled(bool)),
this, SLOT(refreshEditorEnabledState()));
}
bool nmWxPebiResultFilterSettingsDlg::initializeFromScene()
{
if(m_pSceneController == nullptr || m_pControlBar == nullptr ||
!m_pSceneController->hasSnapshot()) {
return false;
}
m_nExpectedBindingRevision =
m_pSceneController->getSnapshotBindingRevision();
m_sExpectedSnapshotId = m_pSceneController->getCurrentSnapshotId();
m_sExpectedDisplayPropertyId =
m_pSceneController->getCurrentPropertyId();
m_nExpectedDisplayFrameIndex =
m_pSceneController->getCurrentFrameIndex();
if(m_nExpectedBindingRevision == 0 ||
m_sExpectedSnapshotId.isEmpty() ||
m_sExpectedDisplayPropertyId.isEmpty() ||
m_nExpectedDisplayFrameIndex < 0 ||
!m_pSceneController->getFilterSettings(m_oBaselineSettings)) {
return false;
}
const bool bSignalsBlocked = m_pPropertyCombo->blockSignals(true);
const QStringList listPropertyIds =
m_pSceneController->getAvailablePropertyIds();
for(int nIndex = 0; nIndex < listPropertyIds.size(); ++nIndex) {
const QString& sPropertyId = listPropertyIds[nIndex];
double dRange[2] = { 0.0, 0.0 };
if(!m_pSceneController->getPropertyRange(sPropertyId, dRange)) {
m_pPropertyCombo->blockSignals(bSignalsBlocked);
return false;
}
m_mapPropertyRanges.insert(
sPropertyId, qMakePair(dRange[0], dRange[1]));
QString sDisplayName =
nmPebiResultPropertyDisplayText::getDisplayName(sPropertyId);
if(sDisplayName.isEmpty()) {
sDisplayName = sPropertyId;
}
m_pPropertyCombo->addItem(sDisplayName, sPropertyId);
}
m_pPropertyCombo->blockSignals(bSignalsBlocked);
if(m_pPropertyCombo->count() <= 0) {
return false;
}
if(m_oBaselineSettings.m_sPropertyId.isEmpty() ||
!m_mapPropertyRanges.contains(
m_oBaselineSettings.m_sPropertyId)) {
m_oBaselineSettings.m_sPropertyId =
m_sExpectedDisplayPropertyId;
const QPair<double, double> oRange =
m_mapPropertyRanges.value(
m_oBaselineSettings.m_sPropertyId);
m_oBaselineSettings.m_bMinimumEnabled = true;
m_oBaselineSettings.m_dMinimum = oRange.first;
m_oBaselineSettings.m_bMaximumEnabled = true;
m_oBaselineSettings.m_dMaximum = oRange.second;
}
return populateSettings(m_oBaselineSettings);
}
bool nmWxPebiResultFilterSettingsDlg::initializeUnitEditor(
const QString& sPropertyId)
{
nmPebiResultPropertyDescriptor oDescriptor;
if(!nmPebiResultPropertyCatalog::findDescriptor(
sPropertyId, oDescriptor)) {
return false;
}
const bool bSignalsBlocked = m_pUnitCombo->blockSignals(true);
m_pUnitCombo->clear();
m_pUnitGroup = nullptr;
m_sBaseUnit = oDescriptor.m_sBaseUnit;
m_sDisplayUnit = oDescriptor.m_sDefaultDisplayUnit.isEmpty()
? m_sBaseUnit : oDescriptor.m_sDefaultDisplayUnit;
if(m_sBaseUnit.isEmpty()) {
m_sDisplayUnit.clear();
m_pUnitCombo->setEnabled(false);
m_pUnitCombo->hide();
m_pUnitCombo->blockSignals(bSignalsBlocked);
return true;
}
m_pUnitGroup = iUnitHelper::getUnitGroupByUnit(m_sBaseUnit);
QStringList listUnits;
if(m_pUnitGroup != nullptr &&
m_pUnitGroup->indexOf(m_sBaseUnit) >= 0) {
listUnits = m_pUnitGroup->getAllUnitNames();
}
const bool bHasUnitGroup = !listUnits.isEmpty() &&
listUnits.contains(m_sBaseUnit);
if(!bHasUnitGroup) {
m_pUnitGroup = nullptr;
listUnits.clear();
listUnits.append(m_sBaseUnit);
m_sDisplayUnit = m_sBaseUnit;
} else if(!listUnits.contains(m_sDisplayUnit)) {
m_sDisplayUnit = m_sBaseUnit;
}
m_pUnitCombo->addItems(listUnits);
m_pUnitCombo->setCurrentIndex(
m_pUnitCombo->findText(m_sDisplayUnit));
m_pUnitCombo->setEnabled(bHasUnitGroup);
m_pUnitCombo->show();
m_pUnitCombo->blockSignals(bSignalsBlocked);
return true;
}
bool nmWxPebiResultFilterSettingsDlg::populateSettings(
const nmPebiResultFilterSettings& oSettings)
{
const bool bPropertySignalsBlocked =
m_pPropertyCombo->blockSignals(true);
const int nPropertyIndex = m_pPropertyCombo->findData(
oSettings.m_sPropertyId);
if(nPropertyIndex < 0 ||
!initializeUnitEditor(oSettings.m_sPropertyId)) {
m_pPropertyCombo->blockSignals(bPropertySignalsBlocked);
return false;
}
m_pPropertyCombo->setCurrentIndex(nPropertyIndex);
m_pPropertyCombo->blockSignals(bPropertySignalsBlocked);
double dDisplayMinimum = 0.0;
double dDisplayMaximum = 0.0;
if(!convertUnitValue(
oSettings.m_dMinimum, m_sBaseUnit,
m_sDisplayUnit, dDisplayMinimum) ||
!convertUnitValue(
oSettings.m_dMaximum, m_sBaseUnit,
m_sDisplayUnit, dDisplayMaximum)) {
return false;
}
m_pEnableCheck->setChecked(oSettings.m_bEnabled);
m_pMinimumCheck->setChecked(oSettings.m_bMinimumEnabled);
m_pMaximumCheck->setChecked(oSettings.m_bMaximumEnabled);
m_pMinimumEdit->setText(formatValue(dDisplayMinimum));
m_pMaximumEdit->setText(formatValue(dDisplayMaximum));
refreshEditorEnabledState();
return true;
}
void nmWxPebiResultFilterSettingsDlg::onApplyClicked()
{
applyEditor();
}
void nmWxPebiResultFilterSettingsDlg::onOkClicked()
{
if(applyEditor()) {
accept();
}
}
void nmWxPebiResultFilterSettingsDlg::onPropertyChanged(int nIndex)
{
if(nIndex >= 0 &&
!setPropertyRange(
m_pPropertyCombo->itemData(nIndex).toString())) {
QMessageBox::warning(
this, tr("Filtering settings"),
tr("Unable to convert the filter limits "
"to the selected unit."));
}
}
void nmWxPebiResultFilterSettingsDlg::onDisplayUnitChanged(int nIndex)
{
if(nIndex < 0) {
return;
}
const QString sNewUnit = m_pUnitCombo->itemText(nIndex);
if(sNewUnit == m_sDisplayUnit) {
return;
}
double dOldDisplayMinimum = 0.0;
double dOldDisplayMaximum = 0.0;
double dBaseMinimum = 0.0;
double dBaseMaximum = 0.0;
double dNewDisplayMinimum = 0.0;
double dNewDisplayMaximum = 0.0;
const bool bConverted =
parseFiniteValue(
m_pMinimumEdit->text(), dOldDisplayMinimum) &&
parseFiniteValue(
m_pMaximumEdit->text(), dOldDisplayMaximum) &&
convertUnitValue(
dOldDisplayMinimum, m_sDisplayUnit,
m_sBaseUnit, dBaseMinimum) &&
convertUnitValue(
dOldDisplayMaximum, m_sDisplayUnit,
m_sBaseUnit, dBaseMaximum) &&
convertUnitValue(
dBaseMinimum, m_sBaseUnit,
sNewUnit, dNewDisplayMinimum) &&
convertUnitValue(
dBaseMaximum, m_sBaseUnit,
sNewUnit, dNewDisplayMaximum);
if(!bConverted) {
const bool bSignalsBlocked = m_pUnitCombo->blockSignals(true);
m_pUnitCombo->setCurrentIndex(
m_pUnitCombo->findText(m_sDisplayUnit));
m_pUnitCombo->blockSignals(bSignalsBlocked);
QMessageBox::warning(
this, tr("Filtering settings"),
tr("Unable to convert the filter limits "
"to the selected unit."));
return;
}
m_sDisplayUnit = sNewUnit;
m_pMinimumEdit->setText(formatValue(dNewDisplayMinimum));
m_pMaximumEdit->setText(formatValue(dNewDisplayMaximum));
}
void nmWxPebiResultFilterSettingsDlg::refreshEditorEnabledState()
{
const bool bEnabled = m_pEnableCheck->isChecked();
m_pPropertyCombo->setEnabled(bEnabled);
m_pMinimumCheck->setEnabled(bEnabled);
m_pMaximumCheck->setEnabled(bEnabled);
m_pMinimumEdit->setEnabled(
bEnabled && m_pMinimumCheck->isChecked());
m_pMaximumEdit->setEnabled(
bEnabled && m_pMaximumCheck->isChecked());
m_pUnitCombo->setEnabled(
bEnabled && m_pUnitGroup != nullptr);
}
bool nmWxPebiResultFilterSettingsDlg::collectSettings(
nmPebiResultFilterSettings& oSettings,
QString& sError) const
{
sError.clear();
const int nPropertyIndex = m_pPropertyCombo->currentIndex();
if(nPropertyIndex < 0) {
sError = tr("A filter property must be selected.");
return false;
}
oSettings.m_bEnabled = m_pEnableCheck->isChecked();
oSettings.m_sPropertyId =
m_pPropertyCombo->itemData(nPropertyIndex).toString();
oSettings.m_bMinimumEnabled = m_pMinimumCheck->isChecked();
oSettings.m_bMaximumEnabled = m_pMaximumCheck->isChecked();
// 复选框只控制边界是否参与筛选;未启用边界的编辑值仍需保留,
// 避免重新打开对话框时退回设置对象的默认 0。
double dDisplayMinimum = 0.0;
double dDisplayMaximum = 0.0;
if(!parseFiniteValue(
m_pMinimumEdit->text(), dDisplayMinimum) ||
!parseFiniteValue(
m_pMaximumEdit->text(), dDisplayMaximum)) {
sError = tr("Filter limits must be finite numbers.");
return false;
}
if(!convertUnitValue(
dDisplayMinimum, m_sDisplayUnit,
m_sBaseUnit, oSettings.m_dMinimum) ||
!convertUnitValue(
dDisplayMaximum, m_sDisplayUnit,
m_sBaseUnit, oSettings.m_dMaximum)) {
sError = tr(
"Unable to convert the filter limits "
"to the selected unit.");
return false;
}
if(oSettings.m_bMinimumEnabled &&
oSettings.m_bMaximumEnabled &&
oSettings.m_dMinimum > oSettings.m_dMaximum) {
sError = tr("The minimum filter limit cannot exceed the maximum.");
return false;
}
return true;
}
bool nmWxPebiResultFilterSettingsDlg::applyEditor()
{
nmPebiResultPlaybackController* pPlaybackController =
m_pControlBar == nullptr ? nullptr :
m_pControlBar->getPlaybackController();
if(!m_bInitialized || m_pSceneController == nullptr ||
m_pControlBar == nullptr || pPlaybackController == nullptr ||
pPlaybackController->isPlaying() ||
m_pControlBar->isExportInProgress()) {
const QString sError = tr(
"Filtering is unavailable during playback or export.");
QMessageBox::warning(this, tr("Filtering settings"), sError);
return false;
}
nmPebiResultFilterSettings oSettings;
QString sError;
if(!collectSettings(oSettings, sError) ||
!m_pSceneController->applyFilterSettings(
m_nExpectedBindingRevision,
m_sExpectedSnapshotId,
m_sExpectedDisplayPropertyId,
m_nExpectedDisplayFrameIndex,
oSettings, &sError)) {
if(sError.isEmpty()) {
sError = tr("Unable to apply the filter settings.");
}
QMessageBox::warning(this, tr("Filtering settings"), sError);
return false;
}
m_oBaselineSettings = oSettings;
emit filterSettingsApplied();
return true;
}
bool nmWxPebiResultFilterSettingsDlg::setPropertyRange(
const QString& sPropertyId)
{
if(!m_mapPropertyRanges.contains(sPropertyId) ||
!initializeUnitEditor(sPropertyId)) {
return false;
}
const QPair<double, double> oRange =
m_mapPropertyRanges.value(sPropertyId);
double dDisplayMinimum = 0.0;
double dDisplayMaximum = 0.0;
if(!convertUnitValue(
oRange.first, m_sBaseUnit,
m_sDisplayUnit, dDisplayMinimum) ||
!convertUnitValue(
oRange.second, m_sBaseUnit,
m_sDisplayUnit, dDisplayMaximum)) {
return false;
}
m_pMinimumCheck->setChecked(true);
m_pMaximumCheck->setChecked(true);
m_pMinimumEdit->setText(formatValue(dDisplayMinimum));
m_pMaximumEdit->setText(formatValue(dDisplayMaximum));
refreshEditorEnabledState();
return true;
}
QString nmWxPebiResultFilterSettingsDlg::formatValue(double dValue) const
{
return QLocale::c().toString(dValue, 'g', 12);
}
bool nmWxPebiResultFilterSettingsDlg::parseFiniteValue(
const QString& sText,
double& dValue) const
{
bool bOk = false;
const double dCandidate = QLocale::c().toDouble(
sText.trimmed(), &bOk);
if(!bOk || !isFiniteFilterEditorValue(dCandidate)) {
return false;
}
dValue = dCandidate;
return true;
}
bool nmWxPebiResultFilterSettingsDlg::convertUnitValue(
double dSourceValue,
const QString& sSourceUnit,
const QString& sDestinationUnit,
double& dDestinationValue) const
{
if(!isFiniteFilterEditorValue(dSourceValue)) {
return false;
}
if(sSourceUnit == sDestinationUnit) {
dDestinationValue = dSourceValue;
return true;
}
if(sSourceUnit.isEmpty() || sDestinationUnit.isEmpty() ||
m_pUnitGroup == nullptr ||
m_pUnitGroup->indexOf(sSourceUnit) < 0 ||
m_pUnitGroup->indexOf(sDestinationUnit) < 0) {
return false;
}
int nDigit = 12;
double dCandidate = 0.0;
if(!m_pUnitGroup->convert(
sSourceUnit, dSourceValue,
sDestinationUnit, dCandidate, nDigit) ||
!isFiniteFilterEditorValue(dCandidate)) {
return false;
}
dDestinationValue = dCandidate;
return true;
}
nmWxPebiResultViewWidget::nmWxPebiResultViewWidget(
nmDataAnalyzeManager* pDataManager,
QWidget* pParent)
: QWidget(pParent),
m_pRenderContainer(nullptr),
m_pSceneController(nullptr),
m_pControlBar(nullptr),
m_pToolBar(nullptr),
m_pStatusLabel(nullptr),
m_pScalarBarAction(nullptr),
m_pScaleGridAction(nullptr),
m_pWellNamesAction(nullptr),
m_pFilterAction(nullptr),
m_bObservedSnapshotCurrent(false),
m_bObservedStateValid(false),
m_bSynchronizing(false),
m_bSyncPending(false)
{
createUi();
setDataManager(pDataManager);
}
nmWxPebiResultViewWidget::~nmWxPebiResultViewWidget()
{
disconnectDataManager();
if(m_pControlBar != nullptr) {
m_pControlBar->stopPlayback();
delete m_pControlBar;
m_pControlBar = nullptr;
}
if(m_pSceneController != nullptr) {
m_pSceneController->clear();
delete m_pSceneController;
m_pSceneController = nullptr;
}
// 渲染容器、工具栏、状态栏和 QAction 最后由 QWidget 对象树统一释放。
}
void nmWxPebiResultViewWidget::setDataManager(
nmDataAnalyzeManager* pDataManager)
{
Q_ASSERT(isResultViewGuiThread());
Q_ASSERT(pDataManager == nullptr ||
pDataManager->thread() == QThread::currentThread());
if(!isResultViewGuiThread() ||
(pDataManager != nullptr &&
pDataManager->thread() != QThread::currentThread())) {
// 窗口会同步读取不可变快照引用,不能跨线程直接访问 Manager。
return;
}
if(m_pDataManager.data() == pDataManager) {
// 生产入口可能重复安装同一 Manager;这里只读最新状态,不能清空相机。
synchronizeFromDataManager();
return;
}
disconnectDataManager();
clearSceneAndControls(tr("No result data."));
m_pDataManager = pDataManager;
if(!m_pDataManager.isNull()) {
connect(m_pDataManager.data(), SIGNAL(sigPebiResultStateChanged()),
this, SLOT(onPebiResultStateChanged()));
connect(m_pDataManager.data(), SIGNAL(destroyed(QObject*)),
this, SLOT(onDataManagerDestroyed(QObject*)));
}
synchronizeFromDataManager();
}
nmDataAnalyzeManager* nmWxPebiResultViewWidget::getDataManager() const
{
return m_pDataManager.data();
}
void nmWxPebiResultViewWidget::synchronizeFromDataManager()
{
Q_ASSERT(isResultViewGuiThread());
Q_ASSERT(m_pDataManager.isNull() ||
m_pDataManager->thread() == QThread::currentThread());
if(!isResultViewGuiThread() ||
(!m_pDataManager.isNull() &&
m_pDataManager->thread() != QThread::currentThread())) {
return;
}
if(m_bSynchronizing) {
// 同步期间只记录一次待处理请求,当前事务结束后重新读取 Manager 最新值。
m_bSyncPending = true;
return;
}
m_bSynchronizing = true;
do {
m_bSyncPending = false;
synchronizeOnce();
} while(m_bSyncPending);
m_bSynchronizing = false;
}
void nmWxPebiResultViewWidget::onPebiResultStateChanged()
{
synchronizeFromDataManager();
}
void nmWxPebiResultViewWidget::onDataManagerDestroyed(QObject* pObject)
{
Q_UNUSED(pObject);
// destroyed() 到达时 QPointer 可能已经清空,槽内绝不再读取 Manager。
m_pDataManager = nullptr;
if(m_bSynchronizing) {
// 极端嵌套事件下不得在快照提交栈内递归清场,退出当前事务后再读空状态。
m_bSyncPending = true;
return;
}
clearSceneAndControls(tr("No result data."));
// 记录稳定空状态,后续重复同步空 Manager 时不再清场或切换状态页。
rememberObservedState(
QSharedPointer<const nmPebiResultSnapshot>(),
QString(), false);
}
void nmWxPebiResultViewWidget::appendContextMenuActions(QMenu* pMenu)
{
if(pMenu == nullptr) {
return;
}
pMenu->addAction(m_pFilterAction);
pMenu->addSeparator();
pMenu->addAction(m_pScalarBarAction);
pMenu->addAction(m_pScaleGridAction);
pMenu->addAction(m_pWellNamesAction);
if(m_pControlBar != nullptr &&
m_pControlBar->getExportAnimationAction() != nullptr) {
pMenu->addSeparator();
pMenu->addAction(m_pControlBar->getExportAnimationAction());
}
}
void nmWxPebiResultViewWidget::onControlOperationFailed(
const QString& sError)
{
// 绑定失败优先显示;输入修改不再提示,也不屏蔽后续真实操作错误。
if(!m_sBindingError.isEmpty()) {
return;
}
m_sOperationError = sError;
refreshStatusBar();
}
void nmWxPebiResultViewWidget::onControlOperationSucceeded()
{
if(m_sOperationError.isEmpty()) {
return;
}
// 这里只清除普通操作错误;刷新函数仍优先显示绑定失败。
m_sOperationError.clear();
refreshStatusBar();
}
void nmWxPebiResultViewWidget::onViewportSizeChanged(
int nWidth,
int nHeight)
{
if(m_pSceneController != nullptr) {
// SceneController 缓存尺寸,即使当前尚未创建结果色标也不会丢失。
m_pSceneController->setViewportSize(nWidth, nHeight);
}
}
void nmWxPebiResultViewWidget::onShowFilterSettings()
{
nmPebiResultPlaybackController* pPlaybackController =
m_pControlBar == nullptr ? nullptr :
m_pControlBar->getPlaybackController();
if(m_pSceneController == nullptr || m_pControlBar == nullptr ||
pPlaybackController == nullptr ||
!m_pSceneController->hasSnapshot() ||
pPlaybackController->isPlaying() ||
m_pControlBar->isExportInProgress()) {
return;
}
nmWxPebiResultFilterSettingsDlg oDialog(
m_pSceneController, m_pControlBar, this);
connect(&oDialog, SIGNAL(filterSettingsApplied()),
this, SLOT(onControlOperationSucceeded()));
oDialog.exec();
synchronizeBusinessActions();
}
void nmWxPebiResultViewWidget::onExportAnimationRequested()
{
nmPebiResultPlaybackController* pPlaybackController =
m_pControlBar == nullptr ? nullptr :
m_pControlBar->getPlaybackController();
QString sBackendError;
if(m_pSceneController == nullptr || m_pRenderContainer == nullptr ||
pPlaybackController == nullptr ||
pPlaybackController->isPlaying() ||
!m_pSceneController->hasSnapshot() ||
m_pDisplayedSnapshot.isNull() ||
!nmFFmpegVideoWriter::isBackendAvailable(&sBackendError)) {
if(!sBackendError.isEmpty()) {
QMessageBox::warning(this, tr("Export Animation"), sBackendError);
}
return;
}
AnimationExportGuard oExportGuard(m_pControlBar);
if(!oExportGuard.isAcquired()) {
QMessageBox::information(
this, tr("Export Animation"),
tr("Another result animation export is already in progress."));
return;
}
const QSharedPointer<const nmPebiResultSnapshot> pFrozenSnapshot =
m_pDisplayedSnapshot;
const quint64 nFrozenBindingRevision =
m_pSceneController->getSnapshotBindingRevision();
const QString sFrozenSnapshotId =
m_pSceneController->getCurrentSnapshotId();
const QString sFrozenPropertyId =
m_pSceneController->getCurrentPropertyId();
const nmVTKMeshLayer::DisplayMode eFrozenMeshDisplayMode =
m_pSceneController->getMeshDisplayMode();
nmPebiResultDisplaySettings oFrozenDisplaySettings;
nmPebiResultFilterSettings oFrozenFilterSettings;
if(!m_pSceneController->getCurrentDisplaySettings(
oFrozenDisplaySettings) ||
!m_pSceneController->getFilterSettings(
oFrozenFilterSettings)) {
return;
}
const int nFrozenFilterFrameIndex =
m_pSceneController->getFilterFrameIndex();
const int nFrameCount = pFrozenSnapshot->getPropertyFrameCount(
sFrozenPropertyId);
if(nFrozenBindingRevision == 0 || sFrozenSnapshotId.isEmpty() ||
sFrozenPropertyId.isEmpty() || nFrameCount <= 1 ||
!nmVTKMeshLayer::isValidDisplayMode(eFrozenMeshDisplayMode) ||
(oFrozenFilterSettings.m_bEnabled &&
nFrozenFilterFrameIndex < 0) ||
!m_pSceneController->isPropertyTimeDependent(sFrozenPropertyId)) {
return;
}
QVector<double> vecFrameTimes;
vecFrameTimes.reserve(nFrameCount);
for(int nFrameIndex = 0; nFrameIndex < nFrameCount; ++nFrameIndex) {
double dTimeHours = 0.0;
if(!pFrozenSnapshot->getPropertyTimeAt(
sFrozenPropertyId, nFrameIndex, dTimeHours)) {
QMessageBox::warning(
this, tr("Export Animation"),
tr("Unable to read the result animation timeline."));
return;
}
vecFrameTimes.append(dTimeHours);
}
nmWxPebiResultAnimationExportDlg oSettingsDialog(
vecFrameTimes, m_pRenderContainer->getViewportSize(), this);
if(oSettingsDialog.exec() != QDialog::Accepted) {
return;
}
// 参数窗口内的文件浏览也会形成嵌套事件循环,开始前重新核对完整显示身份。
if(m_pDisplayedSnapshot.data() != pFrozenSnapshot.data() ||
m_pSceneController->getSnapshotBindingRevision() !=
nFrozenBindingRevision ||
m_pSceneController->getCurrentSnapshotId() != sFrozenSnapshotId ||
m_pSceneController->getCurrentPropertyId() != sFrozenPropertyId ||
m_pSceneController->getMeshDisplayMode() !=
eFrozenMeshDisplayMode) {
QMessageBox::warning(
this, tr("Export Animation"),
tr("The displayed result changed before export started."));
return;
}
nmPebiResultDisplaySettings oCurrentDisplaySettings;
nmPebiResultFilterSettings oCurrentFilterSettings;
if(!m_pSceneController->getCurrentDisplaySettings(
oCurrentDisplaySettings) ||
oCurrentDisplaySettings != oFrozenDisplaySettings ||
!m_pSceneController->getFilterSettings(oCurrentFilterSettings) ||
oCurrentFilterSettings != oFrozenFilterSettings ||
m_pSceneController->getFilterFrameIndex() !=
nFrozenFilterFrameIndex) {
QMessageBox::warning(
this, tr("Export Animation"),
tr("The displayed result changed before export started."));
return;
}
vtkRenderer* pRenderer = m_pRenderContainer->getRenderer();
if(pRenderer == nullptr || pRenderer->GetActiveCamera() == nullptr) {
QMessageBox::warning(
this, tr("Export Animation"),
tr("Unable to freeze the current result display."));
return;
}
nmPebiResultAnimationExporter::Request oRequest;
oRequest.m_pSnapshot = pFrozenSnapshot;
oRequest.m_sPropertyId = sFrozenPropertyId;
oRequest.m_oDisplaySettings = oFrozenDisplaySettings;
oRequest.m_eMeshDisplayMode = eFrozenMeshDisplayMode;
oRequest.m_oFilterSettings = oFrozenFilterSettings;
oRequest.m_nFilterFrameIndex = nFrozenFilterFrameIndex;
oRequest.m_oExportSettings = oSettingsDialog.getSettings();
oRequest.m_sTargetFilePath = oSettingsDialog.getTargetFilePath();
oRequest.m_bScalarBarVisible =
m_pSceneController->isScalarBarVisible();
oRequest.m_bScaleGridVisible =
m_pSceneController->isScaleGridVisible();
oRequest.m_bWellNamesVisible =
m_pSceneController->areWellNamesVisible();
pRenderer->GetBackground(oRequest.m_dBackground);
pRenderer->GetBackground2(oRequest.m_dBackground2);
oRequest.m_bGradientBackground =
pRenderer->GetGradientBackground() != 0;
oRequest.m_pCamera = vtkSmartPointer<vtkCamera>::New();
oRequest.m_pCamera->DeepCopy(pRenderer->GetActiveCamera());
QProgressDialog oProgressDialog(
tr("Exporting result animation..."), tr("Cancel"),
0, oRequest.m_oExportSettings.getOutputFrameCount(), this);
oProgressDialog.setWindowTitle(tr("Export Animation"));
oProgressDialog.setWindowModality(Qt::ApplicationModal);
oProgressDialog.setMinimumDuration(0);
oProgressDialog.setAutoClose(false);
oProgressDialog.setAutoReset(false);
nmPebiResultAnimationExporter oExporter;
connect(&oExporter, SIGNAL(progressChanged(int,int)),
&oProgressDialog, SLOT(setValue(int)));
connect(&oProgressDialog, SIGNAL(canceled()),
&oExporter, SLOT(cancel()));
oProgressDialog.show();
QString sExportError;
const nmPebiResultAnimationExporter::ExportResult eResult =
oExporter.exportAnimation(oRequest, &sExportError);
oProgressDialog.close();
oExportGuard.release();
if(eResult == nmPebiResultAnimationExporter::Export_Succeeded) {
onControlOperationSucceeded();
QMessageBox::information(
this, tr("Export Animation"),
tr("The result animation was saved to:\n%1")
.arg(QDir::toNativeSeparators(
oRequest.m_sTargetFilePath)));
} else if(eResult == nmPebiResultAnimationExporter::Export_Failed) {
QMessageBox::warning(
this, tr("Export Animation"),
sExportError.isEmpty()
? tr("Unable to export the result animation.")
: sExportError);
}
}
void nmWxPebiResultViewWidget::onScalarBarToggled(bool bVisible)
{
if(m_pSceneController != nullptr && m_pSceneController->hasSnapshot()) {
m_pSceneController->setScalarBarVisible(bVisible);
}
}
void nmWxPebiResultViewWidget::onScaleGridToggled(bool bVisible)
{
if(m_pSceneController != nullptr && m_pSceneController->hasSnapshot()) {
m_pSceneController->setScaleGridVisible(bVisible);
}
}
void nmWxPebiResultViewWidget::onWellNamesToggled(bool bVisible)
{
if(m_pSceneController != nullptr && m_pSceneController->hasSnapshot()) {
m_pSceneController->setWellNamesVisible(bVisible);
}
}
void nmWxPebiResultViewWidget::createUi()
{
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(0, 0, 0, 0);
pMainLayout->setSpacing(0);
QWidget* pRenderArea = new QWidget(this);
QHBoxLayout* pRenderLayout = new QHBoxLayout(pRenderArea);
pRenderLayout->setContentsMargins(0, 0, 0, 0);
pRenderLayout->setSpacing(0);
// 通用容器是本窗口唯一创建 QVTKWidget、Renderer 和 RenderWindow 的对象。
m_pRenderContainer = new nmWxVTKRenderContainerWidget(pRenderArea);
m_pRenderContainer->setSizePolicy(
QSizePolicy::Expanding, QSizePolicy::Expanding);
m_pRenderContainer->setViewCommandCapabilities(
nmVTKViewCommandController::ViewCommand_ZoomIn |
nmVTKViewCommandController::ViewCommand_ZoomOut |
nmVTKViewCommandController::ViewCommand_Fit |
nmVTKViewCommandController::ViewCommand_Top |
nmVTKViewCommandController::ViewCommand_Front |
nmVTKViewCommandController::ViewCommand_SetRotationCenter |
nmVTKViewCommandController::
ViewCommand_ShowRotationCenterMarker |
nmVTKViewCommandController::ViewCommand_SaveImage |
nmVTKViewCommandController::ViewCommand_CopyImage |
nmVTKViewCommandController::ViewCommand_Print |
nmVTKViewCommandController::ViewCommand_PrintPreview);
m_pSceneController = new nmPebiResultSceneController(m_pRenderContainer);
connect(m_pRenderContainer, SIGNAL(viewportSizeChanged(int,int)),
this, SLOT(onViewportSizeChanged(int,int)));
const QSize oInitialViewportSize =
m_pRenderContainer->getViewportSize();
onViewportSizeChanged(
oInitialViewportSize.width(), oInitialViewportSize.height());
m_pToolBar = new QToolBar(pRenderArea);
m_pToolBar->setOrientation(Qt::Vertical);
m_pToolBar->setMovable(false);
m_pToolBar->setFloatable(false);
m_pToolBar->setIconSize(QSize(32, 32));
m_pToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_pToolBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
m_pScalarBarAction = new QAction(
QIcon(resultViewIconPath("NmColorScale.png")),
tr("Color Scale"), this);
m_pScaleGridAction = new QAction(
QIcon(resultViewIconPath("NmScaleGrid.png")),
tr("Scale Grid"), this);
m_pWellNamesAction = new QAction(
QIcon(resultViewIconPath("NmShowWellNames.png")),
tr("Well Names"), this);
m_pFilterAction = new QAction(
QIcon(resultViewIconPath("NmFilter.png")),
tr("Data Filtering..."), this);
m_pFilterAction->setToolTip(m_pFilterAction->text());
QAction* const pBusinessActions[] = {
m_pScalarBarAction, m_pScaleGridAction, m_pWellNamesAction
};
for(int nIndex = 0; nIndex < 3; ++nIndex) {
pBusinessActions[nIndex]->setCheckable(true);
pBusinessActions[nIndex]->setToolTip(
pBusinessActions[nIndex]->text());
}
nmVTKViewCommandController* pCommandController =
m_pRenderContainer->getViewCommandController();
if(pCommandController != nullptr) {
QAction* pZoomOutAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_ZoomOut);
QAction* pFitAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Fit);
QAction* pZoomInAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_ZoomIn);
QAction* pTopAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Top);
QAction* pFrontAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Front);
QAction* pPickCenterAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_SetRotationCenter);
QAction* pCopyAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_CopyImage);
if(pZoomOutAction != nullptr) m_pToolBar->addAction(pZoomOutAction);
if(pFitAction != nullptr) m_pToolBar->addAction(pFitAction);
if(pZoomInAction != nullptr) m_pToolBar->addAction(pZoomInAction);
m_pToolBar->addSeparator();
if(pTopAction != nullptr) m_pToolBar->addAction(pTopAction);
if(pFrontAction != nullptr) m_pToolBar->addAction(pFrontAction);
if(pPickCenterAction != nullptr) m_pToolBar->addAction(pPickCenterAction);
m_pToolBar->addSeparator();
m_pToolBar->addAction(m_pFilterAction);
for(int nIndex = 0; nIndex < 3; ++nIndex) {
m_pToolBar->addAction(pBusinessActions[nIndex]);
}
m_pToolBar->addSeparator();
if(pCopyAction != nullptr) m_pToolBar->addAction(pCopyAction);
}
connect(m_pScalarBarAction, SIGNAL(toggled(bool)),
this, SLOT(onScalarBarToggled(bool)));
connect(m_pScaleGridAction, SIGNAL(toggled(bool)),
this, SLOT(onScaleGridToggled(bool)));
connect(m_pWellNamesAction, SIGNAL(toggled(bool)),
this, SLOT(onWellNamesToggled(bool)));
connect(m_pFilterAction, SIGNAL(triggered()),
this, SLOT(onShowFilterSettings()));
connect(m_pRenderContainer, SIGNAL(contextMenuAboutToShow(QMenu*)),
this, SLOT(appendContextMenuActions(QMenu*)));
pRenderLayout->addWidget(m_pRenderContainer, 1);
pRenderLayout->addWidget(m_pToolBar);
pMainLayout->addWidget(pRenderArea, 1);
m_pStatusLabel = new QLabel(this);
m_pStatusLabel->setWordWrap(true);
m_pStatusLabel->setContentsMargins(8, 4, 8, 4);
m_pStatusLabel->hide();
pMainLayout->addWidget(m_pStatusLabel);
m_pControlBar = new nmWxPebiResultControlBar(
m_pSceneController, this);
connect(m_pControlBar, SIGNAL(operationFailed(QString)),
this, SLOT(onControlOperationFailed(QString)));
connect(m_pControlBar, SIGNAL(operationSucceeded()),
this, SLOT(onControlOperationSucceeded()));
connect(m_pControlBar, SIGNAL(exportAnimationRequested()),
this, SLOT(onExportAnimationRequested()));
connect(m_pControlBar, SIGNAL(exportInProgressChanged(bool)),
this, SLOT(synchronizeBusinessActions()));
if(m_pControlBar->getPlaybackController() != nullptr) {
connect(m_pControlBar->getPlaybackController(), SIGNAL(stateChanged()),
this, SLOT(synchronizeBusinessActions()));
}
pMainLayout->addWidget(m_pControlBar);
synchronizeBusinessActions();
m_pRenderContainer->showEmptyState(tr("No result data."));
}
void nmWxPebiResultViewWidget::synchronizeOnce()
{
if(m_pDataManager.isNull()) {
if(m_bObservedStateValid && m_pObservedSnapshot.isNull()) {
return;
}
clearSceneAndControls(tr("No result data."));
rememberObservedState(
QSharedPointer<const nmPebiResultSnapshot>(),
QString(), false);
return;
}
const QSharedPointer<const nmPebiResultSnapshot> pSnapshot =
m_pDataManager->getPebiResultSnapshot();
const QString sSnapshotId = pSnapshot.isNull()
? QString() : pSnapshot->getSnapshotId();
const bool bCurrent = !pSnapshot.isNull() &&
m_pDataManager->isPebiResultSnapshotCurrent();
const bool bSameIdentity = m_bObservedStateValid &&
m_pObservedSnapshot.data() == pSnapshot.data() &&
m_sObservedSnapshotId == sSnapshotId;
const bool bSameState = bSameIdentity &&
m_bObservedSnapshotCurrent == bCurrent;
if(bSameState) {
return;
}
const bool bBecameStale = bSameIdentity &&
m_bObservedSnapshotCurrent && !bCurrent;
m_sOperationError.clear();
if(pSnapshot.isNull()) {
clearSceneAndControls(tr("No result data."));
rememberObservedState(pSnapshot, sSnapshotId, false);
return;
}
if(!bSameIdentity) {
// 候选提交前停止本窗口 Timer;失败时旧 Scene 和最后压力帧记忆仍保留。
m_pControlBar->stopPlayback();
QString sError;
const bool bBound = m_pSceneController->setSnapshot(
pSnapshot, &sError);
rememberObservedState(pSnapshot, sSnapshotId, bCurrent);
if(bBound) {
m_pDisplayedSnapshot = pSnapshot;
m_sDisplayedSnapshotId = sSnapshotId;
m_sBindingError.clear();
// 新成功绑定序号会让 Playback 和 ControlBar 同时重置各自缓存。
m_pControlBar->synchronizeFromScene();
synchronizeBusinessActions();
refreshStatusBar();
return;
}
m_sBindingError = sError.isEmpty()
? tr("Unable to display the latest result.")
: tr("Unable to display the latest result: %1").arg(sError);
if(!m_pSceneController->hasSnapshot()) {
m_pDisplayedSnapshot.clear();
m_sDisplayedSnapshotId.clear();
}
m_pControlBar->synchronizeFromScene();
synchronizeBusinessActions();
if(m_pSceneController->hasSnapshot()) {
// 旧画面保持 Ready;这里只显示红色非阻塞提示,不能追加 Render。
refreshStatusBar();
} else {
m_pStatusLabel->hide();
m_pRenderContainer->showErrorState(m_sBindingError);
}
return;
}
rememberObservedState(pSnapshot, sSnapshotId, bCurrent);
if(bBecameStale) {
// 只在“当前 -> 过期”的边沿暂停一次;用户之后可以手动重新播放旧结果。
m_pControlBar->stopPlayback();
}
refreshStatusBar();
}
void nmWxPebiResultViewWidget::clearSceneAndControls(
const QString& sEmptyMessage)
{
if(m_pControlBar != nullptr) {
m_pControlBar->stopPlayback();
}
if(m_pSceneController != nullptr) {
m_pSceneController->clear();
}
m_pObservedSnapshot.clear();
m_sObservedSnapshotId.clear();
m_bObservedSnapshotCurrent = false;
m_bObservedStateValid = false;
m_pDisplayedSnapshot.clear();
m_sDisplayedSnapshotId.clear();
m_sBindingError.clear();
m_sOperationError.clear();
if(m_pControlBar != nullptr) {
m_pControlBar->synchronizeFromScene();
}
synchronizeBusinessActions();
if(m_pStatusLabel != nullptr) {
m_pStatusLabel->hide();
}
if(m_pRenderContainer != nullptr) {
m_pRenderContainer->showEmptyState(sEmptyMessage);
}
}
void nmWxPebiResultViewWidget::rememberObservedState(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot,
const QString& sSnapshotId,
bool bCurrent)
{
m_pObservedSnapshot = pSnapshot;
m_sObservedSnapshotId = sSnapshotId;
m_bObservedSnapshotCurrent = bCurrent;
m_bObservedStateValid = true;
}
void nmWxPebiResultViewWidget::synchronizeBusinessActions()
{
if(m_pSceneController == nullptr) {
return;
}
setActionCheckedWithoutSignal(
m_pScalarBarAction, m_pSceneController->isScalarBarVisible());
setActionCheckedWithoutSignal(
m_pScaleGridAction, m_pSceneController->isScaleGridVisible());
setActionCheckedWithoutSignal(
m_pWellNamesAction, m_pSceneController->areWellNamesVisible());
const bool bEnabled = m_pSceneController->hasSnapshot();
m_pScalarBarAction->setEnabled(bEnabled);
m_pScaleGridAction->setEnabled(bEnabled);
m_pWellNamesAction->setEnabled(bEnabled);
nmPebiResultPlaybackController* pPlaybackController =
m_pControlBar == nullptr ? nullptr :
m_pControlBar->getPlaybackController();
const bool bFilterEnabled = bEnabled &&
pPlaybackController != nullptr &&
!pPlaybackController->isPlaying() &&
!m_pControlBar->isExportInProgress();
if(m_pFilterAction != nullptr) {
m_pFilterAction->setEnabled(bFilterEnabled);
}
}
void nmWxPebiResultViewWidget::refreshStatusBar()
{
if(m_pStatusLabel == nullptr || m_pSceneController == nullptr ||
!m_pSceneController->hasSnapshot()) {
if(m_pStatusLabel != nullptr) {
m_pStatusLabel->hide();
}
return;
}
if(!m_sBindingError.isEmpty()) {
m_pStatusLabel->setStyleSheet(
"QLabel { color: #a32626; background: #fdecec; } ");
m_pStatusLabel->setText(m_sBindingError);
m_pStatusLabel->show();
return;
}
if(!m_sOperationError.isEmpty()) {
m_pStatusLabel->setStyleSheet(
"QLabel { color: #a32626; background: #fdecec; } ");
m_pStatusLabel->setText(m_sOperationError);
m_pStatusLabel->show();
return;
}
m_pStatusLabel->hide();
}
void nmWxPebiResultViewWidget::disconnectDataManager()
{
nmDataAnalyzeManager* pDataManager = m_pDataManager.data();
if(pDataManager != nullptr) {
disconnect(pDataManager, SIGNAL(sigPebiResultStateChanged()),
this, SLOT(onPebiResultStateChanged()));
disconnect(pDataManager, SIGNAL(destroyed(QObject*)),
this, SLOT(onDataManagerDestroyed(QObject*)));
}
m_pDataManager = nullptr;
}