QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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
24 : mPreferredVectorFormat( QgsProcessingUtils::defaultVectorExtension() )
25 , mPreferredRasterFormat( QgsProcessingUtils::defaultRasterExtension() )
26{
27 auto callback = [ = ]( const QgsFeature & feature )
28 {
29 if ( mFeedback )
30 mFeedback->reportError( QObject::tr( "Encountered a transform error when reprojecting feature with id %1." ).arg( feature.id() ) );
31 };
32 mTransformErrorCallback = callback;
33 mExpressionContext.setLoadedLayerStore( &tempLayerStore );
34}
35
37{
38 for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it )
39 {
40 delete it.value().postProcessor();
41 }
42}
43
45{
46 mExpressionContext = context;
47 // any layers temporarily loaded by expressions should use the same temporary layer store as this context
48 mExpressionContext.setLoadedLayerStore( &tempLayerStore );
49}
50
51void QgsProcessingContext::setLayersToLoadOnCompletion( const QMap<QString, QgsProcessingContext::LayerDetails> &layers )
52{
53 for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it )
54 {
55 if ( !layers.contains( it.key() ) || layers.value( it.key() ).postProcessor() != it.value().postProcessor() )
56 delete it.value().postProcessor();
57 }
58 mLayersToLoadOnCompletion = layers;
59}
60
62{
63 if ( mLayersToLoadOnCompletion.contains( layer ) && mLayersToLoadOnCompletion.value( layer ).postProcessor() != details.postProcessor() )
64 delete mLayersToLoadOnCompletion.value( layer ).postProcessor();
65
66 mLayersToLoadOnCompletion.insert( layer, details );
67}
68
70{
71 mInvalidGeometryCheck = check;
72 mUseDefaultInvalidGeometryCallback = true;
73 mInvalidGeometryCallback = defaultInvalidGeometryCallbackForCheck( check );
74}
75
76std::function<void ( const QgsFeature & )> QgsProcessingContext::invalidGeometryCallback( QgsFeatureSource *source ) const
77{
78 if ( mUseDefaultInvalidGeometryCallback )
79 return defaultInvalidGeometryCallbackForCheck( mInvalidGeometryCheck, source );
80 else
81 return mInvalidGeometryCallback;
82}
83
85{
86 const QString sourceName = source ? source->sourceName() : QString();
87 switch ( check )
88 {
90 {
91 auto callback = [sourceName]( const QgsFeature & feature )
92 {
93 if ( !sourceName.isEmpty() )
94 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 ) );
95 else
96 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() ) );
97 };
98 return callback;
99 }
100
102 {
103 auto callback = [ = ]( const QgsFeature & feature )
104 {
105 if ( mFeedback )
106 {
107 if ( !sourceName.isEmpty() )
108 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 ) );
109 else
110 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() ) );
111 }
112 };
113 return callback;
114 }
115
117 return nullptr;
118 }
119 return nullptr;
120}
121
123{
124 setLayersToLoadOnCompletion( context.mLayersToLoadOnCompletion );
125 context.mLayersToLoadOnCompletion.clear();
126 tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() );
127}
128
130{
131 return QgsProcessingUtils::mapLayerFromString( identifier, *this, false );
132}
133
135{
136 return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) );
137}
138
140{
141 return mLogLevel;
142}
143
145{
146 mLogLevel = level;
147}
148
150{
151 QVariantMap res;
152 if ( mDistanceUnit != Qgis::DistanceUnit::Unknown )
153 res.insert( QStringLiteral( "distance_units" ), QgsUnitTypes::encodeUnit( mDistanceUnit ) );
154 if ( mAreaUnit != Qgis::AreaUnit::Unknown )
155 res.insert( QStringLiteral( "area_units" ), QgsUnitTypes::encodeUnit( mAreaUnit ) );
156 if ( !mEllipsoid.isEmpty() )
157 res.insert( QStringLiteral( "ellipsoid" ), mEllipsoid );
158 if ( mProject )
159 res.insert( QStringLiteral( "project_path" ), mProject->fileName() );
160
161 return res;
162}
163
164QStringList QgsProcessingContext::asQgisProcessArguments( QgsProcessingContext::ProcessArgumentFlags flags ) const
165{
166 auto escapeIfNeeded = []( const QString & input ) -> QString
167 {
168 // play it safe and escape everything UNLESS it's purely alphanumeric characters (and a very select scattering of other common characters!)
169 const thread_local QRegularExpression nonAlphaNumericRx( QStringLiteral( "[^a-zA-Z0-9.\\-/_]" ) );
170 if ( nonAlphaNumericRx.match( input ).hasMatch() )
171 {
172 QString escaped = input;
173 escaped.replace( '\'', QLatin1String( "'\\''" ) );
174 return QStringLiteral( "'%1'" ).arg( escaped );
175 }
176 else
177 {
178 return input;
179 }
180 };
181
182 QStringList res;
183 if ( mDistanceUnit != Qgis::DistanceUnit::Unknown )
184 res << QStringLiteral( "--distance_units=%1" ).arg( QgsUnitTypes::encodeUnit( mDistanceUnit ) );
185 if ( mAreaUnit != Qgis::AreaUnit::Unknown )
186 res << QStringLiteral( "--area_units=%1" ).arg( QgsUnitTypes::encodeUnit( mAreaUnit ) );
187 if ( !mEllipsoid.isEmpty() )
188 res << QStringLiteral( "--ellipsoid=%1" ).arg( mEllipsoid );
189
191 {
192 res << QStringLiteral( "--project_path=%1" ).arg( escapeIfNeeded( mProject->fileName() ) );
193 }
194
195 return res;
196}
197
199{
200 return mCurrentTimeRange;
201}
202
203void QgsProcessingContext::setCurrentTimeRange( const QgsDateTimeRange &currentTimeRange )
204{
205 mCurrentTimeRange = currentTimeRange;
206}
207
209{
210 return mEllipsoid;
211}
212
213void QgsProcessingContext::setEllipsoid( const QString &ellipsoid )
214{
215 mEllipsoid = ellipsoid;
216}
217
219{
220 return mDistanceUnit;
221}
222
224{
225 mDistanceUnit = unit;
226}
227
229{
230 return mAreaUnit;
231}
232
234{
235 mAreaUnit = areaUnit;
236}
237
239{
240 return mPostProcessor;
241}
242
244{
245 if ( mPostProcessor && mPostProcessor != processor )
246 delete mPostProcessor;
247
248 mPostProcessor = processor;
249}
250
252{
253 if ( !layer )
254 return;
255
256 const bool preferFilenameAsLayerName = QgsProcessing::settingsPreferFilenameAsLayerName->value();
257
258 // note - for temporary layers, we don't use the filename, regardless of user setting (it will be meaningless!)
259 if ( ( !forceName && preferFilenameAsLayerName && !layer->isTemporary() ) || name.isEmpty() )
260 {
261 const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
262 const QString layerName = sourceParts.value( QStringLiteral( "layerName" ) ).toString();
263 // if output layer name exists, use that!
264 if ( !layerName.isEmpty() )
265 layer->setName( layerName );
266 else
267 {
268 const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
269 if ( !path.isEmpty() )
270 {
271 const QFileInfo fi( path );
272 layer->setName( fi.baseName() );
273 }
274 else if ( !name.isEmpty() )
275 {
276 // fallback to parameter's name -- shouldn't happen!
277 layer->setName( name );
278 }
279 }
280 }
281 else
282 {
283 layer->setName( name );
284 }
285}
DistanceUnit
Units of distance.
Definition: qgis.h:3047
AreaUnit
Units of area.
Definition: qgis.h:3084
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.
InvalidGeometryCheck
Handling of features with invalid geometries.
@ GeometryNoCheck
No invalid geometry checking.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ GeometrySkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
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:73
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.
LogLevel
Logging level for algorithms to use when pushing feedback messages.
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.
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 setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
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 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.
QgsProcessingContext()
Constructor for QgsProcessingContext.
void setLogLevel(LogLevel level)
Sets the logging level for algorithms to use when pushing feedback messages to users.
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
void setInvalidGeometryCheck(QgsFeatureRequest::InvalidGeometryCheck check)
Sets the behavior used for checking invalid geometries in input layers.
LogLevel logLevel() const
Returns the logging level for algorithms to use when pushing feedback messages to users.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
std::function< void(const QgsFeature &) > defaultInvalidGeometryCallbackForCheck(QgsFeatureRequest::InvalidGeometryCheck check, QgsFeatureSource *source=nullptr) const
Returns the default callback function to use for a particular invalid geometry check.
void setCurrentTimeRange(const QgsDateTimeRange &currentTimeRange)
Sets the current time range to use for temporal operations.
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)
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.