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

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