QGIS API Documentation 3.99.0-Master (e59a7c0ab9f)
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 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ), QVariant(), true );
65 extentParam->setHelp( QObject::tr( "Limit exported features to those with geometries intersecting the provided extent" ) );
66 addParameter( extentParam.release() );
67 addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Layers within new package" ) ) );
68}
69
70QString QgsPackageAlgorithm::shortHelpString() const
71{
72 return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
73}
74
75QString QgsPackageAlgorithm::shortDescription() const
76{
77 return QObject::tr( "Packages a number of existing layers together into a single GeoPackage database." );
78}
79
80QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
81{
82 return new QgsPackageAlgorithm();
83}
84
85bool QgsPackageAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
86{
87 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
88
89 for ( const QgsMapLayer *layer : std::as_const( layers ) )
90 {
91 QgsMapLayer *clonedLayer { layer->clone() };
92 mClonedLayerIds.insert( clonedLayer->id(), layer->id() );
93 mLayers.emplace_back( clonedLayer );
94 }
95
96 if ( mLayers.empty() )
97 {
98 feedback->reportError( QObject::tr( "No layers selected, geopackage will be empty" ), false );
99 }
100
101 return true;
102}
103
104QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
105{
106 const bool overwrite = parameterAsBoolean( parameters, QStringLiteral( "OVERWRITE" ), context );
107 const bool saveStyles = parameterAsBoolean( parameters, QStringLiteral( "SAVE_STYLES" ), context );
108 const bool saveMetadata = parameterAsBoolean( parameters, QStringLiteral( "SAVE_METADATA" ), context );
109 const bool selectedFeaturesOnly = parameterAsBoolean( parameters, QStringLiteral( "SELECTED_FEATURES_ONLY" ), context );
110 const bool exportRelatedLayers = parameterAsBoolean( parameters, QStringLiteral( "EXPORT_RELATED_LAYERS" ), context );
111 const QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
112 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
113
114 if ( packagePath.isEmpty() )
115 throw QgsProcessingException( QObject::tr( "No output file specified." ) );
116
117 // delete existing geopackage if it exists
118 if ( overwrite && QFile::exists( packagePath ) )
119 {
120 feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
121 if ( !QFile( packagePath ).remove() )
122 {
123 throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ).arg( packagePath ) );
124 }
125 }
126
127 OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
128 if ( !hGpkgDriver )
129 {
130 throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
131 }
132
133
134 // Collect related layers from project relations
135 if ( exportRelatedLayers )
136 {
137 const QgsProject *project { context.project() };
138 if ( project && !project->relationManager()->relations().isEmpty() )
139 {
140 // Infinite recursion should not happen in the real world but better safe than sorry
141 const int maxRecursion { 10 };
142 int recursionGuard { 0 };
143
144 // This function recursively finds referenced layers
145 const auto findReferenced = [this, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferenced ) -> void {
146 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
147 Q_ASSERT( originalLayer );
148 const QList<QgsRelation> relations { project->relationManager()->referencingRelations( originalLayer ) };
149 for ( const QgsRelation &relation : std::as_const( relations ) )
150 {
151 QgsVectorLayer *referencedLayer { relation.referencedLayer() };
152 QgsVectorLayer *relatedLayer { nullptr };
153
154 // Check if the layer was already in the export list
155 bool alreadyAdded { false };
156 for ( const auto &layerToExport : std::as_const( mLayers ) )
157 {
158 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
159 if ( originalId == referencedLayer->id() )
160 {
161 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
162 alreadyAdded = true;
163 break;
164 }
165 }
166
167 if ( !alreadyAdded )
168 {
169 feedback->pushInfo( QObject::tr( "Adding referenced layer '%1'" ).arg( referencedLayer->name() ) );
170 relatedLayer = referencedLayer->clone();
171 mLayers.emplace_back( relatedLayer );
172 mClonedLayerIds.insert( relatedLayer->id(), referencedLayer->id() );
173 }
174
175 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
176 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
177 if ( onlySaveSelected )
178 {
179 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->selectedFeatureCount() > 0 )
180 {
181 Q_ASSERT( relatedLayer );
182 QgsFeatureIds selected;
183 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
184 QgsFeature selectedFeature;
185 while ( it.nextFeature( selectedFeature ) )
186 {
187 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
188 if ( referencedFeature.isValid() )
189 {
190 selected.insert( referencedFeature.id() );
191 }
192 }
193 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
194 }
195 }
196
197 // Recursive finding
198 if ( recursionGuard > maxRecursion )
199 {
200 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->name() ) );
201 }
202 else
203 {
204 recursionGuard++;
205 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
206 }
207 }
208 };
209
210 // This function recursively finds referencing layers
211 const auto findReferencing = [this, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferencing ) -> void {
212 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
213 Q_ASSERT( originalLayer );
214 const QList<QgsRelation> relations { project->relationManager()->referencedRelations( originalLayer ) };
215 for ( const QgsRelation &relation : std::as_const( relations ) )
216 {
217 QgsVectorLayer *referencingLayer { relation.referencingLayer() };
218 QgsVectorLayer *relatedLayer { nullptr };
219 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
220
221 // Check if the layer was already in the export list
222 bool alreadyAdded { false };
223 for ( const auto &layerToExport : std::as_const( mLayers ) )
224 {
225 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
226 if ( originalId == referencingLayer->id() )
227 {
228 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
229 alreadyAdded = true;
230 break;
231 }
232 }
233
234 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
235 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
236 QgsFeatureIds selected;
237
238 if ( onlySaveSelected && ( !layerWasExplicitlyAdded || referencingLayer->selectedFeatureCount() > 0 ) )
239 {
240 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->selectedFeatureCount() > 0 )
241 {
242 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
243 QgsFeature selectedFeature;
244 while ( it.nextFeature( selectedFeature ) )
245 {
246 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
247 QgsFeature referencingFeature;
248 while ( referencingFeaturesIterator.nextFeature( referencingFeature ) )
249 {
250 if ( referencingFeature.isValid() )
251 {
252 selected.insert( referencingFeature.id() );
253 }
254 }
255 }
256 }
257 }
258
259 if ( !alreadyAdded && ( !onlySaveSelected || !selected.isEmpty() ) )
260 {
261 feedback->pushInfo( QObject::tr( "Adding referencing layer '%1'" ).arg( referencingLayer->name() ) );
262 relatedLayer = referencingLayer->clone();
263 mLayers.emplace_back( relatedLayer );
264 mClonedLayerIds.insert( relatedLayer->id(), referencingLayer->id() );
265 }
266
267 if ( relatedLayer && !selected.isEmpty() )
268 {
269 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
270 }
271
272 // Recursive finding
273 if ( recursionGuard > maxRecursion )
274 {
275 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->name() ) );
276 }
277 else if ( relatedLayer )
278 {
279 recursionGuard++;
280 findReferencing( relatedLayer, onlySaveSelected, findReferencing );
281 }
282 }
283 };
284
285 for ( const QgsMapLayer *layer : std::as_const( layers ) )
286 {
287 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
288 if ( vLayer )
289 {
290 const bool onlySaveSelected = vLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
291 recursionGuard = 0;
292 findReferenced( vLayer, onlySaveSelected, findReferenced );
293 recursionGuard = 0;
294 findReferencing( vLayer, onlySaveSelected, findReferencing );
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 const bool validExtent = parameters.value( QStringLiteral( "EXTENT" ) ).isValid();
316
317 bool errored = false;
318
319 QgsProcessingMultiStepFeedback multiStepFeedback( mLayers.size(), feedback );
320
321 QStringList outputLayers;
322
323 int i = 0;
324 for ( const auto &layer : mLayers )
325 {
326 if ( feedback->isCanceled() )
327 break;
328
329 multiStepFeedback.setCurrentStep( i );
330 i++;
331
332 if ( !layer )
333 {
334 // don't throw immediately - instead do what we can and error out later
335 feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
336 errored = true;
337 continue;
338 }
339
340 feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
341
342 QgsRectangle extent;
343
344 switch ( layer->type() )
345 {
347 {
348 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
349
350 if ( validExtent )
351 {
353 {
354 feedback->pushWarning( QObject::tr( "No spatial index exists for layer %1, performance will be severely degraded" ).arg( vectorLayer->name() ) );
355 }
356
357 extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, layer->crs() );
358 }
359
360 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, selectedFeaturesOnly, extent ) )
361 errored = true;
362 else
363 outputLayers.append( QStringLiteral( "%1|layername=%2" ).arg( packagePath, layer->name() ) );
364 break;
365 }
366
368 {
369 //not supported
370 feedback->pushDebugInfo( QObject::tr( "Packaging raster layers is not supported." ) );
371 errored = true;
372 break;
373 }
374
376 //not supported
377 feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
378 errored = true;
379 break;
380
382 //not supported
383 feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
384 errored = true;
385 break;
386
388 //not supported
389 feedback->pushDebugInfo( QObject::tr( "Packaging point cloud layers is not supported." ) );
390 errored = true;
391 break;
392
394 //not supported
395 feedback->pushDebugInfo( QObject::tr( "Packaging vector tile layers is not supported." ) );
396 errored = true;
397 break;
398
400 //not supported
401 feedback->pushDebugInfo( QObject::tr( "Packaging annotation layers is not supported." ) );
402 errored = true;
403 break;
404
406 //not supported
407 feedback->pushDebugInfo( QObject::tr( "Packaging group layers is not supported." ) );
408 errored = true;
409 break;
410
412 //not supported
413 feedback->pushDebugInfo( QObject::tr( "Packaging tiled scene layers is not supported." ) );
414 errored = true;
415 break;
416 }
417 }
418
419 if ( errored )
420 throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
421
422 QVariantMap outputs;
423 outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
424 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
425 return outputs;
426}
427
428bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback, bool saveStyles, bool saveMetadata, bool selectedFeaturesOnly, const QgsRectangle &extent )
429{
431 options.driverName = QStringLiteral( "GPKG" );
432 options.layerName = layer->name();
434 options.fileEncoding = context.defaultEncoding();
435 options.onlySelectedFeatures = selectedFeaturesOnly;
436 options.feedback = feedback;
437 if ( saveMetadata )
438 {
439 options.layerMetadata = layer->metadata();
440 options.saveMetadata = true;
441 }
442
443 // Check FID compatibility with GPKG and remove any existing FID field if not compatible,
444 // let this be completely recreated since many layer sources have fid fields which are
445 // not compatible with gpkg requirements
446 const QgsFields fields = layer->fields();
447 const int fidIndex = fields.lookupField( QStringLiteral( "fid" ) );
448
449 options.attributes = fields.allAttributesList();
450 if ( fidIndex >= 0 )
451 {
452 const QMetaType::Type fidType { layer->fields().field( fidIndex ).type() };
455 && fidType != QMetaType::Type::Int
456 && fidType != QMetaType::Type::UInt
457 && fidType != QMetaType::Type::LongLong
458 && fidType != QMetaType::Type::ULongLong )
459 {
460 options.attributes.removeAll( fidIndex );
461 }
462 }
463
464 if ( options.attributes.isEmpty() )
465 {
466 // fid was the only field
467 options.skipAttributeCreation = true;
468 }
469
470 if ( !extent.isNull() )
471 {
472 options.filterExtent = extent;
473 }
474
475 QString error;
476 QString newFilename;
477 QString newLayer;
478 if ( QgsVectorFileWriter::writeAsVectorFormatV3( layer, path, context.transformContext(), options, &error, &newFilename, &newLayer ) != QgsVectorFileWriter::NoError )
479 {
480 feedback->reportError( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
481 return false;
482 }
483 else
484 {
485 if ( saveStyles )
486 {
487 auto res = std::make_unique<QgsVectorLayer>( QStringLiteral( "%1|layername=%2" ).arg( newFilename, newLayer ) );
488 if ( res )
489 {
490 QString errorMsg;
491 QDomDocument doc( QStringLiteral( "qgis" ) );
492 const QgsReadWriteContext context;
493 layer->exportNamedStyle( doc, errorMsg, context );
494 if ( !errorMsg.isEmpty() )
495 {
496 feedback->reportError( QObject::tr( "Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
497 }
498 else
499 {
500 if ( !res->importNamedStyle( doc, errorMsg ) )
501 {
502 feedback->reportError( QObject::tr( "Could not set existing layer style: %1 " ).arg( errorMsg ) );
503 }
504 else
505 {
506 QgsSettings settings;
507 // this is not nice -- but needed to avoid an "overwrite" prompt messagebox from the provider! This api needs a rework to avoid this.
508 const QVariant prevOverwriteStyle = settings.value( QStringLiteral( "qgis/overwriteStyle" ) );
509 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), true );
510 QgsMapLayer::SaveStyleResults saveStyleResults = res->saveStyleToDatabaseV2( newLayer, QString(), true, QString(), errorMsg );
511 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), prevOverwriteStyle );
512 if ( saveStyleResults.testFlag( QgsMapLayer::SaveStyleResult::QmlGenerationFailed )
513 || saveStyleResults.testFlag( QgsMapLayer::SaveStyleResult::DatabaseWriteFailed ) )
514 {
515 feedback->reportError( QObject::tr( "Could not save layer style: %1 " ).arg( errorMsg ) );
516 }
517 }
518 }
519 }
520 else
521 {
522 feedback->reportError( QObject::tr( "Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
523 }
524 }
525 return true;
526 }
527}
528
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ NotPresent
No spatial index exists for the source.
@ 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:78
QString name
Definition qgsmaplayer.h:82
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.
@ DatabaseWriteFailed
An error occurred when attempting to write to the database.
@ QmlGenerationFailed
Generation of the QML failed, and was not written to the database.
QgsLayerMetadata metadata
Definition qgsmaplayer.h:84
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
QFlags< SaveStyleResult > SaveStyleResults
Results of saving styles to database.
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.
A rectangle specified with double values.
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.
QgsRectangle filterExtent
If not empty, only features intersecting the extent will be saved.
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.
Qgis::SpatialIndexPresence hasSpatialIndex() const override
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
QSet< QgsFeatureId > QgsFeatureIds