QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsprocessingcontext.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingcontext.cpp
3 ----------------------
4 begin : April 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
19#include "qgsprocessingutils.h"
20#include "qgsunittypes.h"
21#include "qgsproviderregistry.h"
22#include "qgsprocessing.h"
23
25 : mPreferredVectorFormat( QgsProcessingUtils::defaultVectorExtension() )
26 , mPreferredRasterFormat( QgsProcessingUtils::defaultRasterExtension() )
27{
28 auto callback = [this]( const QgsFeature & feature )
29 {
30 if ( mFeedback )
31 mFeedback->reportError( QObject::tr( "Encountered a transform error when reprojecting feature with id %1." ).arg( feature.id() ) );
32 };
33 mTransformErrorCallback = callback;
34 mExpressionContext.setLoadedLayerStore( &tempLayerStore );
35}
36
38{
39 for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it )
40 {
41 delete it.value().postProcessor();
42 }
43}
44
46{
47 mExpressionContext = context;
48 // any layers temporarily loaded by expressions should use the same temporary layer store as this context
49 mExpressionContext.setLoadedLayerStore( &tempLayerStore );
50}
51
52void QgsProcessingContext::setLayersToLoadOnCompletion( const QMap<QString, QgsProcessingContext::LayerDetails> &layers )
53{
54 for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it )
55 {
56 if ( !layers.contains( it.key() ) || layers.value( it.key() ).postProcessor() != it.value().postProcessor() )
57 delete it.value().postProcessor();
58 }
59 mLayersToLoadOnCompletion = layers;
60}
61
63{
64 if ( mLayersToLoadOnCompletion.contains( layer ) && mLayersToLoadOnCompletion.value( layer ).postProcessor() != details.postProcessor() )
65 delete mLayersToLoadOnCompletion.value( layer ).postProcessor();
66
67 mLayersToLoadOnCompletion.insert( layer, details );
68}
69
71{
72 mInvalidGeometryCheck = check;
73 mUseDefaultInvalidGeometryCallback = true;
74 mInvalidGeometryCallback = defaultInvalidGeometryCallbackForCheck( check );
75}
76
77std::function<void ( const QgsFeature & )> QgsProcessingContext::invalidGeometryCallback( QgsFeatureSource *source ) const
78{
79 if ( mUseDefaultInvalidGeometryCallback )
80 return defaultInvalidGeometryCallbackForCheck( mInvalidGeometryCheck, source );
81 else
82 return mInvalidGeometryCallback;
83}
84
86{
87 const QString sourceName = source ? source->sourceName() : QString();
88 switch ( check )
89 {
91 {
92 auto callback = [sourceName]( const QgsFeature & feature )
93 {
94 if ( !sourceName.isEmpty() )
95 throw QgsProcessingException( QObject::tr( "Feature (%1) from “%2” has invalid geometry. Please fix the geometry or change the “Invalid features filtering” option for this input or globally in Processing settings." ).arg( feature.id() ).arg( sourceName ) );
96 else
97 throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the “Invalid features filtering” option for input layers or globally in Processing settings." ).arg( feature.id() ) );
98 };
99 return callback;
100 }
101
103 {
104 auto callback = [this, sourceName]( const QgsFeature & feature )
105 {
106 if ( mFeedback )
107 {
108 if ( !sourceName.isEmpty() )
109 mFeedback->reportError( QObject::tr( "Feature (%1) from “%2” has invalid geometry and has been skipped. Please fix the geometry or change the “Invalid features filtering” option for this input or globally in Processing settings." ).arg( feature.id() ).arg( sourceName ) );
110 else
111 mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the “Invalid features filtering” option for input layers or globally in Processing settings." ).arg( feature.id() ) );
112 }
113 };
114 return callback;
115 }
116
118 return nullptr;
119 }
120 return nullptr;
121}
122
124{
125 setLayersToLoadOnCompletion( context.mLayersToLoadOnCompletion );
126 context.mLayersToLoadOnCompletion.clear();
127 tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() );
128}
129
131{
132 return QgsProcessingUtils::mapLayerFromString( identifier, *this, false );
133}
134
136{
137 return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) );
138}
139
141{
142 return mLogLevel;
143}
144
146{
147 mLogLevel = level;
148}
149
151{
152 return mTemporaryFolderOverride;
153}
154
155void QgsProcessingContext::setTemporaryFolder( const QString &folder )
156{
157 mTemporaryFolderOverride = folder;
158}
159
161{
162 return mMaximumThreads;
163}
164
166{
167 mMaximumThreads = threads;
168}
169
171{
172 QVariantMap res;
173 if ( mDistanceUnit != Qgis::DistanceUnit::Unknown )
174 res.insert( QStringLiteral( "distance_units" ), QgsUnitTypes::encodeUnit( mDistanceUnit ) );
175 if ( mAreaUnit != Qgis::AreaUnit::Unknown )
176 res.insert( QStringLiteral( "area_units" ), QgsUnitTypes::encodeUnit( mAreaUnit ) );
177 if ( !mEllipsoid.isEmpty() )
178 res.insert( QStringLiteral( "ellipsoid" ), mEllipsoid );
179 if ( mProject )
180 res.insert( QStringLiteral( "project_path" ), mProject->fileName() );
181
182 return res;
183}
184
186{
187 auto escapeIfNeeded = []( const QString & input ) -> QString
188 {
189 // play it safe and escape everything UNLESS it's purely alphanumeric characters (and a very select scattering of other common characters!)
190 const thread_local QRegularExpression nonAlphaNumericRx( QStringLiteral( "[^a-zA-Z0-9.\\-/_]" ) );
191 if ( nonAlphaNumericRx.match( input ).hasMatch() )
192 {
193 QString escaped = input;
194 escaped.replace( '\'', QLatin1String( "'\\''" ) );
195 return QStringLiteral( "'%1'" ).arg( escaped );
196 }
197 else
198 {
199 return input;
200 }
201 };
202
203 QStringList res;
204 if ( mDistanceUnit != Qgis::DistanceUnit::Unknown )
205 res << QStringLiteral( "--distance_units=%1" ).arg( QgsUnitTypes::encodeUnit( mDistanceUnit ) );
206 if ( mAreaUnit != Qgis::AreaUnit::Unknown )
207 res << QStringLiteral( "--area_units=%1" ).arg( QgsUnitTypes::encodeUnit( mAreaUnit ) );
208 if ( !mEllipsoid.isEmpty() )
209 res << QStringLiteral( "--ellipsoid=%1" ).arg( mEllipsoid );
210
212 {
213 res << QStringLiteral( "--project_path=%1" ).arg( escapeIfNeeded( mProject->fileName() ) );
214 }
215
216 return res;
217}
218
220{
221 return mCurrentTimeRange;
222}
223
225{
226 mCurrentTimeRange = currentTimeRange;
227}
228
230{
231 return mEllipsoid;
232}
233
234void QgsProcessingContext::setEllipsoid( const QString &ellipsoid )
235{
236 mEllipsoid = ellipsoid;
237}
238
240{
241 return mDistanceUnit;
242}
243
245{
246 mDistanceUnit = unit;
247}
248
250{
251 return mAreaUnit;
252}
253
255{
256 mAreaUnit = areaUnit;
257}
258
260{
261 return mPostProcessor;
262}
263
265{
266 if ( mPostProcessor && mPostProcessor != processor )
267 delete mPostProcessor;
268
269 mPostProcessor = processor;
270}
271
273{
274 if ( !layer )
275 return;
276
277 const bool preferFilenameAsLayerName = QgsProcessing::settingsPreferFilenameAsLayerName->value();
278
279 // note - for temporary layers, we don't use the filename, regardless of user setting (it will be meaningless!)
280 if ( ( !forceName && preferFilenameAsLayerName && !layer->isTemporary() ) || name.isEmpty() )
281 {
282 const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
283 const QString layerName = sourceParts.value( QStringLiteral( "layerName" ) ).toString();
284 // if output layer name exists, use that!
285 if ( !layerName.isEmpty() )
286 layer->setName( layerName );
287 else
288 {
289 const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
290 if ( !path.isEmpty() )
291 {
292 const QFileInfo fi( path );
293 layer->setName( fi.baseName() );
294 }
295 else if ( !name.isEmpty() )
296 {
297 // fallback to parameter's name -- shouldn't happen!
298 layer->setName( name );
299 }
300 }
301 }
302 else
303 {
304 layer->setName( name );
305 }
306}
DistanceUnit
Units of distance.
Definition: qgis.h:4124
@ Unknown
Unknown distance unit.
AreaUnit
Units of area.
Definition: qgis.h:4162
@ Unknown
Unknown areal unit.
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
Definition: qgis.h:1778
@ NoCheck
No invalid geometry checking.
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
ProcessingLogLevel
Logging level for algorithms to use when pushing feedback messages.
Definition: qgis.h:2960
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setLoadedLayerStore(QgsMapLayerStore *store)
Sets the destination layer store for any layers loaded during expression evaluation.
An interface for objects which provide features via a getFeatures method.
virtual QString sourceName() const =0
Returns a friendly display name for the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsMapLayer * takeMapLayer(QgsMapLayer *layer)
Takes a layer from the store.
QgsMapLayer * mapLayer(const QString &id) const
Retrieve a pointer to a layer by layer id.
void transferLayersFromStore(QgsMapLayerStore *other)
Transfers all the map layers contained within another map layer store and adds them to this store.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
virtual bool isTemporary() const
Returns true if the layer is considered a temporary layer.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setName(const QString &name)
Set the display name of the layer.
Details for layers to load into projects.
QgsProcessingLayerPostProcessorInterface * postProcessor() const
Layer post-processor.
void setPostProcessor(QgsProcessingLayerPostProcessorInterface *processor)
Sets the layer post-processor.
void setOutputLayerName(QgsMapLayer *layer) const
Sets a layer name to match this output, respecting any local user settings which affect this name.
Contains information about the context in which a processing algorithm is executed.
QgsProcessingContext::Flags flags() const
Returns any flags set in the context.
@ IncludeProjectPath
Include the associated project path argument.
QFlags< ProcessArgumentFlag > ProcessArgumentFlags
QgsDateTimeRange currentTimeRange() const
Returns the current time range to use for temporal operations.
void takeResultsFrom(QgsProcessingContext &context)
Takes the results from another context and merges them with the results currently stored in this cont...
QVariantMap exportToMap() const
Exports the context's settings to a variant map.
Qgis::AreaUnit areaUnit() const
Returns the area unit to use for area calculations.
QStringList asQgisProcessArguments(QgsProcessingContext::ProcessArgumentFlags flags=QgsProcessingContext::ProcessArgumentFlags()) const
Returns list of the equivalent qgis_process arguments representing the settings from the context.
void setLogLevel(Qgis::ProcessingLogLevel level)
Sets the logging level for algorithms to use when pushing feedback messages to users.
QgsMapLayer * getMapLayer(const QString &identifier)
Returns a map layer from the context with a matching identifier.
std::function< void(const QgsFeature &) > invalidGeometryCallback(QgsFeatureSource *source=nullptr) const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
void setMaximumThreads(int threads)
Sets the (optional) number of threads to use when running algorithms.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
std::function< void(const QgsFeature &) > defaultInvalidGeometryCallbackForCheck(Qgis::InvalidGeometryCheck check, QgsFeatureSource *source=nullptr) const
Returns the default callback function to use for a particular invalid geometry check.
void setLayersToLoadOnCompletion(const QMap< QString, QgsProcessingContext::LayerDetails > &layers)
Sets the map of layers (by ID or datasource) to LayerDetails, to load into the canvas upon completion...
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
void setDistanceUnit(Qgis::DistanceUnit unit)
Sets the unit to use for distance calculations.
void setInvalidGeometryCheck(Qgis::InvalidGeometryCheck check)
Sets the behavior used for checking invalid geometries in input layers.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model.
void setAreaUnit(Qgis::AreaUnit areaUnit)
Sets the unit to use for area calculations.
void setEllipsoid(const QString &ellipsoid)
Sets a specified ellipsoid to use for distance and area calculations.
Qgis::DistanceUnit distanceUnit() const
Returns the distance unit to use for distance calculations.
Qgis::ProcessingLogLevel logLevel() const
Returns the logging level for algorithms to use when pushing feedback messages to users.
QgsProcessingContext()
Constructor for QgsProcessingContext.
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
void setTemporaryFolder(const QString &folder)
Sets the (optional) temporary folder to use when running algorithms.
QString temporaryFolder() const
Returns the (optional) temporary folder to use when running algorithms.
void setCurrentTimeRange(const QgsDateTimeRange &currentTimeRange)
Sets the current time range to use for temporal operations.
int maximumThreads() const
Returns the (optional) number of threads to use when running algorithms.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
An interface for layer post-processing handlers for execution following a processing algorithm operat...
Utility functions for use with processing classes.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
static const QgsSettingsEntryBool * settingsPreferFilenameAsLayerName
Settings entry prefer filename as layer name.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.