diff --git a/src/core/utils/layerutils.cpp b/src/core/utils/layerutils.cpp index 27fdf09775..e7f3fa904d 100644 --- a/src/core/utils/layerutils.cpp +++ b/src/core/utils/layerutils.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -545,6 +546,16 @@ bool LayerUtils::hasMValue( QgsVectorLayer *layer ) return QgsWkbTypes::hasM( layer->wkbType() ); } +QSet LayerUtils::uniqueValuesForVectorLayerFieldIndex( QgsVectorLayer *layer, int fieldIndex ) +{ + if ( !layer ) + { + return QSet(); + } + + return layer->uniqueValues( fieldIndex ); +} + QgsVectorLayer *LayerUtils::loadVectorLayer( const QString &uri, const QString &name, const QString &provider ) { QgsVectorLayer *layer = new QgsVectorLayer( uri, name, provider ); @@ -595,3 +606,64 @@ FeatureIterator LayerUtils::createFeatureIteratorFromRectangle( QgsVectorLayer * const QgsFeatureRequest request = QgsFeatureRequest( rectangle ); return FeatureIterator( layer, request ); } + +QString LayerUtils::saveVectorLayerAs( QgsVectorLayer *layer, const QString &filePath, const QString &driverName, const QString &filterExpression ) +{ + if ( !layer || filePath.isEmpty() ) + { + return QString(); + } + + QFileInfo fileInfo( filePath ); + const QString finalDriverName = driverName.isEmpty() ? QgsVectorFileWriter::driverForExtension( fileInfo.suffix() ) : driverName; + if ( finalDriverName.isEmpty() ) + { + return QString(); + } + QDir dir; + if ( !dir.mkpath( fileInfo.absolutePath() ) ) + { + return QString(); + } + + QStringList datasetOptions = QgsVectorFileWriter::defaultDatasetOptions( finalDriverName ); + if ( finalDriverName == QStringLiteral( "GPX" ) ) + { + datasetOptions.removeAll( QStringLiteral( "GPX_USE_EXTENSIONS=NO" ) ); + datasetOptions << QStringLiteral( "GPX_USE_EXTENSIONS=YES" ); + } + + QString finalFileName; + QString finalLayerName; + QgsVectorFileWriter::SaveVectorOptions saveOptions; + saveOptions.fileEncoding = QStringLiteral( "UTF8" ); + saveOptions.layerName = fileInfo.completeBaseName(); + saveOptions.driverName = finalDriverName; + saveOptions.datasourceOptions = datasetOptions; + saveOptions.layerOptions = QgsVectorFileWriter::defaultLayerOptions( finalDriverName ); + saveOptions.symbologyExport = Qgis::FeatureSymbologyExport::NoSymbology; + saveOptions.actionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile; + + std::unique_ptr writer( QgsVectorFileWriter::create( filePath, layer->fields(), layer->wkbType(), layer->crs(), QgsProject::instance()->transformContext(), saveOptions, QgsFeatureSink::RegeneratePrimaryKey, &finalFileName, &finalLayerName ) ); + if ( writer->hasError() ) + { + qInfo() << QStringLiteral( "Vector layer file writer error: %1" ).arg( writer->errorMessage() ); + return QString(); + } + + QgsFeatureRequest request; + if ( !filterExpression.isEmpty() ) + { + request.setFilterExpression( filterExpression ); + request.setExpressionContext( layer->createExpressionContext() ); + } + + QgsFeatureIterator it = layer->getFeatures( request ); + QgsFeature feature; + while ( it.nextFeature( feature ) ) + { + writer->addFeature( feature, QgsFeatureSink::FastInsert ); + } + + return finalFileName; +} diff --git a/src/core/utils/layerutils.h b/src/core/utils/layerutils.h index 05cd9355d8..1a1f4ff8fc 100644 --- a/src/core/utils/layerutils.h +++ b/src/core/utils/layerutils.h @@ -180,6 +180,11 @@ class LayerUtils : public QObject */ Q_INVOKABLE static bool hasMValue( QgsVectorLayer *layer ); + /** + * Returns a list of unique values for a given \a fieldIndex from the \a layer. + */ + Q_INVOKABLE QSet uniqueValuesForVectorLayerFieldIndex( QgsVectorLayer *layer, int fieldIndex ); + /** * Loads a vector layer. * \param uri the data source uri @@ -226,6 +231,16 @@ class LayerUtils : public QObject * Returns a feature iterator to get features overlapping a given \a rectangle within the provided \a layer. */ Q_INVOKABLE static FeatureIterator createFeatureIteratorFromRectangle( QgsVectorLayer *layer, const QgsRectangle &rectangle ); + + /** + * Saves a vector layer into an on-disk dataset a given path using the OGR provider. + * \param layer the vector layer to save features from + * \param filePath the file path where the dataset will be writen + * \param driverName an optional OGR driver name (if left empty, the file path extension will drive the OGR driver) + * \param filterExpression an optional filter expression used to save a subset of features from the layer (note that only the global, project, and layer expression context scopes are used) + * \returns If successful, finalized file path will be returned, otherwise an empty string will be returned + */ + Q_INVOKABLE static QString saveVectorLayerAs( QgsVectorLayer *layer, const QString &filePath, const QString &driverName = QString(), const QString &filterExpression = QString() ); }; #endif // LAYERUTILS_H