QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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
72QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
73{
74 return new QgsPackageAlgorithm();
75}
76
77bool QgsPackageAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
78{
79 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
80
81 for ( const QgsMapLayer *layer : std::as_const( layers ) )
82 {
83 QgsMapLayer *clonedLayer { layer->clone() };
84 mClonedLayerIds.insert( clonedLayer->id(), layer->id() );
85 mLayers.emplace_back( clonedLayer );
86 }
87
88 if ( mLayers.empty() )
89 {
90 feedback->reportError( QObject::tr( "No layers selected, geopackage will be empty" ), false );
91 }
92
93 return true;
94}
95
96QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
97{
98 const bool overwrite = parameterAsBoolean( parameters, QStringLiteral( "OVERWRITE" ), context );
99 const bool saveStyles = parameterAsBoolean( parameters, QStringLiteral( "SAVE_STYLES" ), context );
100 const bool saveMetadata = parameterAsBoolean( parameters, QStringLiteral( "SAVE_METADATA" ), context );
101 const bool selectedFeaturesOnly = parameterAsBoolean( parameters, QStringLiteral( "SELECTED_FEATURES_ONLY" ), context );
102 const bool exportRelatedLayers = parameterAsBoolean( parameters, QStringLiteral( "EXPORT_RELATED_LAYERS" ), context );
103 const QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
104 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
105
106 if ( packagePath.isEmpty() )
107 throw QgsProcessingException( QObject::tr( "No output file specified." ) );
108
109 // delete existing geopackage if it exists
110 if ( overwrite && QFile::exists( packagePath ) )
111 {
112 feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
113 if ( !QFile( packagePath ).remove() )
114 {
115 throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ).arg( packagePath ) );
116 }
117 }
118
119 OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
120 if ( !hGpkgDriver )
121 {
122 throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
123 }
124
125
126 // Collect related layers from project relations
127 if ( exportRelatedLayers )
128 {
129 const QgsProject *project { context.project() };
130 if ( project && !project->relationManager()->relations().isEmpty() )
131 {
132 // Infinite recursion should not happen in the real world but better safe than sorry
133 const int maxRecursion { 10 };
134 int recursionGuard { 0 };
135
136 // This function recursively finds referenced layers
137 const auto findReferenced = [=, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferenced ) -> void {
138 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
139 Q_ASSERT( originalLayer );
140 const QList<QgsRelation> relations { project->relationManager()->referencingRelations( originalLayer ) };
141 for ( const QgsRelation &relation : std::as_const( relations ) )
142 {
143 QgsVectorLayer *referencedLayer { relation.referencedLayer() };
144 QgsVectorLayer *relatedLayer { nullptr };
145
146 // Check if the layer was already in the export list
147 bool alreadyAdded { false };
148 for ( const auto &layerToExport : std::as_const( mLayers ) )
149 {
150 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
151 if ( originalId == referencedLayer->id() )
152 {
153 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
154 alreadyAdded = true;
155 break;
156 }
157 }
158
159 if ( !alreadyAdded )
160 {
161 feedback->pushInfo( QObject::tr( "Adding referenced layer '%1'" ).arg( referencedLayer->name() ) );
162 relatedLayer = referencedLayer->clone();
163 mLayers.emplace_back( relatedLayer );
164 mClonedLayerIds.insert( relatedLayer->id(), referencedLayer->id() );
165 }
166
167 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
168 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
169 if ( onlySaveSelected )
170 {
171 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->selectedFeatureCount() > 0 )
172 {
173 Q_ASSERT( relatedLayer );
174 QgsFeatureIds selected;
175 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
176 QgsFeature selectedFeature;
177 while ( it.nextFeature( selectedFeature ) )
178 {
179 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
180 if ( referencedFeature.isValid() )
181 {
182 selected.insert( referencedFeature.id() );
183 }
184 }
185 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
186 }
187 }
188
189 // Recursive finding
190 if ( recursionGuard > maxRecursion )
191 {
192 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->name() ) );
193 }
194 else
195 {
196 recursionGuard++;
197 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
198 }
199 }
200 };
201
202 // This function recursively finds referencing layers
203 const auto findReferencing = [=, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferencing ) -> void {
204 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
205 Q_ASSERT( originalLayer );
206 const QList<QgsRelation> relations { project->relationManager()->referencedRelations( originalLayer ) };
207 for ( const QgsRelation &relation : std::as_const( relations ) )
208 {
209 QgsVectorLayer *referencingLayer { relation.referencingLayer() };
210 QgsVectorLayer *relatedLayer { nullptr };
211 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
212
213 // Check if the layer was already in the export list
214 bool alreadyAdded { false };
215 for ( const auto &layerToExport : std::as_const( mLayers ) )
216 {
217 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
218 if ( originalId == referencingLayer->id() )
219 {
220 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
221 alreadyAdded = true;
222 break;
223 }
224 }
225
226 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
227 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
228 QgsFeatureIds selected;
229
230 if ( onlySaveSelected && ( !layerWasExplicitlyAdded || referencingLayer->selectedFeatureCount() > 0 ) )
231 {
232 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->selectedFeatureCount() > 0 )
233 {
234 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
235 QgsFeature selectedFeature;
236 while ( it.nextFeature( selectedFeature ) )
237 {
238 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
239 QgsFeature referencingFeature;
240 while ( referencingFeaturesIterator.nextFeature( referencingFeature ) )
241 {
242 if ( referencingFeature.isValid() )
243 {
244 selected.insert( referencingFeature.id() );
245 }
246 }
247 }
248 }
249 }
250
251 if ( !alreadyAdded && ( !onlySaveSelected || !selected.isEmpty() ) )
252 {
253 feedback->pushInfo( QObject::tr( "Adding referencing layer '%1'" ).arg( referencingLayer->name() ) );
254 relatedLayer = referencingLayer->clone();
255 mLayers.emplace_back( relatedLayer );
256 mClonedLayerIds.insert( relatedLayer->id(), referencingLayer->id() );
257 }
258
259 if ( relatedLayer && !selected.isEmpty() )
260 {
261 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
262 }
263
264 // Recursive finding
265 if ( recursionGuard > maxRecursion )
266 {
267 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->name() ) );
268 }
269 else if ( relatedLayer )
270 {
271 recursionGuard++;
272 findReferencing( relatedLayer, onlySaveSelected, findReferencing );
273 }
274 }
275 };
276
277 for ( const QgsMapLayer *layer : std::as_const( layers ) )
278 {
279 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
280 if ( vLayer )
281 {
282 const bool onlySaveSelected = vLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
283 recursionGuard = 0;
284 findReferenced( vLayer, onlySaveSelected, findReferenced );
285 recursionGuard = 0;
286 findReferencing( vLayer, onlySaveSelected, findReferencing );
287 }
288 }
289 }
290 }
291
293
294 if ( !QFile::exists( packagePath ) )
295 {
296 hDS = gdal::ogr_datasource_unique_ptr( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
297 if ( !hDS )
298 throw QgsProcessingException( QObject::tr( "Creation of database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
299 }
300 else
301 {
302 hDS = gdal::ogr_datasource_unique_ptr( OGROpen( packagePath.toUtf8().constData(), true, nullptr ) );
303 if ( !hDS )
304 throw QgsProcessingException( QObject::tr( "Opening database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
305 }
306
307
308 bool errored = false;
309
310 QgsProcessingMultiStepFeedback multiStepFeedback( mLayers.size(), feedback );
311
312 QStringList outputLayers;
313
314 int i = 0;
315 for ( const auto &layer : mLayers )
316 {
317 if ( feedback->isCanceled() )
318 break;
319
320 multiStepFeedback.setCurrentStep( i );
321 i++;
322
323 if ( !layer )
324 {
325 // don't throw immediately - instead do what we can and error out later
326 feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
327 errored = true;
328 continue;
329 }
330
331 feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
332
333 switch ( layer->type() )
334 {
336 {
337 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
338 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, selectedFeaturesOnly ) )
339 errored = true;
340 else
341 outputLayers.append( QStringLiteral( "%1|layername=%2" ).arg( packagePath, layer->name() ) );
342 break;
343 }
344
346 {
347 //not supported
348 feedback->pushDebugInfo( QObject::tr( "Packaging raster layers is not supported." ) );
349 errored = true;
350 break;
351 }
352
354 //not supported
355 feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
356 errored = true;
357 break;
358
360 //not supported
361 feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
362 errored = true;
363 break;
364
366 //not supported
367 feedback->pushDebugInfo( QObject::tr( "Packaging point cloud layers is not supported." ) );
368 errored = true;
369 break;
370
372 //not supported
373 feedback->pushDebugInfo( QObject::tr( "Packaging vector tile layers is not supported." ) );
374 errored = true;
375 break;
376
378 //not supported
379 feedback->pushDebugInfo( QObject::tr( "Packaging annotation layers is not supported." ) );
380 errored = true;
381 break;
382
384 //not supported
385 feedback->pushDebugInfo( QObject::tr( "Packaging group layers is not supported." ) );
386 errored = true;
387 break;
388
390 //not supported
391 feedback->pushDebugInfo( QObject::tr( "Packaging tiled scene layers is not supported." ) );
392 errored = true;
393 break;
394 }
395 }
396
397 if ( errored )
398 throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
399
400 QVariantMap outputs;
401 outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
402 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
403 return outputs;
404}
405
406bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback, bool saveStyles, bool saveMetadata, bool selectedFeaturesOnly )
407{
409 options.driverName = QStringLiteral( "GPKG" );
410 options.layerName = layer->name();
412 options.fileEncoding = context.defaultEncoding();
413 options.onlySelectedFeatures = selectedFeaturesOnly;
414 options.feedback = feedback;
415 if ( saveMetadata )
416 {
417 options.layerMetadata = layer->metadata();
418 options.saveMetadata = true;
419 }
420
421 // Check FID compatibility with GPKG and remove any existing FID field if not compatible,
422 // let this be completely recreated since many layer sources have fid fields which are
423 // not compatible with gpkg requirements
424 const QgsFields fields = layer->fields();
425 const int fidIndex = fields.lookupField( QStringLiteral( "fid" ) );
426
427 options.attributes = fields.allAttributesList();
428 if ( fidIndex >= 0 )
429 {
430 const QMetaType::Type fidType { layer->fields().field( fidIndex ).type() };
433 && fidType != QMetaType::Type::Int
434 && fidType != QMetaType::Type::UInt
435 && fidType != QMetaType::Type::LongLong
436 && fidType != QMetaType::Type::ULongLong )
437 {
438 options.attributes.removeAll( fidIndex );
439 }
440 }
441
442 if ( options.attributes.isEmpty() )
443 {
444 // fid was the only field
445 options.skipAttributeCreation = true;
446 }
447
448 QString error;
449 QString newFilename;
450 QString newLayer;
451 if ( QgsVectorFileWriter::writeAsVectorFormatV3( layer, path, context.transformContext(), options, &error, &newFilename, &newLayer ) != QgsVectorFileWriter::NoError )
452 {
453 feedback->reportError( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
454 return false;
455 }
456 else
457 {
458 if ( saveStyles )
459 {
460 std::unique_ptr<QgsVectorLayer> res = std::make_unique<QgsVectorLayer>( QStringLiteral( "%1|layername=%2" ).arg( newFilename, newLayer ) );
461 if ( res )
462 {
463 QString errorMsg;
464 QDomDocument doc( QStringLiteral( "qgis" ) );
465 const QgsReadWriteContext context;
466 layer->exportNamedStyle( doc, errorMsg, context );
467 if ( !errorMsg.isEmpty() )
468 {
469 feedback->reportError( QObject::tr( "Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
470 }
471 else
472 {
473 if ( !res->importNamedStyle( doc, errorMsg ) )
474 {
475 feedback->reportError( QObject::tr( "Could not set existing layer style: %1 " ).arg( errorMsg ) );
476 }
477 else
478 {
479 QgsSettings settings;
480 // this is not nice -- but needed to avoid an "overwrite" prompt messagebox from the provider! This api needs a rework to avoid this.
481 const QVariant prevOverwriteStyle = settings.value( QStringLiteral( "qgis/overwriteStyle" ) );
482 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), true );
483 res->saveStyleToDatabase( newLayer, QString(), true, QString(), errorMsg );
484 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), prevOverwriteStyle );
485 if ( !errorMsg.isEmpty() )
486 {
487 feedback->reportError( QObject::tr( "Could not save layer style: %1 " ).arg( errorMsg ) );
488 }
489 }
490 }
491 }
492 else
493 {
494 feedback->reportError( QObject::tr( "Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
495 }
496 }
497 return true;
498 }
499}
500
@ 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:76
QString name
Definition qgsmaplayer.h:80
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:82
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
The class is used as a container of context for various read/write operations on other objects.
Represents a relationship between two vector layers.
Definition qgsrelation.h:44
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
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 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 data sets.
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