|
19 | 19 | #include "qgsproject.h"
|
20 | 20 | #include "qgssettings.h"
|
21 | 21 | #include "qgsprocessingcontext.h"
|
| 22 | +#include "qgsvectorlayerimport.h" |
| 23 | +#include "qgsvectorfilewriter.h" |
| 24 | +#include "qgsmemoryproviderutils.h" |
22 | 25 |
|
23 | 26 | QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
|
24 | 27 | {
|
@@ -289,4 +292,116 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
|
289 | 292 | }
|
290 | 293 | }
|
291 | 294 |
|
| 295 | +void parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &format, QMap<QString, QVariant> &options ) |
| 296 | +{ |
| 297 | + QRegularExpression splitRx( "^(.*?):(.*)$" ); |
| 298 | + QRegularExpressionMatch match = splitRx.match( destination ); |
| 299 | + if ( match.hasMatch() ) |
| 300 | + { |
| 301 | + providerKey = match.captured( 1 ); |
| 302 | + if ( providerKey == QStringLiteral( "postgis" ) ) // older processing used "postgis" instead of "postgres" |
| 303 | + { |
| 304 | + providerKey = QStringLiteral( "postgres" ); |
| 305 | + } |
| 306 | + uri = match.captured( 2 ); |
| 307 | + } |
| 308 | + else |
| 309 | + { |
| 310 | + providerKey = QStringLiteral( "ogr" ); |
| 311 | + QRegularExpression splitRx( "^(.*)\\.(.*?)$" ); |
| 312 | + QRegularExpressionMatch match = splitRx.match( destination ); |
| 313 | + QString extension; |
| 314 | + if ( match.hasMatch() ) |
| 315 | + { |
| 316 | + extension = match.captured( 2 ); |
| 317 | + format = QgsVectorFileWriter::driverForExtension( extension ); |
| 318 | + } |
| 319 | + |
| 320 | + if ( format.isEmpty() ) |
| 321 | + { |
| 322 | + format = QStringLiteral( "ESRI Shapefile" ); |
| 323 | + destination = destination + QStringLiteral( ".shp" ); |
| 324 | + } |
| 325 | + |
| 326 | + options.insert( QStringLiteral( "driverName" ), format ); |
| 327 | + uri = destination; |
| 328 | + } |
| 329 | +} |
| 330 | + |
| 331 | +QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QgsVectorLayer *&outputLayer ) |
| 332 | +{ |
| 333 | + outputLayer = nullptr; |
| 334 | + QgsVectorLayer *layer = nullptr; |
| 335 | + |
| 336 | + QString destEncoding = encoding; |
| 337 | + if ( destEncoding.isEmpty() ) |
| 338 | + { |
| 339 | + // no destination encoding specified, use default |
| 340 | + destEncoding = context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding(); |
| 341 | + } |
| 342 | + |
| 343 | + if ( destination.isEmpty() || destination.startsWith( QStringLiteral( "memory:" ) ) ) |
| 344 | + { |
| 345 | + // memory provider cannot be used with QgsVectorLayerImport - so create layer manually |
| 346 | + layer = QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs ); |
| 347 | + if ( layer && layer->isValid() ) |
| 348 | + destination = layer->id(); |
| 349 | + } |
| 350 | + else |
| 351 | + { |
| 352 | + QMap<QString, QVariant> options; |
| 353 | + options.insert( QStringLiteral( "fileEncoding" ), destEncoding ); |
| 354 | + |
| 355 | + QString providerKey; |
| 356 | + QString uri; |
| 357 | + QString format; |
| 358 | + parseDestinationString( destination, providerKey, uri, format, options ); |
| 359 | + |
| 360 | + if ( providerKey == "ogr" ) |
| 361 | + { |
| 362 | + // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows |
| 363 | + // us to use any OGR format which supports feature addition |
| 364 | + QString finalFileName; |
| 365 | + QgsVectorFileWriter *writer = new QgsVectorFileWriter( destination, destEncoding, fields, geometryType, crs, format, QgsVectorFileWriter::defaultDatasetOptions( format ), |
| 366 | + QgsVectorFileWriter::defaultLayerOptions( format ), &finalFileName ); |
| 367 | + destination = finalFileName; |
| 368 | + return writer; |
| 369 | + } |
| 370 | + else |
| 371 | + { |
| 372 | + //create empty layer |
| 373 | + { |
| 374 | + QgsVectorLayerImport import( uri, providerKey, fields, geometryType, crs, false, &options ); |
| 375 | + if ( import.hasError() ) |
| 376 | + return nullptr; |
| 377 | + } |
| 378 | + |
| 379 | + layer = new QgsVectorLayer( uri, destination, providerKey ); |
| 380 | + } |
| 381 | + } |
| 382 | + |
| 383 | + if ( !layer ) |
| 384 | + return nullptr; |
| 385 | + |
| 386 | + if ( !layer->isValid() ) |
| 387 | + { |
| 388 | + delete layer; |
| 389 | + return nullptr; |
| 390 | + } |
| 391 | + |
| 392 | + context.temporaryLayerStore()->addMapLayer( layer ); |
| 393 | + |
| 394 | + outputLayer = layer; |
| 395 | + // this is a factory, so we need to return a proxy |
| 396 | + return new QgsProxyFeatureSink( layer->dataProvider() ); |
| 397 | +} |
| 398 | + |
| 399 | +void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QgsVectorLayer **outputLayer ) |
| 400 | +{ |
| 401 | + QgsVectorLayer *layer = nullptr; |
| 402 | + *sink = createFeatureSink( destination, encoding, fields, geometryType, crs, context, layer ); |
| 403 | + if ( outputLayer ) |
| 404 | + *outputLayer = layer; |
| 405 | +} |
| 406 | + |
292 | 407 |
|
0 commit comments