QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 "qgsgeometryengine.h"
20#include "qgsogrutils.h"
21#include "qgsvectorfilewriter.h"
22#include "qgsvectorlayer.h"
23#include "qgssettings.h"
24
26
27QString QgsPackageAlgorithm::name() const
28{
29 return QStringLiteral( "package" );
30}
31
32QString QgsPackageAlgorithm::displayName() const
33{
34 return QObject::tr( "Package layers" );
35}
36
37QStringList QgsPackageAlgorithm::tags() const
38{
39 return QObject::tr( "geopackage,collect,merge,combine,styles" ).split( ',' );
40}
41
42QString QgsPackageAlgorithm::group() const
43{
44 return QObject::tr( "Database" );
45}
46
47QString QgsPackageAlgorithm::groupId() const
48{
49 return QStringLiteral( "database" );
50}
51
52void QgsPackageAlgorithm::initAlgorithm( const QVariantMap & )
53{
54 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), QgsProcessing::TypeVector ) );
55 QgsProcessingParameterFileDestination *outputParameter = new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QObject::tr( "GeoPackage files (*.gpkg)" ) );
56 outputParameter->setMetadata( QVariantMap( {{QStringLiteral( "widget_wrapper" ), QVariantMap( {{QStringLiteral( "dontconfirmoverwrite" ), true }} ) }} ) );
57 addParameter( outputParameter );
58 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite existing GeoPackage" ), false ) );
59 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_STYLES" ), QObject::tr( "Save layer styles into GeoPackage" ), true ) );
60 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_METADATA" ), QObject::tr( "Save layer metadata into GeoPackage" ), true ) );
61 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SELECTED_FEATURES_ONLY" ), QObject::tr( "Save only selected features" ), false ) );
62 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "EXPORT_RELATED_LAYERS" ), QObject::tr( "Export related layers following relations defined in the project" ), false ) );
63 addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Layers within new package" ) ) );
64}
65
66QString QgsPackageAlgorithm::shortHelpString() const
67{
68 return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
69}
70
71QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
72{
73 return new QgsPackageAlgorithm();
74}
75
76bool QgsPackageAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
77{
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
133 // Infinite recursion should not happen in the real world but better safe than sorry
134 const int maxRecursion { 10 };
135 int recursionGuard { 0 };
136
137 // This function recursively finds referenced layers
138 const auto findReferenced = [ =, &project, &feedback, &recursionGuard, &layers ]( const QgsVectorLayer * vLayer, bool onlySaveSelected, auto &&findReferenced ) -> void
139 {
140 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
141 Q_ASSERT( originalLayer );
142 const QList<QgsRelation> relations { project->relationManager()->referencingRelations( originalLayer ) };
143 for ( const QgsRelation &relation : std::as_const( relations ) )
144 {
145
146 QgsVectorLayer *referencedLayer { relation.referencedLayer() };
147 QgsVectorLayer *relatedLayer { nullptr };
148
149 // Check if the layer was already in the export list
150 bool alreadyAdded { false };
151 for ( const auto &layerToExport : std::as_const( mLayers ) )
152 {
153 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
154 if ( originalId == referencedLayer->id() )
155 {
156 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
157 alreadyAdded = true;
158 break;
159 }
160 }
161
162 if ( !alreadyAdded )
163 {
164 feedback->pushInfo( QObject::tr( "Adding referenced layer '%1'" ).arg( referencedLayer->name() ) );
165 relatedLayer = referencedLayer->clone();
166 mLayers.emplace_back( relatedLayer );
167 mClonedLayerIds.insert( relatedLayer->id(), referencedLayer->id() );
168 }
169
170 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
171 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
172 if ( onlySaveSelected )
173 {
174 if ( ! layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->selectedFeatureCount() > 0 )
175 {
176 Q_ASSERT( relatedLayer );
177 QgsFeatureIds selected;
178 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
179 QgsFeature selectedFeature;
180 while ( it.nextFeature( selectedFeature ) )
181 {
182 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
183 if ( referencedFeature.isValid() )
184 {
185 selected.insert( referencedFeature.id() );
186 }
187 }
188 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
189 }
190 }
191
192 // Recursive finding
193 if ( recursionGuard > maxRecursion )
194 {
195 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->name() ) );
196 }
197 else
198 {
199 recursionGuard++;
200 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
201 }
202 }
203
204 };
205
206 // This function recursively finds referencing layers
207 const auto findReferencing = [ =, &project, &feedback, &recursionGuard, &layers ]( const QgsVectorLayer * vLayer, bool onlySaveSelected, auto &&findReferencing ) -> void
208 {
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
215 QgsVectorLayer *referencingLayer { relation.referencingLayer() };
216 QgsVectorLayer *relatedLayer { nullptr };
217 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
218
219 // Check if the layer was already in the export list
220 bool alreadyAdded { false };
221 for ( const auto &layerToExport : std::as_const( mLayers ) )
222 {
223 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
224 if ( originalId == referencingLayer->id() )
225 {
226 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
227 alreadyAdded = true;
228 break;
229 }
230 }
231
232 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
233 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
234 QgsFeatureIds selected;
235
236 if ( onlySaveSelected && ( ! layerWasExplicitlyAdded || referencingLayer->selectedFeatureCount() > 0 ) )
237 {
238 if ( ! layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->selectedFeatureCount() > 0 )
239 {
240 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
241 QgsFeature selectedFeature;
242 while ( it.nextFeature( selectedFeature ) )
243 {
244 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
245 QgsFeature referencingFeature;
246 while ( referencingFeaturesIterator.nextFeature( referencingFeature ) )
247 {
248 if ( referencingFeature.isValid() )
249 {
250 selected.insert( referencingFeature.id() );
251 }
252 }
253 }
254 }
255 }
256
257 if ( ! alreadyAdded && ( ! onlySaveSelected || ! selected.isEmpty() ) )
258 {
259 feedback->pushInfo( QObject::tr( "Adding referencing layer '%1'" ).arg( referencingLayer->name() ) );
260 relatedLayer = referencingLayer->clone();
261 mLayers.emplace_back( relatedLayer );
262 mClonedLayerIds.insert( relatedLayer->id(), referencingLayer->id() );
263 }
264
265 if ( relatedLayer && ! selected.isEmpty() )
266 {
267 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
268 }
269
270 // Recursive finding
271 if ( recursionGuard > maxRecursion )
272 {
273 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->name() ) );
274 }
275 else if ( relatedLayer )
276 {
277 recursionGuard++;
278 findReferencing( relatedLayer, onlySaveSelected, findReferencing ) ;
279 }
280 }
281
282 };
283
284 for ( const QgsMapLayer *layer : std::as_const( layers ) )
285 {
286 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
287 if ( vLayer )
288 {
289 const bool onlySaveSelected = vLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
290 recursionGuard = 0;
291 findReferenced( vLayer, onlySaveSelected, findReferenced );
292 recursionGuard = 0;
293 findReferencing( vLayer, onlySaveSelected, findReferencing );
294 }
295 }
296
297 }
298 }
299
301
302 if ( !QFile::exists( packagePath ) )
303 {
304 hDS = gdal::ogr_datasource_unique_ptr( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
305 if ( !hDS )
306 throw QgsProcessingException( QObject::tr( "Creation of database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
307 }
308 else
309 {
310 hDS = gdal::ogr_datasource_unique_ptr( OGROpen( packagePath.toUtf8().constData(), true, nullptr ) );
311 if ( !hDS )
312 throw QgsProcessingException( QObject::tr( "Opening database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
313 }
314
315
316 bool errored = false;
317
318 QgsProcessingMultiStepFeedback multiStepFeedback( mLayers.size(), feedback );
319
320 QStringList outputLayers;
321
322 int i = 0;
323 for ( const auto &layer : mLayers )
324 {
325 if ( feedback->isCanceled() )
326 break;
327
328 multiStepFeedback.setCurrentStep( i );
329 i++;
330
331 if ( !layer )
332 {
333 // don't throw immediately - instead do what we can and error out later
334 feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
335 errored = true;
336 continue;
337 }
338
339 feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
340
341 switch ( layer->type() )
342 {
344 {
345 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
346 const bool onlySaveSelected = vectorLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
347 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, onlySaveSelected ) )
348 errored = true;
349 else
350 outputLayers.append( QStringLiteral( "%1|layername=%2" ).arg( packagePath, layer->name() ) );
351 break;
352 }
353
355 {
356 //not supported
357 feedback->pushDebugInfo( QObject::tr( "Packaging raster layers is not supported." ) );
358 errored = true;
359 break;
360 }
361
363 //not supported
364 feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
365 errored = true;
366 break;
367
369 //not supported
370 feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
371 errored = true;
372 break;
373
375 //not supported
376 feedback->pushDebugInfo( QObject::tr( "Packaging point cloud layers is not supported." ) );
377 errored = true;
378 break;
379
381 //not supported
382 feedback->pushDebugInfo( QObject::tr( "Packaging vector tile layers is not supported." ) );
383 errored = true;
384 break;
385
387 //not supported
388 feedback->pushDebugInfo( QObject::tr( "Packaging annotation layers is not supported." ) );
389 errored = true;
390 break;
391
393 //not supported
394 feedback->pushDebugInfo( QObject::tr( "Packaging group layers is not supported." ) );
395 errored = true;
396 break;
397 }
398 }
399
400 if ( errored )
401 throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
402
403 QVariantMap outputs;
404 outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
405 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
406 return outputs;
407}
408
409bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context,
410 QgsProcessingFeedback *feedback, bool saveStyles, bool saveMetadata, bool selectedFeaturesOnly )
411{
413 options.driverName = QStringLiteral( "GPKG" );
414 options.layerName = layer->name();
416 options.fileEncoding = context.defaultEncoding();
417 options.onlySelectedFeatures = selectedFeaturesOnly;
418 options.feedback = feedback;
419 if ( saveMetadata )
420 {
421 options.layerMetadata = layer->metadata();
422 options.saveMetadata = true;
423 }
424
425 // Check FID compatibility with GPKG and remove any existing FID field if not compatible,
426 // let this be completely recreated since many layer sources have fid fields which are
427 // not compatible with gpkg requirements
428 const QgsFields fields = layer->fields();
429 const int fidIndex = fields.lookupField( QStringLiteral( "fid" ) );
430
431 options.attributes = fields.allAttributesList();
432 if ( fidIndex >= 0 )
433 {
434 const QVariant::Type fidType { layer->fields().field( fidIndex ).type() };
435 if ( ! layer->fieldConstraints( fidIndex ).testFlag( QgsFieldConstraints::Constraint::ConstraintUnique )
436 && ! layer->fieldConstraints( fidIndex ).testFlag( QgsFieldConstraints::Constraint::ConstraintNotNull )
437 && fidType != QVariant::Int
438 && fidType != QVariant::UInt
439 && fidType != QVariant::LongLong
440 && fidType != QVariant::ULongLong )
441 {
442 options.attributes.removeAll( fidIndex );
443 }
444 }
445
446 if ( options.attributes.isEmpty() )
447 {
448 // fid was the only field
449 options.skipAttributeCreation = true;
450 }
451
452 QString error;
453 QString newFilename;
454 QString newLayer;
455 if ( QgsVectorFileWriter::writeAsVectorFormatV3( layer, path, context.transformContext(), options, &error, &newFilename, &newLayer ) != QgsVectorFileWriter::NoError )
456 {
457 feedback->reportError( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
458 return false;
459 }
460 else
461 {
462 if ( saveStyles )
463 {
464 std::unique_ptr< QgsVectorLayer > res = std::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=%2" ).arg( newFilename, newLayer ) );
465 if ( res )
466 {
467 QString errorMsg;
468 QDomDocument doc( QStringLiteral( "qgis" ) );
469 const QgsReadWriteContext context;
470 layer->exportNamedStyle( doc, errorMsg, context );
471 if ( !errorMsg.isEmpty() )
472 {
473 feedback->reportError( QObject::tr( "Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
474 }
475 else
476 {
477 if ( !res->importNamedStyle( doc, errorMsg ) )
478 {
479 feedback->reportError( QObject::tr( "Could not set existing layer style: %1 " ).arg( errorMsg ) );
480 }
481 else
482 {
483 QgsSettings settings;
484 // this is not nice -- but needed to avoid an "overwrite" prompt messagebox from the provider! This api needs a rework to avoid this.
485 const QVariant prevOverwriteStyle = settings.value( QStringLiteral( "qgis/overwriteStyle" ) );
486 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), true );
487 res->saveStyleToDatabase( newLayer, QString(), true, QString(), errorMsg );
488 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), prevOverwriteStyle );
489 if ( !errorMsg.isEmpty() )
490 {
491 feedback->reportError( QObject::tr( "Could not save layer style: %1 " ).arg( errorMsg ) );
492 }
493 }
494 }
495 }
496 else
497 {
498 feedback->reportError( QObject::tr( "Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
499 }
500 }
501 return true;
502 }
503}
504
@ 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:56
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:219
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
QVariant::Type type
Definition: qgsfield.h:58
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:376
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
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:78
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.
Definition: qgsexception.h:83
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.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:104
The class is used as a container of context for various read/write operations on other objects.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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.
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Definition: qgsogrutils.h:120
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37