Skip to content

Commit

Permalink
[processing] When reporting that a feature is invalid, also mention
Browse files Browse the repository at this point in the history
the layer name so that it's clear which of the corresponding inputs
the warning/error relates to

Fixes #26664
  • Loading branch information
nyalldawson committed Oct 15, 2020
1 parent b38ea53 commit a53bb3d
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 10 deletions.
26 changes: 22 additions & 4 deletions src/core/processing/qgsprocessingcontext.cpp
Expand Up @@ -61,18 +61,31 @@ void QgsProcessingContext::addLayerToLoadOnCompletion( const QString &layer, con
void QgsProcessingContext::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check )
{
mInvalidGeometryCheck = check;
mUseDefaultInvalidGeometryCallback = true;
mInvalidGeometryCallback = defaultInvalidGeometryCallbackForCheck( check );
}

std::function<void ( const QgsFeature & )> QgsProcessingContext::defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check ) const
std::function<void ( const QgsFeature & )> QgsProcessingContext::invalidGeometryCallback( QgsFeatureSource *source ) const
{
if ( mUseDefaultInvalidGeometryCallback )
return defaultInvalidGeometryCallbackForCheck( mInvalidGeometryCheck, source );
else
return mInvalidGeometryCallback;
}

std::function<void ( const QgsFeature & )> QgsProcessingContext::defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check, QgsFeatureSource *source ) const
{
const QString sourceName = source ? source->sourceName() : QString();
switch ( check )
{
case QgsFeatureRequest::GeometryAbortOnInvalid:
{
auto callback = []( const QgsFeature & feature )
auto callback = [sourceName]( 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() ) );
if ( !sourceName.isEmpty() )
throw QgsProcessingException( QObject::tr( "Feature (%1) from “%2” has invalid geometry. Please fix the geometry or change the Processing setting to the “Ignore invalid input features” option." ).arg( feature.id() ).arg( sourceName ) );
else
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() ) );
};
return callback;
}
Expand All @@ -82,7 +95,12 @@ std::function<void ( const QgsFeature & )> QgsProcessingContext::defaultInvalidG
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() ) );
{
if ( !sourceName.isEmpty() )
mFeedback->reportError( QObject::tr( "Feature (%1) from “%2” 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() ).arg( sourceName ) );
else
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() ) );
}
};
return callback;
}
Expand Down
10 changes: 7 additions & 3 deletions src/core/processing/qgsprocessingcontext.h
Expand Up @@ -74,6 +74,7 @@ class CORE_EXPORT QgsProcessingContext
mTransformContext = other.mTransformContext;
mExpressionContext = other.mExpressionContext;
mInvalidGeometryCallback = other.mInvalidGeometryCallback;
mUseDefaultInvalidGeometryCallback = other.mUseDefaultInvalidGeometryCallback;
mInvalidGeometryCheck = other.mInvalidGeometryCheck;
mTransformErrorCallback = other.mTransformErrorCallback;
mDefaultEncoding = other.mDefaultEncoding;
Expand Down Expand Up @@ -389,7 +390,7 @@ class CORE_EXPORT QgsProcessingContext
* \since QGIS 3.0
*/
#ifndef SIP_RUN
void setInvalidGeometryCallback( const std::function< void( const QgsFeature & ) > &callback ) { mInvalidGeometryCallback = callback; }
void setInvalidGeometryCallback( const std::function< void( const QgsFeature & ) > &callback ) { mInvalidGeometryCallback = callback; mUseDefaultInvalidGeometryCallback = false; }
#else
void setInvalidGeometryCallback( SIP_PYCALLABLE / AllowNone / );
% MethodCode
Expand All @@ -413,14 +414,14 @@ class CORE_EXPORT QgsProcessingContext
* \see setInvalidGeometryCallback()
* \since QGIS 3.0
*/
SIP_SKIP std::function< void( const QgsFeature & ) > invalidGeometryCallback() const { return mInvalidGeometryCallback; }
SIP_SKIP std::function< void( const QgsFeature & ) > invalidGeometryCallback( QgsFeatureSource *source = nullptr ) const;

/**
* Returns the default callback function to use for a particular invalid geometry \a check
* \note not available in Python bindings
* \since QGIS 3.14
*/
SIP_SKIP std::function< void( const QgsFeature & ) > defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check ) const;
SIP_SKIP std::function< void( const QgsFeature & ) > defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check, QgsFeatureSource *source = nullptr ) const;

/**
* Sets a callback function to use when encountering a transform error when iterating
Expand Down Expand Up @@ -621,8 +622,11 @@ class CORE_EXPORT QgsProcessingContext
//! Temporary project owned by the context, used for storing temporarily loaded map layers
QgsMapLayerStore tempLayerStore;
QgsExpressionContext mExpressionContext;

QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck;
bool mUseDefaultInvalidGeometryCallback = true;
std::function< void( const QgsFeature & ) > mInvalidGeometryCallback;

std::function< void( const QgsFeature & ) > mTransformErrorCallback;
QString mDefaultEncoding;
QMap< QString, LayerDetails > mLayersToLoadOnCompletion;
Expand Down
6 changes: 3 additions & 3 deletions src/core/processing/qgsprocessingutils.cpp
Expand Up @@ -1213,10 +1213,10 @@ QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *origin
, mInvalidGeometryCheck( QgsWkbTypes::geometryType( mSource->wkbType() ) == QgsWkbTypes::PointGeometry
? QgsFeatureRequest::GeometryNoCheck // never run geometry validity checks for point layers!
: context.invalidGeometryCheck() )
, mInvalidGeometryCallback( context.invalidGeometryCallback() )
, mInvalidGeometryCallback( context.invalidGeometryCallback( originalSource ) )
, mTransformErrorCallback( context.transformErrorCallback() )
, mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid ) )
, mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid ) )
, mInvalidGeometryCallbackSkip( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometrySkipInvalid, originalSource ) )
, mInvalidGeometryCallbackAbort( context.defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::GeometryAbortOnInvalid, originalSource ) )
, mFeatureLimit( featureLimit )
{}

Expand Down

0 comments on commit a53bb3d

Please sign in to comment.