QGIS API Documentation 3.43.0-Master (e01d6d7c4c0)
qgsalgorithmpackage.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmpackage.cpp
3 ---------------------
4 begin : November 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsalgorithmpackage.h"
19#include "qgsogrutils.h"
20#include "qgsvectorfilewriter.h"
21#include "qgsvectorlayer.h"
22#include "qgssettings.h"
23
24#include <QLocale>
25
27
28QString QgsPackageAlgorithm::name() const
29{
30 return QStringLiteral( "package" );
31}
32
33QString QgsPackageAlgorithm::displayName() const
34{
35 return QObject::tr( "Package layers" );
36}
37
38QStringList QgsPackageAlgorithm::tags() const
39{
40 return QObject::tr( "geopackage,collect,merge,combine,styles" ).split( ',' );
41}
42
43QString QgsPackageAlgorithm::group() const
44{
45 return QObject::tr( "Database" );
46}
47
48QString QgsPackageAlgorithm::groupId() const
49{
50 return QStringLiteral( "database" );
51}
52
53void QgsPackageAlgorithm::initAlgorithm( const QVariantMap & )
54{
55 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), Qgis::ProcessingSourceType::Vector ) );
56 QgsProcessingParameterFileDestination *outputParameter = new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QObject::tr( "GeoPackage files (*.gpkg)" ) );
57 outputParameter->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "dontconfirmoverwrite" ), true } } ) } } ) );
58 addParameter( outputParameter );
59 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite existing GeoPackage" ), false ) );
60 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_STYLES" ), QObject::tr( "Save layer styles into GeoPackage" ), true ) );
61 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_METADATA" ), QObject::tr( "Save layer metadata into GeoPackage" ), true ) );
62 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SELECTED_FEATURES_ONLY" ), QObject::tr( "Save only selected features" ), false ) );
63 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "EXPORT_RELATED_LAYERS" ), QObject::tr( "Export related layers following relations defined in the project" ), false ) );
64 addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Layers within new package" ) ) );
65}
66
67QString QgsPackageAlgorithm::shortHelpString() const
68{
69 return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
70}
71
72QString QgsPackageAlgorithm::shortDescription() const
73{
74 return QObject::tr( "Packages a number of existing layers together into a single GeoPackage database." );
75}
76
77QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
78{
79 return new QgsPackageAlgorithm();
80}
81
82bool QgsPackageAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
83{
84 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
85
86 for ( const QgsMapLayer *layer : std::as_const( layers ) )
87 {
88 QgsMapLayer *clonedLayer { layer->clone() };
89 mClonedLayerIds.insert( clonedLayer->id(), layer->id() );
90 mLayers.emplace_back( clonedLayer );
91 }
92
93 if ( mLayers.empty() )
94 {
95 feedback->reportError( QObject::tr( "No layers selected, geopackage will be empty" ), false );
96 }
97
98 return true;
99}
100
101QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
102{
103 const bool overwrite = parameterAsBoolean( parameters, QStringLiteral( "OVERWRITE" ), context );
104 const bool saveStyles = parameterAsBoolean( parameters, QStringLiteral( "SAVE_STYLES" ), context );
105 const bool saveMetadata = parameterAsBoolean( parameters, QStringLiteral( "SAVE_METADATA" ), context );
106 const bool selectedFeaturesOnly = parameterAsBoolean( parameters, QStringLiteral( "SELECTED_FEATURES_ONLY" ), context );
107 const bool exportRelatedLayers = parameterAsBoolean( parameters, QStringLiteral( "EXPORT_RELATED_LAYERS" ), context );
108 const QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
109 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
110
111 if ( packagePath.isEmpty() )
112 throw QgsProcessingException( QObject::tr( "No output file specified." ) );
113
114 // delete existing geopackage if it exists
115 if ( overwrite && QFile::exists( packagePath ) )
116 {
117 feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
118 if ( !QFile( packagePath ).remove() )
119 {
120 throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ).arg( packagePath ) );
121 }
122 }
123
124 OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
125 if ( !hGpkgDriver )
126 {
127 throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
128 }
129
130
131 // Collect related layers from project relations
132 if ( exportRelatedLayers )
133 {
134 const QgsProject *project { context.project() };
135 if ( project && !project->relationManager()->relations().isEmpty() )
136 {
137 // Infinite recursion should not happen in the real world but better safe than sorry
138 const int maxRecursion { 10 };
139 int recursionGuard { 0 };
140
141 // This function recursively finds referenced layers
142 const auto findReferenced = [=, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferenced ) -> void {
143 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
144 Q_ASSERT( originalLayer );
145 const QList<QgsRelation> relations { project->relationManager()->referencingRelations( originalLayer ) };
146 for ( const QgsRelation &relation : std::as_const( relations ) )
147 {
148 QgsVectorLayer *referencedLayer { relation.referencedLayer() };
149 QgsVectorLayer *relatedLayer { nullptr };
150
151 // Check if the layer was already in the export list
152 bool alreadyAdded { false };
153 for ( const auto &layerToExport : std::as_const( mLayers ) )
154 {
155 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
156 if ( originalId == referencedLayer->id() )
157 {
158 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
159 alreadyAdded = true;
160 break;
161 }
162 }
163
164 if ( !alreadyAdded )
165 {
166 feedback->pushInfo( QObject::tr( "Adding referenced layer '%1'" ).arg( referencedLayer->name() ) );
167 relatedLayer = referencedLayer->clone();
168 mLayers.emplace_back( relatedLayer );
169 mClonedLayerIds.insert( relatedLayer->id(), referencedLayer->id() );
170 }
171
172 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
173 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
174 if ( onlySaveSelected )
175 {
176 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->selectedFeatureCount() > 0 )
177 {
178 Q_ASSERT( relatedLayer );
179 QgsFeatureIds selected;
180 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
181 QgsFeature selectedFeature;
182 while ( it.nextFeature( selectedFeature ) )
183 {
184 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
185 if ( referencedFeature.isValid() )
186 {
187 selected.insert( referencedFeature.id() );
188 }
189 }
190 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
191 }
192 }
193
194 // Recursive finding
195 if ( recursionGuard > maxRecursion )
196 {
197 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->name() ) );
198 }
199 else
200 {
201 recursionGuard++;
202 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
203 }
204 }
205 };
206
207 // This function recursively finds referencing layers
208 const auto findReferencing = [=, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferencing ) -> void {
209 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
210 Q_ASSERT( originalLayer );
211 const QList<QgsRelation> relations { project->relationManager()->referencedRelations( originalLayer ) };
212 for ( const QgsRelation &relation : std::as_const( relations ) )
213 {
214 QgsVectorLayer *referencingLayer { relation.referencingLayer() };
215 QgsVectorLayer *relatedLayer { nullptr };
216 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
217
218 // Check if the layer was already in the export list
219 bool alreadyAdded { false };
220 for ( const auto &layerToExport : std::as_const( mLayers ) )
221 {
222 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
223 if ( originalId == referencingLayer->id() )
224 {
225 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
226 alreadyAdded = true;
227 break;
228 }
229 }
230
231 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
232 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
233 QgsFeatureIds selected;
234
235 if ( onlySaveSelected && ( !layerWasExplicitlyAdded || referencingLayer->selectedFeatureCount() > 0 ) )
236 {
237 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->selectedFeatureCount() > 0 )
238 {
239 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
240 QgsFeature selectedFeature;
241 while ( it.nextFeature( selectedFeature ) )
242 {
243 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
244 QgsFeature referencingFeature;
245 while ( referencingFeaturesIterator.nextFeature( referencingFeature ) )
246 {
247 if ( referencingFeature.isValid() )
248 {
249 selected.insert( referencingFeature.id() );
250 }
251 }
252 }
253 }
254 }
255
256 if ( !alreadyAdded && ( !onlySaveSelected || !selected.isEmpty() ) )
257 {
258 feedback->pushInfo( QObject::tr( "Adding referencing layer '%1'" ).arg( referencingLayer->name() ) );
259 relatedLayer = referencingLayer->clone();
260 mLayers.emplace_back( relatedLayer );
261 mClonedLayerIds.insert( relatedLayer->id(), referencingLayer->id() );
262 }
263
264 if ( relatedLayer && !selected.isEmpty() )
265 {
266 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
267 }
268
269 // Recursive finding
270 if ( recursionGuard > maxRecursion )
271 {
272 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->name() ) );
273 }
274 else if ( relatedLayer )
275 {
276 recursionGuard++;
277 findReferencing( relatedLayer, onlySaveSelected, findReferencing );
278 }
279 }
280 };
281
282 for ( const QgsMapLayer *layer : std::as_const( layers ) )
283 {
284 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
285 if ( vLayer )
286 {
287 const bool onlySaveSelected = vLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
288 recursionGuard = 0;
289 findReferenced( vLayer, onlySaveSelected, findReferenced );
290 recursionGuard = 0;
291 findReferencing( vLayer, onlySaveSelected, findReferencing );
292 }
293 }
294 }
295 }
296
298
299 if ( !QFile::exists( packagePath ) )
300 {
301 hDS = gdal::ogr_datasource_unique_ptr( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
302 if ( !hDS )
303 throw QgsProcessingException( QObject::tr( "Creation of database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
304 }
305 else
306 {
307 hDS = gdal::ogr_datasource_unique_ptr( OGROpen( packagePath.toUtf8().constData(), true, nullptr ) );
308 if ( !hDS )
309 throw QgsProcessingException( QObject::tr( "Opening database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
310 }
311
312
313 bool errored = false;
314
315 QgsProcessingMultiStepFeedback multiStepFeedback( mLayers.size(), feedback );
316
317 QStringList outputLayers;
318
319 int i = 0;
320 for ( const auto &layer : mLayers )
321 {
322 if ( feedback->isCanceled() )
323 break;
324
325 multiStepFeedback.setCurrentStep( i );
326 i++;
327
328 if ( !layer )
329 {
330 // don't throw immediately - instead do what we can and error out later
331 feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
332 errored = true;
333 continue;
334 }
335
336 feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
337
338 switch ( layer->type() )
339 {
341 {
342 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
343 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, selectedFeaturesOnly ) )
344 errored = true;
345 else
346 outputLayers.append( QStringLiteral( "%1|layername=%2" ).arg( packagePath, layer->name() ) );
347 break;
348 }
349
351 {
352 //not supported
353 feedback->pushDebugInfo( QObject::tr( "Packaging raster layers is not supported." ) );
354 errored = true;
355 break;
356 }
357
359 //not supported
360 feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
361 errored = true;
362 break;
363
365 //not supported
366 feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
367 errored = true;
368 break;
369
371 //not supported
372 feedback->pushDebugInfo( QObject::tr( "Packaging point cloud layers is not supported." ) );
373 errored = true;
374 break;
375
377 //not supported
378 feedback->pushDebugInfo( QObject::tr( "Packaging vector tile layers is not supported." ) );
379 errored = true;
380 break;
381
383 //not supported
384 feedback->pushDebugInfo( QObject::tr( "Packaging annotation layers is not supported." ) );
385 errored = true;
386 break;
387
389 //not supported
390 feedback->pushDebugInfo( QObject::tr( "Packaging group layers is not supported." ) );
391 errored = true;
392 break;
393
395 //not supported
396 feedback->pushDebugInfo( QObject::tr( "Packaging tiled scene layers is not supported." ) );
397 errored = true;
398 break;
399 }
400 }
401
402 if ( errored )
403 throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
404
405 QVariantMap outputs;
406 outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
407 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
408 return outputs;
409}
410
411bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback, bool saveStyles, bool saveMetadata, bool selectedFeaturesOnly )
412{
414 options.driverName = QStringLiteral( "GPKG" );
415 options.layerName = layer->name();
417 options.fileEncoding = context.defaultEncoding();
418 options.onlySelectedFeatures = selectedFeaturesOnly;
419 options.feedback = feedback;
420 if ( saveMetadata )
421 {
422 options.layerMetadata = layer->metadata();
423 options.saveMetadata = true;
424 }
425
426 // Check FID compatibility with GPKG and remove any existing FID field if not compatible,
427 // let this be completely recreated since many layer sources have fid fields which are
428 // not compatible with gpkg requirements
429 const QgsFields fields = layer->fields();
430 const int fidIndex = fields.lookupField( QStringLiteral( "fid" ) );
431
432 options.attributes = fields.allAttributesList();
433 if ( fidIndex >= 0 )
434 {
435 const QMetaType::Type fidType { layer->fields().field( fidIndex ).type() };
438 && fidType != QMetaType::Type::Int
439 && fidType != QMetaType::Type::UInt
440 && fidType != QMetaType::Type::LongLong
441 && fidType != QMetaType::Type::ULongLong )
442 {
443 options.attributes.removeAll( fidIndex );
444 }
445 }
446
447 if ( options.attributes.isEmpty() )
448 {
449 // fid was the only field
450 options.skipAttributeCreation = true;
451 }
452
453 QString error;
454 QString newFilename;
455 QString newLayer;
456 if ( QgsVectorFileWriter::writeAsVectorFormatV3( layer, path, context.transformContext(), options, &error, &newFilename, &newLayer ) != QgsVectorFileWriter::NoError )
457 {
458 feedback->reportError( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
459 return false;
460 }
461 else
462 {
463 if ( saveStyles )
464 {
465 auto res = std::make_unique<QgsVectorLayer>( QStringLiteral( "%1|layername=%2" ).arg( newFilename, newLayer ) );
466 if ( res )
467 {
468 QString errorMsg;
469 QDomDocument doc( QStringLiteral( "qgis" ) );
470 const QgsReadWriteContext context;
471 layer->exportNamedStyle( doc, errorMsg, context );
472 if ( !errorMsg.isEmpty() )
473 {
474 feedback->reportError( QObject::tr( "Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
475 }
476 else
477 {
478 if ( !res->importNamedStyle( doc, errorMsg ) )
479 {
480 feedback->reportError( QObject::tr( "Could not set existing layer style: %1 " ).arg( errorMsg ) );
481 }
482 else
483 {
484 QgsSettings settings;
485 // this is not nice -- but needed to avoid an "overwrite" prompt messagebox from the provider! This api needs a rework to avoid this.
486 const QVariant prevOverwriteStyle = settings.value( QStringLiteral( "qgis/overwriteStyle" ) );
487 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), true );
488 res->saveStyleToDatabase( newLayer, QString(), true, QString(), errorMsg );
489 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), prevOverwriteStyle );
490 if ( !errorMsg.isEmpty() )
491 {
492 feedback->reportError( QObject::tr( "Could not save layer style: %1 " ).arg( errorMsg ) );
493 }
494 }
495 }
496 }
497 else
498 {
499 feedback->reportError( QObject::tr( "Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
500 }
501 }
502 return true;
503 }
504}
505
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ AddToSelection
Add selection to current selection.
Wrapper for iterator of features from vector data provider or vector layer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
bool isValid() const
Returns the validity of this feature.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
QMetaType::Type type
Definition qgsfield.h:60
Container of fields for a vector layer.
Definition qgsfields.h:46
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Base class for all map layer types.
Definition qgsmaplayer.h:77
QString name
Definition qgsmaplayer.h:81
virtual void exportNamedStyle(QDomDocument &doc, QString &errorMsg, const QgsReadWriteContext &context=QgsReadWriteContext(), QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const
Export the properties of this layer as named style in a QDomDocument.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:83
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
Contains information about the context in which a processing algorithm is executed.
QString defaultEncoding() const
Returns the default encoding to use for newly created files.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
Processing feedback object for multi-step operations.
A multi-layer output for processing algorithms which create map layers, when the number and nature of...
A boolean parameter for processing algorithms.
void setMetadata(const QVariantMap &metadata)
Sets the parameter's freeform metadata.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
A parameter for processing algorithms which accepts multiple map layers.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
A container for the context for various read/write operations on objects.
Represents a relationship between two vector layers.
Definition qgsrelation.h:44
Stores settings for use within QGIS.
Definition qgssettings.h:65
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Options to pass to QgsVectorFileWriter::writeAsVectorFormat().
QgsLayerMetadata layerMetadata
Layer metadata to save for the exported vector file.
QString layerName
Layer name. If let empty, it will be derived from the filename.
bool saveMetadata
Set to true to save layer metadata for the exported vector file.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
QgsAttributeList attributes
Attributes to export (empty means all unless skipAttributeCreation is set)
bool onlySelectedFeatures
Write only selected features of layer.
bool skipAttributeCreation
Only write geometries.
QgsFeedback * feedback
Optional feedback object allowing cancellation of layer save.
static QgsVectorFileWriter::WriterError writeAsVectorFormatV3(QgsVectorLayer *layer, const QString &fileName, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QString *errorMessage=nullptr, QString *newFilename=nullptr, QString *newLayer=nullptr)
Writes a layer out to a vector file.
@ CreateOrOverwriteLayer
Create or overwrite layer.
Represents a vector layer which manages a vector based dataset.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
QSet< QgsFeatureId > QgsFeatureIds