diff --git a/python/core/auto_generated/mesh/qgsmeshlayer.sip.in b/python/core/auto_generated/mesh/qgsmeshlayer.sip.in index 0bc8a5ed38aa..6062f7442f33 100644 --- a/python/core/auto_generated/mesh/qgsmeshlayer.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshlayer.sip.in @@ -94,6 +94,8 @@ Constructor for LayerOptions with optional ``transformContext``. QgsCoordinateTransformContext transformContext; + bool loadDefaultStyle; + bool skipCrsValidation; }; @@ -161,6 +163,8 @@ QgsMeshLayer cannot be copied. virtual bool supportsEditing() const; + virtual QString loadDefaultStyle( bool &resultFlag /Out/ ) ${SIP_FINAL}; + QString providerType() const; %Docstring diff --git a/python/core/auto_generated/mesh/qgsmeshlayertemporalproperties.sip.in b/python/core/auto_generated/mesh/qgsmeshlayertemporalproperties.sip.in index a4b38c5120bb..9d0a8b4f79b9 100644 --- a/python/core/auto_generated/mesh/qgsmeshlayertemporalproperties.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshlayertemporalproperties.sip.in @@ -89,6 +89,22 @@ Returns the method used to match dataset from temporal capabilities Sets the method used to match dataset from temporal capabilities :param matchingMethod: the matching method +%End + + bool isValid() const; +%Docstring +Returns whether the instance is valid + +.. versionadded:: 3.22 +%End + + void setIsValid( bool isValid ); +%Docstring +Sets whether the instance is valid + +:param isValid: whether the instance is valid + +.. versionadded:: 3.22 %End }; diff --git a/python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in b/python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in index 60e020d0424f..d69c9252c797 100644 --- a/python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in @@ -747,6 +747,13 @@ Returns the active vector dataset group Sets the active vector dataset group .. versionadded:: 3.14 +%End + + bool hasSettings( int datasetGroupIndex ) const; +%Docstring +Returns whether the group with ``index`` has render settings (scalar or vector) + +.. versionadded:: 3.22 %End }; diff --git a/src/app/qgsapplayertreeviewmenuprovider.cpp b/src/app/qgsapplayertreeviewmenuprovider.cpp index d2ac0e41ffec..603bbd88bcdc 100644 --- a/src/app/qgsapplayertreeviewmenuprovider.cpp +++ b/src/app/qgsapplayertreeviewmenuprovider.cpp @@ -50,6 +50,7 @@ #include "qgsvectorlayer.h" #include "qgsvectorlayerlabeling.h" #include "qgsxmlutils.h" +#include "qgsmeshlayer.h" QgsAppLayerTreeViewMenuProvider::QgsAppLayerTreeViewMenuProvider( QgsLayerTreeView *view, QgsMapCanvas *canvas ) @@ -153,6 +154,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu() QgsRasterLayer *rlayer = qobject_cast( layer ); QgsVectorLayer *vlayer = qobject_cast( layer ); QgsPointCloudLayer *pcLayer = qobject_cast( layer ); + QgsMeshLayer *meshLayer = qobject_cast( layer ); if ( layer && layer->isSpatial() ) { @@ -363,8 +365,8 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu() menu->addAction( tr( "&Filter…" ), QgisApp::instance(), qOverload<>( &QgisApp::layerSubsetString ) ); } - // change data source is only supported for vectors and rasters, point clouds - if ( vlayer || rlayer || pcLayer ) + // change data source is only supported for vectors, rasters, point clouds, mesh + if ( vlayer || rlayer || pcLayer || meshLayer ) { QAction *a = new QAction( layer->isValid() ? tr( "C&hange Data Source…" ) : tr( "Repair Data Source…" ), menu ); diff --git a/src/core/mesh/qgsmeshdatasetgroupstore.cpp b/src/core/mesh/qgsmeshdatasetgroupstore.cpp index 810ab6286b8b..4112f2b31b88 100644 --- a/src/core/mesh/qgsmeshdatasetgroupstore.cpp +++ b/src/core/mesh/qgsmeshdatasetgroupstore.cpp @@ -343,6 +343,16 @@ void QgsMeshDatasetGroupStore::readXml( const QDomElement &storeElem, const QgsR setDatasetGroupTreeItem( new QgsMeshDatasetGroupTreeItem( rootTreeItemElem, context ) ); } +int QgsMeshDatasetGroupStore::globalDatasetGroupIndexInSource( QgsMeshDatasetSourceInterface *source, int nativeGroupIndex ) const +{ + for ( QMap::const_iterator it = mRegistery.cbegin(); it != mRegistery.cend(); ++it ) + { + if ( it.value().first == source && it.value().second == nativeGroupIndex ) + return it.key(); + } + + return -1; +} bool QgsMeshDatasetGroupStore::saveDatasetGroup( QString filePath, int groupIndex, QString driver ) { diff --git a/src/core/mesh/qgsmeshdatasetgroupstore.h b/src/core/mesh/qgsmeshdatasetgroupstore.h index 4861f53a89d0..0335765260d7 100644 --- a/src/core/mesh/qgsmeshdatasetgroupstore.h +++ b/src/core/mesh/qgsmeshdatasetgroupstore.h @@ -210,6 +210,14 @@ class QgsMeshDatasetGroupStore: public QObject //! Reads the store's information from a DOM document void readXml( const QDomElement &storeElem, const QgsReadWriteContext &context ); + /** + * Returns the global dataset group index of the dataset group with native index \a globalGroupIndex in the \a source + * Returns -1 if the group or the source is not registered + * + * Since QGIS 3.22 + */ + int globalDatasetGroupIndexInSource( QgsMeshDatasetSourceInterface *source, int nativeGroupIndex ) const; + signals: //! Emitted after dataset groups are added void datasetGroupsAdded( QList indexes ); diff --git a/src/core/mesh/qgsmeshlayer.cpp b/src/core/mesh/qgsmeshlayer.cpp index a538d21e036a..602b5dff6bb9 100644 --- a/src/core/mesh/qgsmeshlayer.cpp +++ b/src/core/mesh/qgsmeshlayer.cpp @@ -51,12 +51,15 @@ QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath, : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ), mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ), mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) ) - { mShouldValidateCrs = !options.skipCrsValidation; const QgsDataProvider::ProviderOptions providerOptions { options.transformContext }; QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags(); + if ( options.loadDefaultStyle ) + { + flags |= QgsDataProvider::FlagLoadDefaultStyle; + } if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata ) { flags |= QgsDataProvider::FlagTrustDataSource; @@ -65,7 +68,7 @@ QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath, resetDatasetGroupTreeItem(); setLegend( QgsMapLayerLegend::defaultMeshLegend( this ) ); - if ( isValid() ) + if ( isValid() && options.loadDefaultStyle ) setDefaultRendererSettings( mDatasetGroupStore->datasetGroupIndexes() ); connect( mDatasetGroupStore.get(), &QgsMeshDatasetGroupStore::datasetGroupsAdded, this, &QgsMeshLayer::onDatasetGroupsAdded ); @@ -201,6 +204,22 @@ bool QgsMeshLayer::supportsEditing() const return driverMetadata.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData; } +QString QgsMeshLayer::loadDefaultStyle( bool &resultFlag ) +{ + const QList groupsList = datasetGroupsIndexes(); + + for ( const int index : groupsList ) + assignDefaultStyleToDatasetGroup( index ); + + if ( !groupsList.isEmpty() ) + { + emit rendererChanged(); + emitStyleChanged(); + } + + return QgsMapLayer::loadDefaultStyle( resultFlag ); +} + bool QgsMeshLayer::addDatasets( const QString &path, const QDateTime &defaultReferenceTime ) { const bool isTemporalBefore = dataProvider()->temporalCapabilities()->hasTemporalCapabilities(); @@ -1138,17 +1157,8 @@ void QgsMeshLayer::setDataSourcePrivate( const QString &dataSource, const QStrin mLayerName = baseName; setProviderType( provider ); - // if we’re given a provider type, try to create and bind one to this layer - bool ok = false; if ( !mDataSource.isEmpty() && !provider.isEmpty() ) - { - ok = setDataProvider( provider, options, flags ); - } - - if ( ok ) - { - mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() ); - } + setDataProvider( provider, options, flags ); } QgsPointXY QgsMeshLayer::snapOnElement( QgsMesh::ElementType elementType, const QgsPointXY &point, double searchRadius ) @@ -1693,8 +1703,15 @@ bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvid return false; } + if ( !mTemporalProperties->isValid() ) + { + mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( dataProvider()->temporalCapabilities() ); + } + mDataProvider->setTemporalUnit( mTemporalUnit ); + mDatasetGroupStore->setPersistentProvider( mDataProvider, mExtraDatasetUri ); + setCrs( mDataProvider->crs() ); if ( provider == QLatin1String( "mesh_memory" ) ) @@ -1703,8 +1720,17 @@ bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvid mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() ); } + // set default style if required by flags or if the dataset group does not has a style yet for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i ) - assignDefaultStyleToDatasetGroup( i ); + { + int globalIndex = mDatasetGroupStore->globalDatasetGroupIndexInSource( mDataProvider, i ); + if ( globalIndex != -1 && + ( !mRendererSettings.hasSettings( globalIndex ) || ( flags & QgsDataProvider::FlagLoadDefaultStyle ) ) ) + assignDefaultStyleToDatasetGroup( globalIndex ); + } + + emit rendererChanged(); + emitStyleChanged(); connect( mDataProvider, &QgsMeshDataProvider::dataChanged, this, &QgsMeshLayer::dataChanged ); diff --git a/src/core/mesh/qgsmeshlayer.h b/src/core/mesh/qgsmeshlayer.h index 3a768aebfe4a..89aa0f5ba3c3 100644 --- a/src/core/mesh/qgsmeshlayer.h +++ b/src/core/mesh/qgsmeshlayer.h @@ -112,8 +112,17 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer : transformContext( transformContext ) {} + /** + * Coordinate transform context + */ QgsCoordinateTransformContext transformContext; + /** + * Set to TRUE if the default layer style should be loaded. + * \since QGIS 3.22 + */ + bool loadDefaultStyle = true; + /** * Controls whether the layer is allowed to have an invalid/unknown CRS. * @@ -182,6 +191,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer QString htmlMetadata() const override; bool isEditable() const override; bool supportsEditing() const override; + QString loadDefaultStyle( bool &resultFlag SIP_OUT ) FINAL; //! Returns the provider type for this layer QString providerType() const; diff --git a/src/core/mesh/qgsmeshlayertemporalproperties.cpp b/src/core/mesh/qgsmeshlayertemporalproperties.cpp index c59708eed1f1..5f829bfd83a3 100644 --- a/src/core/mesh/qgsmeshlayertemporalproperties.cpp +++ b/src/core/mesh/qgsmeshlayertemporalproperties.cpp @@ -61,6 +61,7 @@ bool QgsMeshLayerTemporalProperties::readXml( const QDomElement &element, const mMatchingMethod = static_cast( temporalElement.attribute( QStringLiteral( "matching-method" ) ).toInt() ); + mIsValid = true; return true; } @@ -74,6 +75,8 @@ void QgsMeshLayerTemporalProperties::setDefaultsFromDataProviderTemporalCapabili if ( mReferenceTime.isValid() ) mTimeExtent = temporalCapabilities->timeExtent(); + + mIsValid = true; } QgsDateTimeRange QgsMeshLayerTemporalProperties::calculateTemporalExtent( QgsMapLayer * ) const @@ -112,3 +115,13 @@ void QgsMeshLayerTemporalProperties::setMatchingMethod( const QgsMeshDataProvide { mMatchingMethod = matchingMethod; } + +bool QgsMeshLayerTemporalProperties::isValid() const +{ + return mIsValid; +} + +void QgsMeshLayerTemporalProperties::setIsValid( bool isValid ) +{ + mIsValid = isValid; +} diff --git a/src/core/mesh/qgsmeshlayertemporalproperties.h b/src/core/mesh/qgsmeshlayertemporalproperties.h index 324aa9b1abf6..cd23b2ffab0a 100644 --- a/src/core/mesh/qgsmeshlayertemporalproperties.h +++ b/src/core/mesh/qgsmeshlayertemporalproperties.h @@ -100,11 +100,28 @@ class CORE_EXPORT QgsMeshLayerTemporalProperties : public QgsMapLayerTemporalPro */ void setMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod ); + /** + * Returns whether the instance is valid + * + * \since QGIS 3.22 + */ + bool isValid() const; + + /** + * Sets whether the instance is valid + * + * \param isValid whether the instance is valid + * + * \since QGIS 3.22 + */ + void setIsValid( bool isValid ); + private: QDateTime mReferenceTime; QgsDateTimeRange mTimeExtent; QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod mMatchingMethod = QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetBeforeStartRangeTime; + bool mIsValid = false; }; #endif // QGSMESHLAYERTEMPORALPROPERTIES_H diff --git a/src/core/mesh/qgsmeshrenderersettings.cpp b/src/core/mesh/qgsmeshrenderersettings.cpp index 0e56afcfbd82..baf46f799d42 100644 --- a/src/core/mesh/qgsmeshrenderersettings.cpp +++ b/src/core/mesh/qgsmeshrenderersettings.cpp @@ -740,3 +740,7 @@ void QgsMeshRendererVectorTracesSettings::setParticlesCount( int value ) mParticlesCount = value; } +bool QgsMeshRendererSettings::hasSettings( int datasetGroupIndex ) const +{ + return mRendererScalarSettings.contains( datasetGroupIndex ) || mRendererVectorSettings.contains( datasetGroupIndex ); +} diff --git a/src/core/mesh/qgsmeshrenderersettings.h b/src/core/mesh/qgsmeshrenderersettings.h index a90577fbdeb5..cc27c82e9a14 100644 --- a/src/core/mesh/qgsmeshrenderersettings.h +++ b/src/core/mesh/qgsmeshrenderersettings.h @@ -673,6 +673,13 @@ class CORE_EXPORT QgsMeshRendererSettings */ void setActiveVectorDatasetGroup( int activeVectorDatasetGroup ); + /** + * Returns whether the group with \a index has render settings (scalar or vector) + * + * \since QGIS 3.22 + */ + bool hasSettings( int datasetGroupIndex ) const; + private: QgsMeshRendererMeshSettings mRendererNativeMeshSettings; QgsMeshRendererMeshSettings mRendererTriangularMeshSettings; diff --git a/src/core/qgsmaplayerfactory.cpp b/src/core/qgsmaplayerfactory.cpp index a2a18495de2e..f28d038540e7 100644 --- a/src/core/qgsmaplayerfactory.cpp +++ b/src/core/qgsmaplayerfactory.cpp @@ -91,6 +91,7 @@ QgsMapLayer *QgsMapLayerFactory::createLayer( const QString &uri, const QString { QgsMeshLayer::LayerOptions meshOptions; meshOptions.transformContext = options.transformContext; + meshOptions.loadDefaultStyle = options.loadDefaultStyle; return new QgsMeshLayer( uri, name, provider, meshOptions ); }