[processing] Always report errors if features cannot be written

to a destination

Before we silently ignored these - now algorithms will automatically
push errors to the log if a feature cannot be written to a sink (no
changes to algorithms or special handling required)
This commit is contained in:
Nyall Dawson 2018-02-16 19:25:36 +10:00
parent 84d2443b0a
commit 1f3ee0501a
3 changed files with 87 additions and 3 deletions

View File

@ -283,6 +283,7 @@ Returns an expression context scope suitable for this source.
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -388,7 +388,7 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, Qgs
destination = layer->id();
// this is a factory, so we need to return a proxy
std::unique_ptr< QgsProxyFeatureSink > sink( new QgsProxyFeatureSink( layer->dataProvider() ) );
std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
context.temporaryLayerStore()->addMapLayer( layer.release() );
return sink.release();
@ -415,7 +415,7 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, Qgs
throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
}
destination = finalFileName;
return writer.release();
return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
}
else
{
@ -434,7 +434,7 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, Qgs
destination = layer->id();
context.temporaryLayerStore()->addMapLayer( layer.release() );
return exporter.release();
return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
}
}
return nullptr;
@ -750,3 +750,44 @@ QgsExpressionContextScope *QgsProcessingFeatureSource::createExpressionContextSc
}
return expressionContextScope;
}
//
// QgsProcessingFeatureSink
//
QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
: QgsProxyFeatureSink( originalSink )
, mContext( context )
, mSinkName( sinkName )
, mOwnsSink( ownsOriginalSink )
{}
QgsProcessingFeatureSink::~QgsProcessingFeatureSink()
{
if ( mOwnsSink )
delete destinationSink();
}
bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
{
bool result = QgsProxyFeatureSink::addFeature( feature, flags );
if ( !result )
mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
return result;
}
bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
{
bool result = QgsProxyFeatureSink::addFeatures( features, flags );
if ( !result )
mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2" ).arg( features.count() ).arg( mSinkName ) );
return result;
}
bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
{
bool result = !QgsProxyFeatureSink::addFeatures( iterator, flags );
if ( !result )
mContext.feedback()->reportError( QObject::tr( "Features could not be written to %2" ).arg( mSinkName ) );
return result;
}

View File

@ -336,6 +336,48 @@ class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource
};
#ifndef SIP_RUN
/**
* \class QgsProcessingFeatureSink
* \ingroup core
* QgsProxyFeatureSink subclass which reports feature addition errors to a QgsProcessingContext.
* \since QGIS 3.0
* \note Not available in Python bindings.
*/
class CORE_EXPORT QgsProcessingFeatureSink : public QgsProxyFeatureSink
{
public:
/**
* Constructor for QgsProcessingFeatureSink, accepting an original feature sink \a originalSink
* and processing \a context. Any added features are added to the \a originalSink, with feature
* writing errors being reports to \a context.
*
* The \a context must exist for the lifetime of this object.
*
* The \a sinkName is used to identify the destination sink when reporting errors.
*
* Ownership of \a originalSink is dictated by \a ownsOriginalSource. If \a ownsOriginalSink is false,
* ownership is not transferred, and callers must ensure that \a originalSink exists for the lifetime of this object.
* If \a ownsOriginalSink is true, then this object will take ownership of \a originalSink.
*/
QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink = false );
~QgsProcessingFeatureSink();
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = nullptr ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = nullptr ) override;
bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = nullptr ) override;
private:
QgsProcessingContext &mContext;
QString mSinkName;
bool mOwnsSink = false;
};
#endif
#endif // QGSPROCESSINGUTILS_H