diff --git a/python/core/processing/qgsprocessingcontext.sip b/python/core/processing/qgsprocessingcontext.sip index e95cc5a67c9..a701fa9d7c8 100644 --- a/python/core/processing/qgsprocessingcontext.sip +++ b/python/core/processing/qgsprocessingcontext.sip @@ -142,7 +142,6 @@ Destination project .. seealso:: invalidGeometryCheck() %End - void setInvalidGeometryCallback( SIP_PYCALLABLE / AllowNone / ); %Docstring Sets a callback function to use when encountering an invalid geometry and @@ -198,16 +197,29 @@ Destination project %Docstring Sets the default ``encoding`` to use for newly created files. .. seealso:: defaultEncoding() +%End + + QgsProcessingFeedback *feedback(); +%Docstring + Returns the associated feedback object. +.. seealso:: setFeedback() + :rtype: QgsProcessingFeedback +%End + + void setFeedback( QgsProcessingFeedback *feedback ); +%Docstring + Sets an associated ``feedback`` object. This allows context related functions + to report feedback and errors to users and processing logs. While ideally this feedback + object should outlive the context, only a weak pointer to ``feedback`` is stored + and no errors will occur if feedback is deleted before the context. + Ownership of ``feedback`` is not transferred. +.. seealso:: setFeedback() %End private: QgsProcessingContext( const QgsProcessingContext &other ); }; - - - - QFlags operator|(QgsProcessingContext::Flag f1, QFlags f2); diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py index 60ac761753c..431a15309aa 100644 --- a/python/plugins/processing/gui/AlgorithmDialogBase.py +++ b/python/plugins/processing/gui/AlgorithmDialogBase.py @@ -189,7 +189,7 @@ class AlgorithmDialogBase(BASE, WIDGET): def setInfo(self, msg, error=False, escape_html=True): if error: - self.txtLog.append('
{}
'.format(msg, quote=False)) + self.txtLog.append('{}
'.format(msg, quote=False)) elif escape_html: self.txtLog.append(html.escape(msg)) else: diff --git a/python/plugins/processing/tools/dataobjects.py b/python/plugins/processing/tools/dataobjects.py index abf098fcd20..2656f01cf6a 100644 --- a/python/plugins/processing/tools/dataobjects.py +++ b/python/plugins/processing/tools/dataobjects.py @@ -71,27 +71,13 @@ def createContext(feedback=None): """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) + context.setFeedback(feedback) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) - def raise_invalid_geometry_error(f, feedback=feedback): - if feedback: - feedback.pushInfo(QCoreApplication.translate("FeatureIterator", - 'Feature with id {} has invalid geometry, skipping feature.'.format(f.id()))) - - if context.invalidGeometryCheck() == QgsFeatureRequest.GeometrySkipInvalid: - context.setInvalidGeometryCallback(raise_invalid_geometry_error) - - def raise_transform_error(f, feedback=feedback): - if feedback: - feedback.pushInfo(QCoreApplication.translate("FeatureIterator", - 'Encountered a transform error when reprojecting feature with id {}.'.format(f.id()))) - - context.setTransformErrorCallback(raise_transform_error) - settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) diff --git a/src/core/processing/qgsprocessingcontext.h b/src/core/processing/qgsprocessingcontext.h index b246adc5e26..4ba4fb5ad75 100644 --- a/src/core/processing/qgsprocessingcontext.h +++ b/src/core/processing/qgsprocessingcontext.h @@ -25,6 +25,7 @@ #include "qgsfeaturerequest.h" #include "qgsmaplayerlistutils.h" #include "qgsexception.h" +#include "qgsprocessingfeedback.h" /** * \class QgsProcessingContext @@ -50,7 +51,15 @@ class CORE_EXPORT QgsProcessingContext /** * Constructor for QgsProcessingContext. */ - QgsProcessingContext() = default; + QgsProcessingContext() + { + auto callback = [ = ]( const QgsFeature & feature ) + { + if ( mFeedback ) + mFeedback->reportError( QObject::tr( "Encountered a transform error when reprojecting feature with id %1." ).arg( feature.id() ) ); + }; + mTransformErrorCallback = callback; + } //! QgsProcessingContext cannot be copied QgsProcessingContext( const QgsProcessingContext &other ) = delete; @@ -176,17 +185,34 @@ class CORE_EXPORT QgsProcessingContext { mInvalidGeometryCheck = check; - if ( mInvalidGeometryCheck == QgsFeatureRequest::GeometryAbortOnInvalid ) + switch ( mInvalidGeometryCheck ) { - auto callback = []( const QgsFeature & feature ) + case QgsFeatureRequest::GeometryAbortOnInvalid: { - throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) ); - }; - mInvalidGeometryCallback = callback; + auto callback = []( const QgsFeature & feature ) + { + throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) ); + }; + mInvalidGeometryCallback = callback; + break; + } + + case QgsFeatureRequest::GeometrySkipInvalid: + { + auto callback = [ = ]( const QgsFeature & feature ) + { + if ( mFeedback ) + mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) ); + }; + mInvalidGeometryCallback = callback; + break; + } + + default: + break; } } - /** * Sets a callback function to use when encountering an invalid geometry and * invalidGeometryCheck() is set to GeometryAbortOnInvalid. This function will be @@ -268,6 +294,22 @@ class CORE_EXPORT QgsProcessingContext */ void setDefaultEncoding( const QString &encoding ) { mDefaultEncoding = encoding; } + /** + * Returns the associated feedback object. + * \see setFeedback() + */ + QgsProcessingFeedback *feedback() { return mFeedback; } + + /** + * Sets an associated \a feedback object. This allows context related functions + * to report feedback and errors to users and processing logs. While ideally this feedback + * object should outlive the context, only a weak pointer to \a feedback is stored + * and no errors will occur if feedback is deleted before the context. + * Ownership of \a feedback is not transferred. + * \see setFeedback() + */ + void setFeedback( QgsProcessingFeedback *feedback ) { mFeedback = feedback; } + private: QgsProcessingContext::Flags mFlags = 0; @@ -282,15 +324,13 @@ class CORE_EXPORT QgsProcessingContext QString mDefaultEncoding; QMap< QString, LayerDetails > mLayersToLoadOnCompletion; + QPointer< QgsProcessingFeedback > mFeedback; + #ifdef SIP_RUN QgsProcessingContext( const QgsProcessingContext &other ); #endif }; - - - - Q_DECLARE_OPERATORS_FOR_FLAGS( QgsProcessingContext::Flags ) #endif // QGSPROCESSINGPARAMETERS_H