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