Skip to content

Commit

Permalink
Create class for encapsulating settings relating to a feature sink
Browse files Browse the repository at this point in the history
input to a processing algorithm.

This allows parameter inputs to encapsulate extra information
relating to a feature sink input, such as destination file
encoding and whether the sink layer should be loaded into
the project on completion
  • Loading branch information
nyalldawson committed Jun 5, 2017
1 parent 5b8affc commit 005a08e
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 20 deletions.
4 changes: 2 additions & 2 deletions python/core/processing/qgsprocessingalgorithm.sip
Expand Up @@ -308,15 +308,15 @@ class QgsProcessingAlgorithm
%End

QgsFeatureSink *parameterAsSink( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
QString &destinationIdentifier /Out/ ) const /Factory/;
%Docstring
Evaluates the parameter with matching ``name`` to a feature sink.

Sinks will either be taken from ``context``'s active project, or created from external
providers and stored temporarily in the ``context``.

The ``encoding``, ``fields``, ``geometryType`` and ``crs`` parameters dictate the properties
The ``fields``, ``geometryType`` and ``crs`` parameters dictate the properties
of the resulting feature sink.

The ``destinationIdentifier`` argument will be set to a string which can be used to retrieve the layer corresponding
Expand Down
43 changes: 41 additions & 2 deletions python/core/processing/qgsprocessingparameters.sip
Expand Up @@ -11,6 +11,45 @@



class QgsProcessingFeatureSink
{
%Docstring

Encapsulates settings relating to a feature sink input to a processing algorithm.

.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsprocessingparameters.h"
%End
public:

QgsProcessingFeatureSink( const QVariant &sink = QVariant(), bool loadIntoProject = false );
%Docstring
Constructor for QgsProcessingFeatureSink.
%End

QVariant sink;
%Docstring
Sink definition. Usually set to the destination file name for the sink's layer.
%End

bool loadIntoProject;
%Docstring
True if sink should be loaded into the current project when the algorithm completes.
%End

QString fileEncoding;
%Docstring
Encoding for destination file.
%End

};






class QgsProcessingParameterDefinition
Expand Down Expand Up @@ -266,12 +305,12 @@ class QgsProcessingParameters
%End

static QgsFeatureSink *parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters,
const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context, QString &destinationIdentifier /Out/ ) /Factory/;
%Docstring
Evaluates the parameter with matching ``definition`` to a feature sink.

The ``encoding``, ``fields``, ``geometryType`` and ``crs`` parameters dictate the properties
The ``fields``, ``geometryType`` and ``crs`` parameters dictate the properties
of the resulting feature sink.

Sinks will either be taken from ``context``'s active project, or created from external
Expand Down
4 changes: 2 additions & 2 deletions src/core/processing/qgsnativealgorithms.cpp
Expand Up @@ -83,7 +83,7 @@ QVariantMap QgsCentroidAlgorithm::processAlgorithm( const QVariantMap &parameter
return QVariantMap();

QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT_LAYER" ), context, QString(), layer->fields(), QgsWkbTypes::Point, layer->crs(), dest ) );
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT_LAYER" ), context, layer->fields(), QgsWkbTypes::Point, layer->crs(), dest ) );

long count = QgsProcessingUtils::featureCount( layer, context );
if ( count <= 0 )
Expand Down Expand Up @@ -156,7 +156,7 @@ QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters,
return QVariantMap();

QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT_LAYER" ), context, QString(), layer->fields(), QgsWkbTypes::Polygon, layer->crs(), dest ) );
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT_LAYER" ), context, layer->fields(), QgsWkbTypes::Polygon, layer->crs(), dest ) );

// fixed parameters
//bool dissolve = QgsProcessingParameters::parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context );
Expand Down
4 changes: 2 additions & 2 deletions src/core/processing/qgsprocessingalgorithm.cpp
Expand Up @@ -210,9 +210,9 @@ bool QgsProcessingAlgorithm::parameterAsBool( const QVariantMap &parameters, con
return QgsProcessingParameters::parameterAsBool( parameterDefinition( name ), parameters, context );
}

QgsFeatureSink *QgsProcessingAlgorithm::parameterAsSink( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QString &destinationIdentifier ) const
QgsFeatureSink *QgsProcessingAlgorithm::parameterAsSink( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QString &destinationIdentifier ) const
{
return QgsProcessingParameters::parameterAsSink( parameterDefinition( name ), parameters, encoding, fields, geometryType, crs, context, destinationIdentifier );
return QgsProcessingParameters::parameterAsSink( parameterDefinition( name ), parameters, fields, geometryType, crs, context, destinationIdentifier );
}

QgsMapLayer *QgsProcessingAlgorithm::parameterAsLayer( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const
Expand Down
4 changes: 2 additions & 2 deletions src/core/processing/qgsprocessingalgorithm.h
Expand Up @@ -304,7 +304,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* Sinks will either be taken from \a context's active project, or created from external
* providers and stored temporarily in the \a context.
*
* The \a encoding, \a fields, \a geometryType and \a crs parameters dictate the properties
* The \a fields, \a geometryType and \a crs parameters dictate the properties
* of the resulting feature sink.
*
* The \a destinationIdentifier argument will be set to a string which can be used to retrieve the layer corresponding
Expand All @@ -313,7 +313,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* This function creates a new object and the caller takes responsibility for deleting the returned object.
*/
QgsFeatureSink *parameterAsSink( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
QString &destinationIdentifier SIP_OUT ) const SIP_FACTORY;

/**
Expand Down
38 changes: 36 additions & 2 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -202,14 +202,48 @@ bool QgsProcessingParameters::parameterAsBool( const QgsProcessingParameterDefin
return def.toBool();
}

QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QString &encoding, const QgsFields &fields,
QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsFields &fields,
QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context, QString &destinationIdentifier )
{
QString dest = parameterAsString( definition, parameters, context );
QVariant val;
if ( definition )
{
val = parameters.value( definition->name() );
}

bool loadIntoProject = false;
QString encoding;
if ( val.canConvert<QgsProcessingFeatureSink>() )
{
// input is a QgsProcessingFeatureSink - get extra properties from it
QgsProcessingFeatureSink fromVar = qvariant_cast<QgsProcessingFeatureSink>( val );
loadIntoProject = fromVar.loadIntoProject;
encoding = fromVar.fileEncoding;
val = fromVar.sink;
}

QString dest;
if ( val.canConvert<QgsProperty>() )
{
dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
}
else if ( !val.isValid() || val.toString().isEmpty() )
{
// fall back to default
dest = definition->defaultValue().toString();
}
else
{
dest = val.toString();
}

std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( dest, encoding, fields, geometryType, crs, context ) );
destinationIdentifier = dest;

if ( loadIntoProject )
context.addLayerToLoadOnCompletion( destinationIdentifier );

return sink.release();
}

Expand Down
45 changes: 43 additions & 2 deletions src/core/processing/qgsprocessingparameters.h
Expand Up @@ -30,6 +30,47 @@ class QgsRasterLayer;
class QgsVectorLayer;
class QgsFeatureSink;

/**
* \class QgsProcessingFeatureSink
* \ingroup core
*
* Encapsulates settings relating to a feature sink input to a processing algorithm.
*
* \since QGIS 3.0
*/

class CORE_EXPORT QgsProcessingFeatureSink
{
public:

/**
* Constructor for QgsProcessingFeatureSink.
*/
QgsProcessingFeatureSink( const QVariant &sink = QVariant(), bool loadIntoProject = false )
: sink( sink )
, loadIntoProject( loadIntoProject )
{}

/**
* Sink definition. Usually set to the destination file name for the sink's layer.
*/
QVariant sink;

/**
* True if sink should be loaded into the current project when the algorithm completes.
*/
bool loadIntoProject;

/**
* Encoding for destination file.
*/
QString fileEncoding;

};

Q_DECLARE_METATYPE( QgsProcessingFeatureSink )



//
// Parameter definitions
Expand Down Expand Up @@ -285,7 +326,7 @@ class CORE_EXPORT QgsProcessingParameters
/**
* Evaluates the parameter with matching \a definition to a feature sink.
*
* The \a encoding, \a fields, \a geometryType and \a crs parameters dictate the properties
* The \a fields, \a geometryType and \a crs parameters dictate the properties
* of the resulting feature sink.
*
* Sinks will either be taken from \a context's active project, or created from external
Expand All @@ -296,7 +337,7 @@ class CORE_EXPORT QgsProcessingParameters
* This function creates a new object and the caller takes responsibility for deleting the returned object.
*/
static QgsFeatureSink *parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters,
const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context, QString &destinationIdentifier SIP_OUT ) SIP_FACTORY;

/**
Expand Down
50 changes: 44 additions & 6 deletions tests/src/core/testqgsprocessing.cpp
Expand Up @@ -217,6 +217,7 @@ class TestQgsProcessing: public QObject
void parameterOutputVectorLayer();
void checkParamValues();
void combineLayerExtent();
void processingFeatureSink();

private:

Expand Down Expand Up @@ -1062,15 +1063,15 @@ void TestQgsProcessing::parameters()
// make sure layer was loaded
QVERIFY( !context.temporaryLayerStore()->mapLayers().isEmpty() );

// as sink
QString encoding;
// parameters as sinks

QgsWkbTypes::Type wkbType = QgsWkbTypes::PolygonM;
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem( "epsg:3111" );
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem( QStringLiteral( "epsg:3111" ) );
QString destId;
def->setName( QStringLiteral( "string" ) );
params.insert( QStringLiteral( "string" ), QStringLiteral( "memory:mem" ) );
std::unique_ptr< QgsFeatureSink > sink;
sink.reset( QgsProcessingParameters::parameterAsSink( def, params, encoding, fields, wkbType, crs, context, destId ) );
sink.reset( QgsProcessingParameters::parameterAsSink( def, params, fields, wkbType, crs, context, destId ) );
QVERIFY( sink.get() );
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destId, context ) );
QVERIFY( layer );
Expand All @@ -1083,8 +1084,8 @@ void TestQgsProcessing::parameters()
// property defined sink destination
params.insert( QStringLiteral( "prop" ), QgsProperty::fromExpression( "'memory:mem2'" ) );
def->setName( QStringLiteral( "prop" ) );
crs = QgsCoordinateReferenceSystem( "epsg:3113" );
sink.reset( QgsProcessingParameters::parameterAsSink( def, params, encoding, fields, wkbType, crs, context, destId ) );
crs = QgsCoordinateReferenceSystem( QStringLiteral( "epsg:3113" ) );
sink.reset( QgsProcessingParameters::parameterAsSink( def, params, fields, wkbType, crs, context, destId ) );
QVERIFY( sink.get() );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destId, context ) );
QVERIFY( layer );
Expand All @@ -1094,6 +1095,27 @@ void TestQgsProcessing::parameters()
QCOMPARE( layer->wkbType(), wkbType );
QCOMPARE( layer->crs(), crs );

// QgsProcessingFeatureSink as parameter
QgsProcessingFeatureSink fs( QStringLiteral( "test.shp" ) );
fs.loadIntoProject = true;
QVERIFY( context.layersToLoadOnCompletion().isEmpty() );
params.insert( QStringLiteral( "fs" ), QVariant::fromValue( fs ) );
def->setName( QStringLiteral( "fs" ) );
crs = QgsCoordinateReferenceSystem( QStringLiteral( "epsg:28356" ) );
sink.reset( QgsProcessingParameters::parameterAsSink( def, params, fields, wkbType, crs, context, destId ) );
QVERIFY( sink.get() );
QgsVectorFileWriter *writer = dynamic_cast< QgsVectorFileWriter *>( sink.get() );
QVERIFY( writer );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destId, context ) );
QVERIFY( layer );
QVERIFY( layer->isValid() );
QCOMPARE( layer->wkbType(), wkbType );
QCOMPARE( layer->crs(), crs );

// make sure layer was automatically added to list to load on completion
QCOMPARE( context.layersToLoadOnCompletion().size(), 1 );
QCOMPARE( context.layersToLoadOnCompletion().at( 0 ), destId );

delete def;
}

Expand Down Expand Up @@ -2249,5 +2271,21 @@ void TestQgsProcessing::combineLayerExtent()
QGSCOMPARENEAR( ext.yMaximum(), 3536664, 10 );
}

void TestQgsProcessing::processingFeatureSink()
{
QVariant sink( QStringLiteral( "test.shp" ) );
QgsProcessingFeatureSink fs( sink, true );
QCOMPARE( fs.sink, sink );
QVERIFY( fs.loadIntoProject );

// test storing QgsProcessingFeatureSink in variant and retrieving
QVariant fsInVariant = QVariant::fromValue( fs );
QVERIFY( fsInVariant.isValid() );

QgsProcessingFeatureSink fromVar = qvariant_cast<QgsProcessingFeatureSink>( fsInVariant );
QCOMPARE( fromVar.sink, sink );
QVERIFY( fromVar.loadIntoProject );
}

QGSTEST_MAIN( TestQgsProcessing )
#include "testqgsprocessing.moc"

0 comments on commit 005a08e

Please sign in to comment.