29QString QgsPackageAlgorithm::name()
const
31 return QStringLiteral(
"package" );
34QString QgsPackageAlgorithm::displayName()
const
36 return QObject::tr(
"Package layers" );
39QStringList QgsPackageAlgorithm::tags()
const
41 return QObject::tr(
"geopackage,collect,merge,combine,styles" ).split(
',' );
44QString QgsPackageAlgorithm::group()
const
46 return QObject::tr(
"Database" );
49QString QgsPackageAlgorithm::groupId()
const
51 return QStringLiteral(
"database" );
54void QgsPackageAlgorithm::initAlgorithm(
const QVariantMap & )
58 outputParameter->
setMetadata( QVariantMap( { { QStringLiteral(
"widget_wrapper" ), QVariantMap( { { QStringLiteral(
"dontconfirmoverwrite" ),
true } } ) } } ) );
59 addParameter( outputParameter );
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() );
69 auto crsParam = std::make_unique< QgsProcessingParameterCrs >( QStringLiteral(
"CRS" ), QObject::tr(
"Destination CRS" ), QVariant(),
true );
71 crsParam->setHelp( QObject::tr(
"If set, all layers will be transformed to the destination CRS during packaging." ) );
72 addParameter( std::move( crsParam ) );
77QString QgsPackageAlgorithm::shortHelpString()
const
79 return QObject::tr(
"This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
82QString QgsPackageAlgorithm::shortDescription()
const
84 return QObject::tr(
"Packages a number of existing layers together into a single GeoPackage database." );
87QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance()
const
89 return new QgsPackageAlgorithm();
94 const QList<QgsMapLayer *> layers = parameterAsLayerList( parameters, QStringLiteral(
"LAYERS" ), context );
96 for (
const QgsMapLayer *layer : std::as_const( layers ) )
99 mClonedLayerIds.insert( clonedLayer->
id(), layer->id() );
100 mLayers.emplace_back( clonedLayer );
103 if ( mLayers.empty() )
105 feedback->
reportError( QObject::tr(
"No layers selected, geopackage will be empty" ),
false );
108 mDestinationCrs = parameterAsCrs( parameters, QStringLiteral(
"CRS" ), context );
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 );
123 if ( packagePath.isEmpty() )
127 if ( overwrite && QFile::exists( packagePath ) )
129 feedback->
pushInfo( QObject::tr(
"Removing existing file '%1'" ).arg( packagePath ) );
130 if ( !QFile( packagePath ).remove() )
136 OGRSFDriverH hGpkgDriver = OGRGetDriverByName(
"GPKG" );
144 if ( exportRelatedLayers )
150 const int maxRecursion { 10 };
151 int recursionGuard { 0 };
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 );
158 for (
const QgsRelation &relation : std::as_const( relations ) )
164 bool alreadyAdded {
false };
165 for (
const auto &layerToExport : std::as_const( mLayers ) )
167 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
168 if ( originalId == referencedLayer->
id() )
170 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
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() );
186 if ( onlySaveSelected )
188 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencedLayer ) ) || referencedLayer->
selectedFeatureCount() > 0 )
190 Q_ASSERT( relatedLayer );
196 QgsFeature referencedFeature { relation.getReferencedFeature( selectedFeature ) };
197 if ( referencedFeature.
isValid() )
199 selected.insert( referencedFeature.
id() );
207 if ( recursionGuard > maxRecursion )
209 feedback->pushWarning( QObject::tr(
"Max recursion (%1) adding referenced layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencedLayer->
name() ) );
214 findReferenced( relatedLayer, onlySaveSelected, findReferenced );
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 );
224 for (
const QgsRelation &relation : std::as_const( relations ) )
228 const bool layerWasExplicitlyAdded { layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) };
231 bool alreadyAdded {
false };
232 for (
const auto &layerToExport : std::as_const( mLayers ) )
234 const QString originalId { mClonedLayerIds.value( layerToExport->id() ) };
235 if ( originalId == referencingLayer->
id() )
237 relatedLayer = qobject_cast<QgsVectorLayer *>( layerToExport.get() );
247 if ( onlySaveSelected && ( !layerWasExplicitlyAdded || referencingLayer->
selectedFeatureCount() > 0 ) )
249 if ( !layers.contains( qobject_cast<QgsMapLayer *>( referencingLayer ) ) || referencingLayer->
selectedFeatureCount() > 0 )
255 QgsFeatureIterator referencingFeaturesIterator { relation.getRelatedFeatures( selectedFeature ) };
257 while ( referencingFeaturesIterator.
nextFeature( referencingFeature ) )
259 if ( referencingFeature.
isValid() )
261 selected.insert( referencingFeature.
id() );
268 if ( !alreadyAdded && ( !onlySaveSelected || !selected.isEmpty() ) )
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() );
276 if ( relatedLayer && !selected.isEmpty() )
282 if ( recursionGuard > maxRecursion )
284 feedback->pushWarning( QObject::tr(
"Max recursion (%1) adding referencing layer '%2', layer was not added" ).arg( QLocale().toString( recursionGuard ), referencingLayer->
name() ) );
286 else if ( relatedLayer )
289 findReferencing( relatedLayer, onlySaveSelected, findReferencing );
294 for (
const QgsMapLayer *layer : std::as_const( layers ) )
296 const QgsVectorLayer *vLayer { qobject_cast<const QgsVectorLayer *>( layer ) };
301 findReferenced( vLayer, onlySaveSelected, findReferenced );
303 findReferencing( vLayer, onlySaveSelected, findReferencing );
311 if ( !QFile::exists( packagePath ) )
315 throw QgsProcessingException( QObject::tr(
"Creation of database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
321 throw QgsProcessingException( QObject::tr(
"Opening database %1 failed (OGR error: %2)" ).arg( packagePath, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
324 const bool validExtent = parameters.value( QStringLiteral(
"EXTENT" ) ).isValid();
326 bool errored =
false;
330 QStringList outputLayers;
333 for (
const auto &layer : mLayers )
335 if ( feedback->isCanceled() )
338 multiStepFeedback.setCurrentStep( i );
344 feedback->pushDebugInfo( QObject::tr(
"Error retrieving map layer." ) );
349 feedback->pushInfo( QObject::tr(
"Packaging layer %1/%2: %3" ).arg( i ).arg( mLayers.size() ).arg( layer ? layer->name() : QString() ) );
353 switch ( layer->type() )
357 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer.get() );
363 feedback->pushWarning( QObject::tr(
"No spatial index exists for layer %1, performance will be severely degraded" ).arg( vectorLayer->
name() ) );
366 extent = parameterAsExtent( parameters, QStringLiteral(
"EXTENT" ), context, mDestinationCrs.isValid() ? mDestinationCrs : layer->crs() );
369 if ( !packageVectorLayer( vectorLayer, packagePath, context, &multiStepFeedback, saveStyles, saveMetadata, selectedFeaturesOnly, extent ) )
372 outputLayers.append( QStringLiteral(
"%1|layername=%2" ).arg( packagePath, layer->name() ) );
379 feedback->pushDebugInfo( QObject::tr(
"Packaging raster layers is not supported." ) );
386 feedback->pushDebugInfo( QObject::tr(
"Packaging plugin layers is not supported." ) );
392 feedback->pushDebugInfo( QObject::tr(
"Packaging mesh layers is not supported." ) );
398 feedback->pushDebugInfo( QObject::tr(
"Packaging point cloud layers is not supported." ) );
404 feedback->pushDebugInfo( QObject::tr(
"Packaging vector tile layers is not supported." ) );
410 feedback->pushDebugInfo( QObject::tr(
"Packaging annotation layers is not supported." ) );
416 feedback->pushDebugInfo( QObject::tr(
"Packaging group layers is not supported." ) );
422 feedback->pushDebugInfo( QObject::tr(
"Packaging tiled scene layers is not supported." ) );
432 outputs.insert( QStringLiteral(
"OUTPUT" ), packagePath );
433 outputs.insert( QStringLiteral(
"OUTPUT_LAYERS" ), outputLayers );
440 options.
driverName = QStringLiteral(
"GPKG" );
452 if ( mDestinationCrs.isValid() )
461 const int fidIndex = fields.
lookupField( QStringLiteral(
"fid" ) );
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 )
494 feedback->
reportError( QObject::tr(
"Packaging layer failed: %1" ).arg( error ) );
501 auto res = std::make_unique<QgsVectorLayer>( QStringLiteral(
"%1|layername=%2" ).arg( newFilename, newLayer ) );
502 if ( res->isValid() )
505 QDomDocument doc( QStringLiteral(
"qgis" ) );
508 if ( !errorMsg.isEmpty() )
510 feedback->
reportError( QObject::tr(
"Could not retrieve existing layer style: %1 " ).arg( errorMsg ) );
514 if ( !res->importNamedStyle( doc, errorMsg ) )
516 feedback->
reportError( QObject::tr(
"Could not set existing layer style: %1 " ).arg( errorMsg ) );
522 const QVariant prevOverwriteStyle = settings.
value( QStringLiteral(
"qgis/overwriteStyle" ) );
523 settings.
setValue( QStringLiteral(
"qgis/overwriteStyle" ),
true );
525 settings.
setValue( QStringLiteral(
"qgis/overwriteStyle" ), prevOverwriteStyle );
529 feedback->
reportError( QObject::tr(
"Could not save layer style: %1 " ).arg( errorMsg ) );
536 feedback->
reportError( QObject::tr(
"Could not save layer style -- error loading: %1 %2" ).arg( newFilename, newLayer ) );
@ 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.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
@ AddToSelection
Add selection to current selection.
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...
bool isValid() const
Returns the validity of this feature.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
Container of fields for a vector layer.
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.
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
QgsLayerMetadata metadata
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,...
QgsRelationManager * relationManager
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.
Stores settings for use within QGIS.
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().
QString fileEncoding
Encoding to use.
QString driverName
OGR driver to use.
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