QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
20#include "qgsogrutils.h"
21#include "qgssettings.h"
22#include "qgsvectorfilewriter.h"
23#include "qgsvectorlayer.h"
24
25#include <QLocale>
26
28
29QString QgsPackageAlgorithm::name() const
30{
31 return QStringLiteral( "package" );
32}
33
34QString QgsPackageAlgorithm::displayName() const
35{
36 return QObject::tr( "Package layers" );
37}
38
39QStringList QgsPackageAlgorithm::tags() const
40{
41 return QObject::tr( "geopackage,collect,merge,combine,styles" ).split( ',' );
42}
43
44QString QgsPackageAlgorithm::group() const
45{
46 return QObject::tr( "Database" );
47}
48
49QString QgsPackageAlgorithm::groupId() const
50{
51 return QStringLiteral( "database" );
52}
53
54void QgsPackageAlgorithm::initAlgorithm( const QVariantMap & )
55{
56 addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), Qgis::ProcessingSourceType::Vector ) );
57 QgsProcessingParameterFileDestination *outputParameter = new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QObject::tr( "GeoPackage files (*.gpkg)" ) );
58 outputParameter->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "dontconfirmoverwrite" ), true } } ) } } ) );
59 addParameter( outputParameter );
60 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite existing GeoPackage" ), false ) );
61 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_STYLES" ), QObject::tr( "Save layer styles into GeoPackage" ), true ) );
62 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SAVE_METADATA" ), QObject::tr( "Save layer metadata into GeoPackage" ), true ) );
63 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SELECTED_FEATURES_ONLY" ), QObject::tr( "Save only selected features" ), false ) );
64 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "EXPORT_RELATED_LAYERS" ), QObject::tr( "Export related layers following relations defined in the project" ), false ) );
65 auto extentParam = std::make_unique<QgsProcessingParameterExtent>( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ), QVariant(), true );
66 extentParam->setHelp( QObject::tr( "Limit exported features to those with geometries intersecting the provided extent" ) );
67 addParameter( extentParam.release() );
68
69 auto crsParam = std::make_unique< QgsProcessingParameterCrs >( QStringLiteral( "CRS" ), QObject::tr( "Destination CRS" ), QVariant(), true );
70 crsParam->setFlags( crsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
71 crsParam->setHelp( QObject::tr( "If set, all layers will be transformed to the destination CRS during packaging." ) );
72 addParameter( std::move( crsParam ) );
73
74 addOutput( new QgsProcessingOutputMultipleLayers( QStringLiteral( "OUTPUT_LAYERS" ), QObject::tr( "Layers within new package" ) ) );
75}
76
77QString QgsPackageAlgorithm::shortHelpString() const
78{
79 return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
80}
81
82QString QgsPackageAlgorithm::shortDescription() const
83{
84 return QObject::tr( "Packages a number of existing layers together into a single GeoPackage database." );
85}
86
87QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
88{
89 return new QgsPackageAlgorithm();
90}
91
92bool QgsPackageAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
93{
94 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
95
96 for ( const QgsMapLayer *layer : std::as_const( layers ) )
97 {
98 QgsMapLayer *clonedLayer { layer->clone() };
99 mClonedLayerIds.insert( clonedLayer->id(), layer->id() );
100 mLayers.emplace_back( clonedLayer );
101 }
102
103 if ( mLayers.empty() )
104 {
105 feedback->reportError( QObject::tr( "No layers selected, geopackage will be empty" ), false );
106 }
107
108 mDestinationCrs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
109
110 return true;
111}
112
113QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
114{
115 const bool overwrite = parameterAsBoolean( parameters, QStringLiteral( "OVERWRITE" ), context );
116 const bool saveStyles = parameterAsBoolean( parameters, QStringLiteral( "SAVE_STYLES" ), context );
117 const bool saveMetadata = parameterAsBoolean( parameters, QStringLiteral( "SAVE_METADATA" ), context );
118 const bool selectedFeaturesOnly = parameterAsBoolean( parameters, QStringLiteral( "SELECTED_FEATURES_ONLY" ), context );
119 const bool exportRelatedLayers = parameterAsBoolean( parameters, QStringLiteral( "EXPORT_RELATED_LAYERS" ), context );
120 const QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
121 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
122
123 if ( packagePath.isEmpty() )
124 throw QgsProcessingException( QObject::tr( "No output file specified." ) );
125
126 // delete existing geopackage if it exists
127 if ( overwrite && QFile::exists( packagePath ) )
128 {
129 feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
130 if ( !QFile( packagePath ).remove() )
131 {
132 throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ).arg( packagePath ) );
133 }
134 }
135
136 OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
137 if ( !hGpkgDriver )
138 {
139 throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
140 }
141
142
143 // Collect related layers from project relations
144 if ( exportRelatedLayers )
145 {
146 const QgsProject *project { context.project() };
147 if ( project && !project->relationManager()->relations().isEmpty() )
148 {
149 // Infinite recursion should not happen in the real world but better safe than sorry
150 const int maxRecursion { 10 };
151 int recursionGuard { 0 };
152
153 // This function recursively finds referenced layers
154 const auto findReferenced = [this, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferenced ) -> void {
155 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
156 Q_ASSERT( originalLayer );
157 const QList<QgsRelation> relations { project->relationManager()->referencingRelations( originalLayer ) };
158 for ( const QgsRelation &relation : std::as_const( relations ) )
159 {
160 QgsVectorLayer *referencedLayer { relation.referencedLayer() };
161 QgsVectorLayer *relatedLayer { nullptr };
162
163 // Check if the layer was already in the export list
164 bool alreadyAdded { false };
165 for ( const auto &layerToExport : std::as_const( mLayers ) )
166 {
167 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
168 if ( originalId == referencedLayer->id() )
169 {
170 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
171 alreadyAdded = true;
172 break;
173 }
174 }
175
176 if ( !alreadyAdded )
177 {
178 feedback->pushInfo( QObject::tr( "Adding referenced layer '%1'" ).arg( referencedLayer->name() ) );
179 relatedLayer = referencedLayer->clone();
180 mLayers.emplace_back( relatedLayer );
181 mClonedLayerIds.insert( relatedLayer->id(), referencedLayer->id() );
182 }
183
184 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
185 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
186 if ( onlySaveSelected )
187 {
188 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->selectedFeatureCount() > 0 )
189 {
190 Q_ASSERT( relatedLayer );
191 QgsFeatureIds selected;
192 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
193 QgsFeature selectedFeature;
194 while ( it.nextFeature( selectedFeature ) )
195 {
196 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
197 if ( referencedFeature.isValid() )
198 {
199 selected.insert( referencedFeature.id() );
200 }
201 }
202 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
203 }
204 }
205
206 // Recursive finding
207 if ( recursionGuard > maxRecursion )
208 {
209 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->name() ) );
210 }
211 else
212 {
213 recursionGuard++;
214 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
215 }
216 }
217 };
218
219 // This function recursively finds referencing layers
220 const auto findReferencing = [this, &project, &feedback, &recursionGuard, &layers]( const QgsVectorLayer *vLayer, bool onlySaveSelected, auto &&findReferencing ) -> void {
221 const QgsVectorLayer *originalLayer { qobject_cast<QgsVectorLayer *>( project->mapLayer( mClonedLayerIds.value( vLayer->id(), vLayer->id() ) ) ) };
222 Q_ASSERT( originalLayer );
223 const QList<QgsRelation> relations { project->relationManager()->referencedRelations( originalLayer ) };
224 for ( const QgsRelation &relation : std::as_const( relations ) )
225 {
226 QgsVectorLayer *referencingLayer { relation.referencingLayer() };
227 QgsVectorLayer *relatedLayer { nullptr };
228 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
229
230 // Check if the layer was already in the export list
231 bool alreadyAdded { false };
232 for ( const auto &layerToExport : std::as_const( mLayers ) )
233 {
234 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
235 if ( originalId == referencingLayer->id() )
236 {
237 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
238 alreadyAdded = true;
239 break;
240 }
241 }
242
243 // Export only relevant features unless the layer was in the original export list and no selection was made on that layer
244 // in that case the user explicitly marked the layer for export and it is supposed to be exported fully.
245 QgsFeatureIds selected;
246
247 if ( onlySaveSelected && ( !layerWasExplicitlyAdded || referencingLayer->selectedFeatureCount() > 0 ) )
248 {
249 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->selectedFeatureCount() > 0 )
250 {
251 QgsFeatureIterator it { vLayer->getSelectedFeatures() };
252 QgsFeature selectedFeature;
253 while ( it.nextFeature( selectedFeature ) )
254 {
255 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
256 QgsFeature referencingFeature;
257 while ( referencingFeaturesIterator.nextFeature( referencingFeature ) )
258 {
259 if ( referencingFeature.isValid() )
260 {
261 selected.insert( referencingFeature.id() );
262 }
263 }
264 }
265 }
266 }
267
268 if ( !alreadyAdded && ( !onlySaveSelected || !selected.isEmpty() ) )
269 {
270 feedback->pushInfo( QObject::tr( "Adding referencing layer '%1'" ).arg( referencingLayer->name() ) );
271 relatedLayer = referencingLayer->clone();
272 mLayers.emplace_back( relatedLayer );
273 mClonedLayerIds.insert( relatedLayer->id(), referencingLayer->id() );
274 }
275
276 if ( relatedLayer && !selected.isEmpty() )
277 {
278 relatedLayer->selectByIds( selected, Qgis::SelectBehavior::AddToSelection );
279 }
280
281 // Recursive finding
282 if ( recursionGuard > maxRecursion )
283 {
284 feedback->pushWarning( QObject::tr( "Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->name() ) );
285 }
286 else if ( relatedLayer )
287 {
288 recursionGuard++;
289 findReferencing( relatedLayer, onlySaveSelected, findReferencing );
290 }
291 }
292 };
293
294 for ( const QgsMapLayer *layer : std::as_const( layers ) )
295 {
296 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
297 if ( vLayer )
298 {
299 const bool onlySaveSelected = vLayer->selectedFeatureCount() > 0 && selectedFeaturesOnly;
300 recursionGuard = 0;
301 findReferenced( vLayer, onlySaveSelected, findReferenced );
302 recursionGuard = 0;
303 findReferencing( vLayer, onlySaveSelected, findReferencing );
304 }
305 }
306 }
307 }
308
310
311 if ( !QFile::exists( packagePath ) )
312 {
313 hDS = gdal::ogr_datasource_unique_ptr( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
314 if ( !hDS )
315 throw QgsProcessingException( QObject::tr( "Creation of database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
316 }
317 else
318 {
319 hDS = gdal::ogr_datasource_unique_ptr( OGROpen( packagePath.toUtf8().constData(), true, nullptr ) );
320 if ( !hDS )
321 throw QgsProcessingException( QObject::tr( "Opening database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
322 }
323
324 const bool validExtent = parameters.value( QStringLiteral( "EXTENT" ) ).isValid();
325
326 bool errored = false;
327
328 QgsProcessingMultiStepFeedback multiStepFeedback( mLayers.size(), feedback );
329
330 QStringList outputLayers;
331
332 int i = 0;
333 for ( const auto &layer : mLayers )
334 {
335 if ( feedback->isCanceled() )
336 break;
337
338 multiStepFeedback.setCurrentStep( i );
339 i++;
340
341 if ( !layer )
342 {
343 // don't throw immediately - instead do what we can and error out later
344 feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
345 errored = true;
346 continue;
347 }
348
349 feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
350
351 QgsRectangle extent;
352
353 switch ( layer->type() )
354 {
356 {
357 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
358
359 if ( validExtent )
360 {
362 {
363 feedback->pushWarning( QObject::tr( "No spatial index exists for layer %1, performance will be severely degraded" ).arg( vectorLayer->name() ) );
364 }
365
366 extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, mDestinationCrs.isValid() ? mDestinationCrs : layer->crs() );
367 }
368
369 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, selectedFeaturesOnly, extent ) )
370 errored = true;
371 else
372 outputLayers.append( QStringLiteral( "%1|layername=%2" ).arg( packagePath, layer->name() ) );
373 break;
374 }
375
377 {
378 //not supported
379 feedback->pushDebugInfo( QObject::tr( "Packaging raster layers is not supported." ) );
380 errored = true;
381 break;
382 }
383
385 //not supported
386 feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
387 errored = true;
388 break;
389
391 //not supported
392 feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
393 errored = true;
394 break;
395
397 //not supported
398 feedback->pushDebugInfo( QObject::tr( "Packaging point cloud layers is not supported." ) );
399 errored = true;
400 break;
401
403 //not supported
404 feedback->pushDebugInfo( QObject::tr( "Packaging vector tile layers is not supported." ) );
405 errored = true;
406 break;
407
409 //not supported
410 feedback->pushDebugInfo( QObject::tr( "Packaging annotation layers is not supported." ) );
411 errored = true;
412 break;
413
415 //not supported
416 feedback->pushDebugInfo( QObject::tr( "Packaging group layers is not supported." ) );
417 errored = true;
418 break;
419
421 //not supported
422 feedback->pushDebugInfo( QObject::tr( "Packaging tiled scene layers is not supported." ) );
423 errored = true;
424 break;
425 }
426 }
427
428 if ( errored )
429 throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
430
431 QVariantMap outputs;
432 outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
433 outputs.insert( QStringLiteral( "OUTPUT_LAYERS" ), outputLayers );
434 return outputs;
435}
436
437bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback, bool saveStyles, bool saveMetadata, bool selectedFeaturesOnly, const QgsRectangle &extent )
438{
440 options.driverName = QStringLiteral( "GPKG" );
441 options.layerName = layer->name();
443 options.fileEncoding = context.defaultEncoding();
444 options.onlySelectedFeatures = selectedFeaturesOnly;
445 options.feedback = feedback;
446 if ( saveMetadata )
447 {
448 options.layerMetadata = layer->metadata();
449 options.saveMetadata = true;
450 }
451
452 if ( mDestinationCrs.isValid() )
453 {
454 options.ct = QgsCoordinateTransform( layer->crs(), mDestinationCrs, context.transformContext() );
455 }
456
457 // Check FID compatibility with GPKG and remove any existing FID field if not compatible,
458 // let this be completely recreated since many layer sources have fid fields which are
459 // not compatible with gpkg requirements
460 const QgsFields fields = layer->fields();
461 const int fidIndex = fields.lookupField( QStringLiteral( "fid" ) );
462
463 options.attributes = fields.allAttributesList();
464 if ( fidIndex >= 0 )
465 {
466 const QMetaType::Type fidType { layer->fields().field( fidIndex ).type() };
469 && fidType != QMetaType::Type::Int
470 && fidType != QMetaType::Type::UInt
471 && fidType != QMetaType::Type::LongLong
472 && fidType != QMetaType::Type::ULongLong )
473 {
474 options.attributes.removeAll( fidIndex );
475 }
476 }
477
478 if ( options.attributes.isEmpty() )
479 {
480 // fid was the only field
481 options.skipAttributeCreation = true;
482 }
483
484 if ( !extent.isNull() )
485 {
486 options.filterExtent = extent;
487 }
488
489 QString error;
490 QString newFilename;
491 QString newLayer;
492 if ( QgsVectorFileWriter::writeAsVectorFormatV3( layer, path, context.transformContext(), options, &error, &newFilename, &newLayer ) != QgsVectorFileWriter::NoError )
493 {
494 feedback->reportError( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
495 return false;
496 }
497 else
498 {
499 if ( saveStyles )
500 {
501 auto res = std::make_unique<QgsVectorLayer>( QStringLiteral( "%1|layername=%2" ).arg( newFilename, newLayer ) );
502 if ( res->isValid() )
503 {
504 QString errorMsg;
505 QDomDocument doc( QStringLiteral( "qgis" ) );
506 const QgsReadWriteContext context;
507 layer->exportNamedStyle( doc, errorMsg, context );
508 if ( !errorMsg.isEmpty() )
509 {
510 feedback->reportError( QObject::tr( "Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
511 }
512 else
513 {
514 if ( !res->importNamedStyle( doc, errorMsg ) )
515 {
516 feedback->reportError( QObject::tr( "Could not set existing layer style: %1 " ).arg( errorMsg ) );
517 }
518 else
519 {
520 QgsSettings settings;
521 // this is not nice -- but needed to avoid an "overwrite" prompt messagebox from the provider! This api needs a rework to avoid this.
522 const QVariant prevOverwriteStyle = settings.value( QStringLiteral( "qgis/overwriteStyle" ) );
523 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), true );
524 QgsMapLayer::SaveStyleResults saveStyleResults = res->saveStyleToDatabaseV2( newLayer, QString(), true, QString(), errorMsg );
525 settings.setValue( QStringLiteral( "qgis/overwriteStyle" ), prevOverwriteStyle );
526 if ( saveStyleResults.testFlag( QgsMapLayer::SaveStyleResult::QmlGenerationFailed )
527 || saveStyleResults.testFlag( QgsMapLayer::SaveStyleResult::DatabaseWriteFailed ) )
528 {
529 feedback->reportError( QObject::tr( "Could not save layer style: %1 " ).arg( errorMsg ) );
530 }
531 }
532 }
533 }
534 else
535 {
536 feedback->reportError( QObject::tr( "Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
537 }
538 }
539 return true;
540 }
541}
542
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3539
@ NotPresent
No spatial index exists for the source.
Definition qgis.h:560
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:198
@ Plugin
Plugin based layer.
Definition qgis.h:193
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:199
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:196
@ Vector
Vector layer.
Definition qgis.h:191
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:195
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:194
@ Raster
Raster layer.
Definition qgis.h:192
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:197
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3763
@ AddToSelection
Add selection to current selection.
Definition qgis.h:1773
Handles coordinate transforms between two coordinate systems.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
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:61
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:80
QString name
Definition qgsmaplayer.h:84
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.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:83
QgsLayerMetadata metadata
Definition qgsmaplayer.h:86
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:109
QgsRelationManager * relationManager
Definition qgsproject.h:120
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i....
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
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().
QgsCoordinateTransform ct
Transform to reproject exported geometries with, or invalid transform for no transformation.
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.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using a list of feature IDs.
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