Skip to content
Permalink
Browse files

[processing] Change explicit encoding string parameters to more

flexible QVariantMap creatOptions parameters which include an
optional fileEncoding value

More flexible, allows sinks to be created using any creation
option which is passed to the underlying provider
  • Loading branch information
nyalldawson committed Jun 5, 2017
1 parent ea2e477 commit d7aa3f5f7c35a6c6c3a0912c16c40871372872c9
@@ -80,9 +80,12 @@ class QgsProcessingFeatureSink
True if sink should be loaded into the current project when the algorithm completes.
%End

QString fileEncoding;
QVariantMap createOptions;
%Docstring
Encoding for destination file.
Map of optional sink creation options, which
are passed to the underlying provider when creating new layers. Known options also
include 'fileEncoding', which is used to specify a file encoding to use for created
files.
%End


@@ -90,19 +90,22 @@ class QgsProcessingUtils
static void createFeatureSinkPython(
QgsFeatureSink **sink /Out,TransferBack/,
QString &destination /In,Out/,
const QString &encoding,
QgsProcessingContext &context,
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context ) /PyName=createFeatureSink/;
const QVariantMap &createOptions = QVariantMap() ) /PyName=createFeatureSink/;
%Docstring
Creates a feature sink ready for adding features. The ``destination`` specifies a destination
URI for the resultant layer. It may be updated in place to reflect the actual destination
for the layer.

Sink parameters such as desired ``encoding``, ``fields``, ``geometryType`` and ``crs`` must be specified.
Sink parameters such as desired ``fields``, ``geometryType`` and ``crs`` must be specified.

If the ``encoding`` is not specified, the default encoding from the ``context`` will be used.
The ``createOptions`` map can be used to specify additional sink creation options, which
are passed to the underlying provider when creating new layers. Known options also
include 'fileEncoding', which is used to specify a file encoding to use for created
files. If 'fileEncoding' is not specified, the default encoding from the ``context`` will be used.

If a layer is created for the feature sink, the layer will automatically be added to the ``context``'s
temporary layer store.
@@ -87,7 +87,7 @@ def processAlgorithm(self, parameters, context, feedback):
for current, i in enumerate(uniqueValues):
fName = u'{0}_{1}.shp'.format(baseName, str(i).strip())

writer, dest = QgsProcessingUtils.createFeatureSink(fName, None, fields, geomType, crs, context)
writer, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)
for f in QgsProcessingUtils.getFeatures(layer, context):
if f[fieldName] == i:
writer.addFeature(f)
@@ -10,8 +10,7 @@
layer = QgsProcessingUtils.mapLayerFromString(input, context)
fields = layer.fields()
fields.append(QgsField('UNIQ_COUNT', QVariant.Int))
writer, writer_dest = QgsProcessingUtils.createFeatureSink(N_unique_values, None, fields, layer.wkbType(), layer.crs(),
context)
writer, writer_dest = QgsProcessingUtils.createFeatureSink(N_unique_values, context, fields, layer.wkbType(), layer.crs())

class_field_index = layer.fields().lookupField(class_field)
value_field_index = layer.fields().lookupField(value_field)
@@ -369,7 +369,7 @@ def getVectorWriter(self, fields, geomType, crs, context):
settings = QgsSettings()
self.encoding = settings.value('/Processing/encoding', 'System', str)

w, w_dest = QgsProcessingUtils.createFeatureSink(self.value, self.encoding, fields, geomType, crs, context)
w, w_dest = QgsProcessingUtils.createFeatureSink(self.value, context, fields, geomType, crs, {'fileEncoding': self.encoding})
self.value = w_dest
return w

@@ -8,8 +8,7 @@
layer = QgsProcessingUtils.mapLayerFromString(INPUT_LAYER, context)
fields = layer.fields()

writer, writer_dest = QgsProcessingUtils.createFeatureSink(OUTPUT_LAYER, 'utf-8', fields, QgsWkbTypes.Point, layer.crs(),
context)
writer, writer_dest = QgsProcessingUtils.createFeatureSink(OUTPUT_LAYER, context, fields, QgsWkbTypes.Point, layer.crs(), {'fileEncoding': 'utf-8'})

features = QgsProcessingUtils.getFeatures(layer, context)
count = QgsProcessingUtils.featureCount(layer, context)
@@ -214,13 +214,13 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
}

bool loadIntoProject = false;
QString encoding;
QVariantMap createOptions;
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;
createOptions = fromVar.createOptions;
val = fromVar.sink;
}

@@ -239,7 +239,7 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
dest = val.toString();
}

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

if ( loadIntoProject )
@@ -106,9 +106,12 @@ class CORE_EXPORT QgsProcessingFeatureSink
bool loadIntoProject;

/**
* Encoding for destination file.
* Map of optional sink creation options, which
* are passed to the underlying provider when creating new layers. Known options also
* include 'fileEncoding', which is used to specify a file encoding to use for created
* files.
*/
QString fileEncoding;
QVariantMap createOptions;


//! Allows direct construction of QVariants.
@@ -262,14 +262,14 @@ void parseDestinationString( QString &destination, QString &providerKey, QString
}
}

QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context )
QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions )
{
QString destEncoding = encoding;
QVariantMap options = createOptions;
QgsVectorLayer *layer = nullptr;
if ( destEncoding.isEmpty() )
if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
{
// no destination encoding specified, use default
destEncoding = context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding();
options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
}

if ( destination.isEmpty() || destination.startsWith( QStringLiteral( "memory:" ) ) )
@@ -279,9 +279,6 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
}
else
{
QMap<QString, QVariant> options;
options.insert( QStringLiteral( "fileEncoding" ), destEncoding );

QString providerKey;
QString uri;
QString format;
@@ -292,7 +289,7 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
// use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
// us to use any OGR format which supports feature addition
QString finalFileName;
QgsVectorFileWriter *writer = new QgsVectorFileWriter( destination, destEncoding, fields, geometryType, crs, format, QgsVectorFileWriter::defaultDatasetOptions( format ),
QgsVectorFileWriter *writer = new QgsVectorFileWriter( destination, options.value( QStringLiteral( "fileEncoding" ) ).toString(), fields, geometryType, crs, format, QgsVectorFileWriter::defaultDatasetOptions( format ),
QgsVectorFileWriter::defaultLayerOptions( format ), &finalFileName );
destination = finalFileName;
return writer;
@@ -329,9 +326,9 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
return new QgsProxyFeatureSink( layer->dataProvider() );
}

void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context )
void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
{
*sink = createFeatureSink( destination, encoding, fields, geometryType, crs, context );
*sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
}


@@ -30,6 +30,7 @@ class QgsProcessingContext;
class QgsMapLayerStore;

#include <QString>
#include <QVariant>

/**
* \class QgsProcessingUtils
@@ -106,7 +107,10 @@ class CORE_EXPORT QgsProcessingUtils
*
* Sink parameters such as desired \a encoding, \a fields, \a geometryType and \a crs must be specified.
*
* If the \a encoding is not specified, the default encoding from the \a context will be used.
* The \a createOptions map can be used to specify additional sink creation options, which
* are passed to the underlying provider when creating new layers. Known options also
* include 'fileEncoding', which is used to specify a file encoding to use for created
* files. If 'fileEncoding' is not specified, the default encoding from the \a context will be used.
*
* If a layer is created for the feature sink, the layer will automatically be added to the \a context's
* temporary layer store.
@@ -116,21 +120,24 @@ class CORE_EXPORT QgsProcessingUtils
#ifndef SIP_RUN
static QgsFeatureSink *createFeatureSink(
QString &destination,
const QString &encoding,
QgsProcessingContext &context,
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context ) SIP_FACTORY;
const QVariantMap &createOptions = QVariantMap() ) SIP_FACTORY;
#endif

/**
* Creates a feature sink ready for adding features. The \a destination specifies a destination
* URI for the resultant layer. It may be updated in place to reflect the actual destination
* for the layer.
*
* Sink parameters such as desired \a encoding, \a fields, \a geometryType and \a crs must be specified.
* Sink parameters such as desired \a fields, \a geometryType and \a crs must be specified.
*
* If the \a encoding is not specified, the default encoding from the \a context will be used.
* The \a createOptions map can be used to specify additional sink creation options, which
* are passed to the underlying provider when creating new layers. Known options also
* include 'fileEncoding', which is used to specify a file encoding to use for created
* files. If 'fileEncoding' is not specified, the default encoding from the \a context will be used.
*
* If a layer is created for the feature sink, the layer will automatically be added to the \a context's
* temporary layer store.
@@ -142,11 +149,11 @@ class CORE_EXPORT QgsProcessingUtils
static void createFeatureSinkPython(
QgsFeatureSink **sink SIP_OUT SIP_TRANSFERBACK,
QString &destination SIP_INOUT,
const QString &encoding,
QgsProcessingContext &context,
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context ) SIP_PYNAME( createFeatureSink );
const QVariantMap &createOptions = QVariantMap() ) SIP_PYNAME( createFeatureSink );

/**
* Combines the extent of several map \a layers. If specified, the target \a crs
@@ -921,7 +921,7 @@ void TestQgsProcessing::createFeatureSink()
QgsVectorLayer *layer = nullptr;

// should create a memory layer
std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context ) );
std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( destination, context, QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem() ) );
QVERIFY( sink.get() );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
@@ -938,7 +938,7 @@ void TestQgsProcessing::createFeatureSink()

// specific memory layer output
destination = QStringLiteral( "memory:mylayer" );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context ) );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, context, QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem() ) );
QVERIFY( sink.get() );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
@@ -957,7 +957,7 @@ void TestQgsProcessing::createFeatureSink()
destination = QStringLiteral( "memory:mylayer" );
QgsFields fields;
fields.append( QgsField( QStringLiteral( "my_field" ), QVariant::String, QString(), 100 ) );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::PointZM, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context ) );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, context, fields, QgsWkbTypes::PointZM, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ) ) );
QVERIFY( sink.get() );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
@@ -980,7 +980,7 @@ void TestQgsProcessing::createFeatureSink()
// non memory layer output
destination = QDir::tempPath() + "/create_feature_sink.tab";
QString prevDest = destination;
sink.reset( QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Polygon, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context ) );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, context, fields, QgsWkbTypes::Polygon, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ) ) );
QVERIFY( sink.get() );
f = QgsFeature( fields );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Polygon((0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
@@ -1001,7 +1001,7 @@ void TestQgsProcessing::createFeatureSink()
// no extension, should default to shp
destination = QDir::tempPath() + "/create_feature_sink2";
prevDest = QDir::tempPath() + "/create_feature_sink2.shp";
sink.reset( QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Point25D, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context ) );
sink.reset( QgsProcessingUtils::createFeatureSink( destination, context, fields, QgsWkbTypes::Point25D, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ) ) );
QVERIFY( sink.get() );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "PointZ(1 2 3)" ) ) );
QVERIFY( sink->addFeature( f ) );

0 comments on commit d7aa3f5

Please sign in to comment.
You can’t perform that action at this time.