QGIS API Documentation  3.0.2-Girona (307d082)
qgsprocessingutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingutils.cpp
3  ------------------------
4  begin : April 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsprocessingutils.h"
19 #include "qgsproject.h"
20 #include "qgssettings.h"
21 #include "qgsexception.h"
22 #include "qgsprocessingcontext.h"
23 #include "qgsvectorlayerexporter.h"
24 #include "qgsvectorfilewriter.h"
25 #include "qgsmemoryproviderutils.h"
27 #include "qgsprocessingalgorithm.h"
30 #include "qgsfileutils.h"
31 
32 QList<QgsRasterLayer *> QgsProcessingUtils::compatibleRasterLayers( QgsProject *project, bool sort )
33 {
34  if ( !project )
35  return QList<QgsRasterLayer *>();
36 
37  QList<QgsRasterLayer *> layers;
38  Q_FOREACH ( QgsRasterLayer *l, project->layers<QgsRasterLayer *>() )
39  {
40  if ( canUseLayer( l ) )
41  layers << l;
42  }
43 
44  if ( sort )
45  {
46  std::sort( layers.begin(), layers.end(), []( const QgsRasterLayer * a, const QgsRasterLayer * b ) -> bool
47  {
48  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
49  } );
50  }
51  return layers;
52 }
53 
54 QList<QgsVectorLayer *> QgsProcessingUtils::compatibleVectorLayers( QgsProject *project, const QList<QgsWkbTypes::GeometryType> &geometryTypes, bool sort )
55 {
56  if ( !project )
57  return QList<QgsVectorLayer *>();
58 
59  QList<QgsVectorLayer *> layers;
60  Q_FOREACH ( QgsVectorLayer *l, project->layers<QgsVectorLayer *>() )
61  {
62  if ( canUseLayer( l, geometryTypes ) )
63  layers << l;
64  }
65 
66  if ( sort )
67  {
68  std::sort( layers.begin(), layers.end(), []( const QgsVectorLayer * a, const QgsVectorLayer * b ) -> bool
69  {
70  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
71  } );
72  }
73  return layers;
74 }
75 
76 QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project, bool sort )
77 {
78  if ( !project )
79  return QList<QgsMapLayer *>();
80 
81  QList<QgsMapLayer *> layers;
82  Q_FOREACH ( QgsRasterLayer *rl, compatibleRasterLayers( project, false ) )
83  layers << rl;
84  Q_FOREACH ( QgsVectorLayer *vl, compatibleVectorLayers( project, QList< QgsWkbTypes::GeometryType >(), false ) )
85  layers << vl;
86 
87  if ( sort )
88  {
89  std::sort( layers.begin(), layers.end(), []( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
90  {
91  return QString::localeAwareCompare( a->name(), b->name() ) < 0;
92  } );
93  }
94  return layers;
95 }
96 
97 QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store )
98 {
99  if ( !store || string.isEmpty() )
100  return nullptr;
101 
102  QList< QgsMapLayer * > layers = store->mapLayers().values();
103 
104  layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
105  {
106  switch ( layer->type() )
107  {
109  return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
111  return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
113  return true;
114  }
115  return true;
116  } ), layers.end() );
117 
118  Q_FOREACH ( QgsMapLayer *l, layers )
119  {
120  if ( l->id() == string )
121  return l;
122  }
123  Q_FOREACH ( QgsMapLayer *l, layers )
124  {
125  if ( l->name() == string )
126  return l;
127  }
128  Q_FOREACH ( QgsMapLayer *l, layers )
129  {
130  if ( normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
131  return l;
132  }
133  return nullptr;
134 }
135 
137 class ProjectionSettingRestorer
138 {
139  public:
140 
141  ProjectionSettingRestorer()
142  {
143  QgsSettings settings;
144  previousSetting = settings.value( QStringLiteral( "/Projections/defaultBehavior" ) ).toString();
145  settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), QStringLiteral( "useProject" ) );
146  }
147 
148  ~ProjectionSettingRestorer()
149  {
150  QgsSettings settings;
151  settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), previousSetting );
152  }
153 
154  QString previousSetting;
155 };
157 
158 QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string )
159 {
160  QStringList components = string.split( '|' );
161  if ( components.isEmpty() )
162  return nullptr;
163 
164  QFileInfo fi;
165  if ( QFileInfo::exists( string ) )
166  fi = QFileInfo( string );
167  else if ( QFileInfo::exists( components.at( 0 ) ) )
168  fi = QFileInfo( components.at( 0 ) );
169  else
170  return nullptr;
171 
172  // TODO - remove when there is a cleaner way to block the unknown projection dialog!
173  ProjectionSettingRestorer restorer;
174  ( void )restorer; // no warnings
175 
176  QString name = fi.baseName();
177 
178  // brute force attempt to load a matching layer
180  options.loadDefaultStyle = false;
181  std::unique_ptr< QgsVectorLayer > layer( new QgsVectorLayer( string, name, QStringLiteral( "ogr" ), options ) );
182  if ( layer->isValid() )
183  {
184  return layer.release();
185  }
186  QgsRasterLayer::LayerOptions rasterOptions;
187  rasterOptions.loadDefaultStyle = false;
188  std::unique_ptr< QgsRasterLayer > rasterLayer( new QgsRasterLayer( string, name, QStringLiteral( "gdal" ), rasterOptions ) );
189  if ( rasterLayer->isValid() )
190  {
191  return rasterLayer.release();
192  }
193  return nullptr;
194 }
195 
196 QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers )
197 {
198  if ( string.isEmpty() )
199  return nullptr;
200 
201  // prefer project layers
202  QgsMapLayer *layer = nullptr;
203  if ( context.project() )
204  {
205  QgsMapLayer *layer = mapLayerFromStore( string, context.project()->layerStore() );
206  if ( layer )
207  return layer;
208  }
209 
210  layer = mapLayerFromStore( string, context.temporaryLayerStore() );
211  if ( layer )
212  return layer;
213 
214  if ( !allowLoadingNewLayers )
215  return nullptr;
216 
217  layer = loadMapLayerFromString( string );
218  if ( layer )
219  {
220  context.temporaryLayerStore()->addMapLayer( layer );
221  return layer;
222  }
223  else
224  {
225  return nullptr;
226  }
227 }
228 
229 QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue )
230 {
231  QVariant val = value;
232  bool selectedFeaturesOnly = false;
233  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
234  {
235  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
237  selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
238  val = fromVar.source;
239  }
240 
241  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) ) )
242  {
243  return new QgsProcessingFeatureSource( layer, context );
244  }
245 
246  QString layerRef;
247  if ( val.canConvert<QgsProperty>() )
248  {
249  layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), fallbackValue.toString() );
250  }
251  else if ( !val.isValid() || val.toString().isEmpty() )
252  {
253  // fall back to default
254  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( fallbackValue ) ) )
255  {
256  return new QgsProcessingFeatureSource( layer, context );
257  }
258 
259  layerRef = fallbackValue.toString();
260  }
261  else
262  {
263  layerRef = val.toString();
264  }
265 
266  if ( layerRef.isEmpty() )
267  return nullptr;
268 
269  QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context ) );
270  if ( !vl )
271  return nullptr;
272 
273  if ( selectedFeaturesOnly )
274  {
275  return new QgsProcessingFeatureSource( new QgsVectorLayerSelectedFeatureSource( vl ), context, true );
276  }
277  else
278  {
279  return new QgsProcessingFeatureSource( vl, context );
280  }
281 }
282 
283 bool QgsProcessingUtils::canUseLayer( const QgsRasterLayer *layer )
284 {
285  // only gdal file-based layers
286  return layer && layer->providerType() == QStringLiteral( "gdal" );
287 }
288 
289 bool QgsProcessingUtils::canUseLayer( const QgsVectorLayer *layer, const QList<QgsWkbTypes::GeometryType> &geometryTypes )
290 {
291  return layer &&
292  ( geometryTypes.isEmpty() || geometryTypes.contains( layer->geometryType() ) );
293 }
294 
295 QString QgsProcessingUtils::normalizeLayerSource( const QString &source )
296 {
297  QString normalized = source;
298  normalized.replace( '\\', '/' );
299  return normalized.trimmed();
300 }
301 
302 QString QgsProcessingUtils::stringToPythonLiteral( const QString &string )
303 {
304  QString s = string;
305  s.replace( '"', QStringLiteral( "\\\"" ) );
306  s.replace( '\'', QStringLiteral( "\\\'" ) );
307  s = s.prepend( '\'' ).append( '\'' );
308  return s;
309 }
310 
311 void QgsProcessingUtils::parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter )
312 {
313  QRegularExpression splitRx( QStringLiteral( "^(.{3,}?):(.*)$" ) );
314  QRegularExpressionMatch match = splitRx.match( destination );
315  if ( match.hasMatch() )
316  {
317  providerKey = match.captured( 1 );
318  if ( providerKey == QStringLiteral( "postgis" ) ) // older processing used "postgis" instead of "postgres"
319  {
320  providerKey = QStringLiteral( "postgres" );
321  }
322  uri = match.captured( 2 );
323  if ( providerKey == QLatin1String( "ogr" ) )
324  {
325  QgsDataSourceUri dsUri( uri );
326  if ( !dsUri.database().isEmpty() )
327  {
328  if ( !dsUri.table().isEmpty() )
329  {
330  layerName = dsUri.table();
331  options.insert( "layerName", layerName );
332  }
333  uri = dsUri.database();
334  }
335  options.insert( QStringLiteral( "update" ), true );
336  }
337  useWriter = false;
338  }
339  else
340  {
341  useWriter = true;
342  providerKey = QStringLiteral( "ogr" );
343  QRegularExpression splitRx( QStringLiteral( "^(.*)\\.(.*?)$" ) );
344  QRegularExpressionMatch match = splitRx.match( destination );
345  QString extension;
346  if ( match.hasMatch() )
347  {
348  extension = match.captured( 2 );
349  format = QgsVectorFileWriter::driverForExtension( extension );
350  }
351 
352  if ( format.isEmpty() )
353  {
354  format = QStringLiteral( "GPKG" );
355  destination = destination + QStringLiteral( ".gpkg" );
356  }
357 
358  options.insert( QStringLiteral( "driverName" ), format );
359  uri = destination;
360  }
361 }
362 
363 QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions )
364 {
365  QVariantMap options = createOptions;
366  if ( !options.contains( QStringLiteral( "fileEncoding" ) ) )
367  {
368  // no destination encoding specified, use default
369  options.insert( QStringLiteral( "fileEncoding" ), context.defaultEncoding().isEmpty() ? QStringLiteral( "system" ) : context.defaultEncoding() );
370  }
371 
372  if ( destination.isEmpty() || destination.startsWith( QStringLiteral( "memory:" ) ) )
373  {
374  // strip "memory:" from start of destination
375  if ( destination.startsWith( QStringLiteral( "memory:" ) ) )
376  destination = destination.mid( 7 );
377 
378  if ( destination.isEmpty() )
379  destination = QStringLiteral( "output" );
380 
381  // memory provider cannot be used with QgsVectorLayerImport - so create layer manually
382  std::unique_ptr< QgsVectorLayer > layer( QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs ) );
383  if ( !layer || !layer->isValid() )
384  {
385  throw QgsProcessingException( QObject::tr( "Could not create memory layer" ) );
386  }
387 
388  // update destination to layer ID
389  destination = layer->id();
390 
391  // this is a factory, so we need to return a proxy
392  std::unique_ptr< QgsProcessingFeatureSink > sink( new QgsProcessingFeatureSink( layer->dataProvider(), destination, context ) );
393  context.temporaryLayerStore()->addMapLayer( layer.release() );
394 
395  return sink.release();
396  }
397  else
398  {
399  QString providerKey;
400  QString uri;
401  QString layerName;
402  QString format;
403  bool useWriter = false;
404  parseDestinationString( destination, providerKey, uri, layerName, format, options, useWriter );
405 
406  if ( useWriter && providerKey == QLatin1String( "ogr" ) )
407  {
408  // use QgsVectorFileWriter for OGR destinations instead of QgsVectorLayerImport, as that allows
409  // us to use any OGR format which supports feature addition
410  QString finalFileName;
411  std::unique_ptr< QgsVectorFileWriter > writer = qgis::make_unique< QgsVectorFileWriter >( destination, options.value( QStringLiteral( "fileEncoding" ) ).toString(), fields, geometryType, crs, format, QgsVectorFileWriter::defaultDatasetOptions( format ),
412  QgsVectorFileWriter::defaultLayerOptions( format ), &finalFileName );
413 
414  if ( writer->hasError() )
415  {
416  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, writer->errorMessage() ) );
417  }
418  destination = finalFileName;
419  return new QgsProcessingFeatureSink( writer.release(), destination, context, true );
420  }
421  else
422  {
423  //create empty layer
424  std::unique_ptr< QgsVectorLayerExporter > exporter( new QgsVectorLayerExporter( uri, providerKey, fields, geometryType, crs, true, options ) );
425  if ( exporter->errorCode() )
426  {
427  throw QgsProcessingException( QObject::tr( "Could not create layer %1: %2" ).arg( destination, exporter->errorMessage() ) );
428  }
429 
430  // use destination string as layer name (eg "postgis:..." )
431  if ( !layerName.isEmpty() )
432  uri += QStringLiteral( "|layername=%1" ).arg( layerName );
433  std::unique_ptr< QgsVectorLayer > layer( new QgsVectorLayer( uri, destination, providerKey ) );
434  // update destination to layer ID
435  destination = layer->id();
436 
437  context.temporaryLayerStore()->addMapLayer( layer.release() );
438  return new QgsProcessingFeatureSink( exporter.release(), destination, context, true );
439  }
440  }
441  return nullptr;
442 }
443 
444 void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &options )
445 {
446  *sink = createFeatureSink( destination, context, fields, geometryType, crs, options );
447 }
448 
449 
451 {
452  QgsRectangle extent;
453  Q_FOREACH ( QgsMapLayer *layer, layers )
454  {
455  if ( !layer )
456  continue;
457 
458  if ( crs.isValid() )
459  {
460  //transform layer extent to target CRS
462  QgsCoordinateTransform ct( layer->crs(), crs );
464  try
465  {
466  QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
467  extent.combineExtentWith( reprojExtent );
468  }
469  catch ( QgsCsException & )
470  {
471  // can't reproject... what to do here? hmmm?
472  // let's ignore this layer for now, but maybe we should just use the original extent?
473  }
474  }
475  else
476  {
477  extent.combineExtentWith( layer->extent() );
478  }
479 
480  }
481  return extent;
482 }
483 
484 QVariant QgsProcessingUtils::generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context )
485 {
486  if ( !input.isValid() )
487  return QStringLiteral( "memory:%1" ).arg( id.toString() );
488 
489  if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
490  {
492  QVariant newSink = generateIteratingDestination( fromVar.sink, id, context );
493  fromVar.sink = QgsProperty::fromValue( newSink );
494  return fromVar;
495  }
496  else if ( input.canConvert<QgsProperty>() )
497  {
498  QString res = input.value< QgsProperty>().valueAsString( context.expressionContext() );
499  return generateIteratingDestination( res, id, context );
500  }
501  else
502  {
503  QString res = input.toString();
504  if ( res.startsWith( QStringLiteral( "memory:" ) ) )
505  {
506  return res + '_' + id.toString();
507  }
508  else
509  {
510  // assume a filename type output for now
511  // TODO - uris?
512  int lastIndex = res.lastIndexOf( '.' );
513  return res.left( lastIndex ) + '_' + id.toString() + res.mid( lastIndex );
514  }
515  }
516 }
517 
519 {
520  static QString sFolder;
521  static QMutex sMutex;
522  sMutex.lock();
523  if ( sFolder.isEmpty() )
524  {
525  QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
526  sFolder = QDir::tempPath() + QStringLiteral( "/processing_" ) + subPath;
527  if ( !QDir( sFolder ).exists() )
528  QDir().mkpath( sFolder );
529  }
530  sMutex.unlock();
531  return sFolder;
532 }
533 
534 QString QgsProcessingUtils::generateTempFilename( const QString &basename )
535 {
536  QString subPath = QUuid::createUuid().toString().remove( '-' ).remove( '{' ).remove( '}' );
537  QString path = tempFolder() + '/' + subPath;
538  if ( !QDir( path ).exists() ) //make sure the directory exists - it shouldn't, but lets be safe...
539  {
540  QDir tmpDir;
541  tmpDir.mkdir( path );
542  }
543  return path + '/' + QgsFileUtils::stringToSafeFilename( basename );
544 }
545 
546 QString QgsProcessingUtils::formatHelpMapAsHtml( const QVariantMap &map, const QgsProcessingAlgorithm *algorithm )
547 {
548  auto getText = [map]( const QString & key )->QString
549  {
550  if ( map.contains( key ) )
551  return map.value( key ).toString();
552  return QString();
553  };
554 
555  QString s = QObject::tr( "<html><body><h2>Algorithm description</h2>\n" );
556  s += QStringLiteral( "<p>" ) + getText( QStringLiteral( "ALG_DESC" ) ) + QStringLiteral( "</p>\n" );
557  s += QObject::tr( "<h2>Input parameters</h2>\n" );
558 
559  Q_FOREACH ( const QgsProcessingParameterDefinition *def, algorithm->parameterDefinitions() )
560  {
561  s += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
562  s += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
563  }
564  s += QObject::tr( "<h2>Outputs</h2>\n" );
565  Q_FOREACH ( const QgsProcessingOutputDefinition *def, algorithm->outputDefinitions() )
566  {
567  s += QStringLiteral( "<h3>" ) + def->description() + QStringLiteral( "</h3>\n" );
568  s += QStringLiteral( "<p>" ) + getText( def->name() ) + QStringLiteral( "</p>\n" );
569  }
570  s += QLatin1String( "<br>" );
571  s += QObject::tr( "<p align=\"right\">Algorithm author: %1</p>" ).arg( getText( QStringLiteral( "ALG_CREATOR" ) ) );
572  s += QObject::tr( "<p align=\"right\">Help author: %1</p>" ).arg( getText( QStringLiteral( "ALG_HELP_CREATOR" ) ) );
573  s += QObject::tr( "<p align=\"right\">Algorithm version: %1</p>" ).arg( getText( QStringLiteral( "ALG_VERSION" ) ) );
574  s += QStringLiteral( "</body></html>" );
575  return s;
576 }
577 
578 QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
579 {
580  bool requiresTranslation = selectedFeaturesOnly;
581  if ( !selectedFeaturesOnly )
582  {
583  QFileInfo fi( vl->source() );
584  requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
585  }
586 
587  if ( requiresTranslation )
588  {
589  QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat );
590 
591  QgsVectorFileWriter writer( temp, context.defaultEncoding(),
592  vl->fields(), vl->wkbType(), vl->crs(), QgsVectorFileWriter::driverForExtension( preferredFormat ) );
593  QgsFeature f;
595  if ( selectedFeaturesOnly )
596  it = vl->getSelectedFeatures();
597  else
598  it = vl->getFeatures();
599 
600  while ( it.nextFeature( f ) )
601  {
602  if ( feedback->isCanceled() )
603  return QString();
604  writer.addFeature( f, QgsFeatureSink::FastInsert );
605  }
606  return temp;
607  }
608  else
609  {
610  return vl->source();
611  }
612 }
613 
615 {
616  QgsFields outFields = fieldsA;
617  QSet< QString > usedNames;
618  for ( const QgsField &f : fieldsA )
619  {
620  usedNames.insert( f.name().toLower() );
621  }
622 
623  for ( const QgsField &f : fieldsB )
624  {
625  if ( usedNames.contains( f.name().toLower() ) )
626  {
627  int idx = 2;
628  QString newName = f.name() + '_' + QString::number( idx );
629  while ( usedNames.contains( newName.toLower() ) )
630  {
631  idx++;
632  newName = f.name() + '_' + QString::number( idx );
633  }
634  QgsField newField = f;
635  newField.setName( newName );
636  outFields.append( newField );
637  usedNames.insert( newName.toLower() );
638  }
639  else
640  {
641  usedNames.insert( f.name().toLower() );
642  outFields.append( f );
643  }
644  }
645 
646  return outFields;
647 }
648 
649 
650 //
651 // QgsProcessingFeatureSource
652 //
653 
654 QgsProcessingFeatureSource::QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource )
655  : mSource( originalSource )
656  , mOwnsSource( ownsOriginalSource )
657  , mInvalidGeometryCheck( context.invalidGeometryCheck() )
658  , mInvalidGeometryCallback( context.invalidGeometryCallback() )
659  , mTransformErrorCallback( context.transformErrorCallback() )
660 {}
661 
663 {
664  if ( mOwnsSource )
665  delete mSource;
666 }
667 
669 {
670  QgsFeatureRequest req( request );
671  req.setTransformErrorCallback( mTransformErrorCallback );
672 
673  if ( flags & FlagSkipGeometryValidityChecks )
675  else
676  {
677  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
678  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
679  }
680 
681  return mSource->getFeatures( req );
682 }
683 
685 {
686  QgsFeatureRequest req( request );
687  req.setInvalidGeometryCheck( mInvalidGeometryCheck );
688  req.setInvalidGeometryCallback( mInvalidGeometryCallback );
689  req.setTransformErrorCallback( mTransformErrorCallback );
690  return mSource->getFeatures( req );
691 }
692 
694 {
695  return mSource->sourceCrs();
696 }
697 
699 {
700  return mSource->fields();
701 }
702 
704 {
705  return mSource->wkbType();
706 }
707 
709 {
710  return mSource->featureCount();
711 }
712 
714 {
715  return mSource->sourceName();
716 
717 }
718 
719 QSet<QVariant> QgsProcessingFeatureSource::uniqueValues( int fieldIndex, int limit ) const
720 {
721  return mSource->uniqueValues( fieldIndex, limit );
722 }
723 
724 QVariant QgsProcessingFeatureSource::minimumValue( int fieldIndex ) const
725 {
726  return mSource->minimumValue( fieldIndex );
727 }
728 
729 QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const
730 {
731  return mSource->maximumValue( fieldIndex );
732 }
733 
735 {
736  return mSource->sourceExtent();
737 }
738 
740 {
741  return mSource->allFeatureIds();
742 }
743 
745 {
746  QgsExpressionContextScope *expressionContextScope = nullptr;
747  QgsExpressionContextScopeGenerator *generator = dynamic_cast<QgsExpressionContextScopeGenerator *>( mSource );
748  if ( generator )
749  {
750  expressionContextScope = generator->createExpressionContextScope();
751  }
752  return expressionContextScope;
753 }
754 
755 
756 //
757 // QgsProcessingFeatureSink
758 //
759 QgsProcessingFeatureSink::QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink )
760  : QgsProxyFeatureSink( originalSink )
761  , mContext( context )
762  , mSinkName( sinkName )
763  , mOwnsSink( ownsOriginalSink )
764 {}
765 
767 {
768  if ( mOwnsSink )
769  delete destinationSink();
770 }
771 
772 bool QgsProcessingFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
773 {
774  bool result = QgsProxyFeatureSink::addFeature( feature, flags );
775  if ( !result )
776  mContext.feedback()->reportError( QObject::tr( "Feature could not be written to %1" ).arg( mSinkName ) );
777  return result;
778 }
779 
780 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
781 {
782  bool result = QgsProxyFeatureSink::addFeatures( features, flags );
783  if ( !result )
784  mContext.feedback()->reportError( QObject::tr( "%1 feature(s) could not be written to %2" ).arg( features.count() ).arg( mSinkName ) );
785  return result;
786 }
787 
788 bool QgsProcessingFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
789 {
790  bool result = !QgsProxyFeatureSink::addFeatures( iterator, flags );
791  if ( !result )
792  mContext.feedback()->reportError( QObject::tr( "Features could not be written to %2" ).arg( mSinkName ) );
793  return result;
794 }
QgsProperty sink
Sink/layer definition.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true)
Interprets a string as a map layer within the supplied context.
Wrapper for iterator of features from vector data provider or vector layer.
virtual QgsRectangle sourceExtent() const
Returns the extent of all geometries from the source.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
A rectangle specified with double values.
Definition: qgsrectangle.h:39
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
Base class for all map layer types.
Definition: qgsmaplayer.h:56
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
QString table() const
Returns the table.
QString description() const
Returns the description for the output.
QgsFeatureRequest & setInvalidGeometryCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering an invalid geometry and invalidGeometryCheck() is s...
Base class for providing feedback from a processing algorithm.
QgsProcessingParameterDefinitions parameterDefinitions() const
Returns an ordered list of parameter definitions utilized by the algorithm.
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
virtual QgsFields fields() const =0
Returns the fields associated with features in the source.
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm...
A simple feature sink which proxies feature addition on to another feature sink.
static QgsRectangle combineLayerExtents(const QList< QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Combines the extent of several map layers.
QgsFeatureRequest & setInvalidGeometryCheck(InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
QgsProcessingFeatureSource(QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource=false)
Constructor for QgsProcessingFeatureSource, accepting an original feature source originalSource and p...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:57
Setting options for loading vector layers.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:549
QString name() const
Returns the name of the output.
QgsFeatureIds allFeatureIds() const override
Returns a list of all feature IDs for features present in the source.
virtual QgsWkbTypes::Type wkbType() const =0
Returns the geometry type for features returned by this source.
An interface for objects which accept features via addFeature(s) methods.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:516
static QList< QgsRasterLayer *> compatibleRasterLayers(QgsProject *project, bool sort=true)
Returns a list of raster layers from a project which are compatible with the processing framework...
static QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsFeatureSource subclass which proxies methods to an underlying QgsFeatureSource, modifying results according to the settings in a QgsProcessingContext.
Container of fields for a vector layer.
Definition: qgsfields.h:42
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:134
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
static QString driverForExtension(const QString &extension)
Returns the OGR driver name for a specified file extension.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request, Flags flags) const
Returns an iterator for the features in the source, respecting the supplied feature flags...
A convenience class for writing vector files to disk.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
QVariant maximumValue(int fieldIndex) const override
Returns the maximum value for an attribute column or an invalid variant in case of error...
static QString convertToCompatibleFormat(const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback)
Converts a source vector layer to a file path to a vector layer of compatible format.
QgsRectangle sourceExtent() const override
Returns the extent of all geometries from the source.
static QString normalizeLayerSource(const QString &source)
Normalizes a layer source string for safe comparison across different operating system environments...
Abstract base class for processing algorithms.
QgsMapLayerStore * layerStore()
Returns a pointer to the project&#39;s internal layer store.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
bool selectedFeaturesOnly
True if only selected features in the source should be used by algorithms.
virtual QgsRectangle extent() const
Returns the extent of the layer.
static void createFeatureSinkPython(QgsFeatureSink **sink, QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap())
Creates a feature sink ready for adding features.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const override
Returns the set of unique values contained within the specified fieldIndex from this source...
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QgsProcessingFeedback * feedback()
Returns the associated feedback object.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
virtual QVariant minimumValue(int fieldIndex) const
Returns the minimum value for an attribute column or an invalid variant in case of error...
QgsFields fields() const override
Returns the fields associated with features in the source.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution...
QgsProperty source
Source definition.
static QgsFeatureSink * createFeatureSink(QString &destination, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions=QVariantMap())
Creates a feature sink ready for adding features.
QgsFields fields() const override
Returns the list of fields of this layer.
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
QVariant minimumValue(int fieldIndex) const override
Returns the minimum value for an attribute column or an invalid variant in case of error...
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Get an iterator of the selected features.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB)
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an &#39;...
bool loadDefaultStyle
Set to true if the default layer style should be loaded.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
QgsWkbTypes::Type wkbType() const override
Returns the WKBType or WKBUnknown in case of error.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
static QList< QgsMapLayer *> compatibleLayers(QgsProject *project, bool sort=true)
Returns a list of map layers from a project which are compatible with the processing framework...
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:59
Reads and writes project states.
Definition: qgsproject.h:82
No invalid geometry checking.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a single feature to the sink.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsProcessingFeatureSource * variantToSource(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a new feature source.
A store for object properties.
Definition: qgsproperty.h:229
virtual QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const
Returns the set of unique values contained within the specified fieldIndex from this source...
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsFeatureRequest & setTransformErrorCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering a transform error when iterating features and a des...
A convenience class for exporting vector layers to a destination data provider.
static QString tempFolder()
Returns a session specific processing temporary folder for use in processing algorithms.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
QString name() const
Returns the name of the parameter.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
QgsExpressionContextScope * createExpressionContextScope() const
Returns an expression context scope suitable for this source.
Encapsulates settings relating to a feature source input to a processing algorithm.
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
static QString generateTempFilename(const QString &basename)
Returns a temporary filename for a given file, putting it into a temporary folder (creating that fold...
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
Base class for the definition of processing outputs.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:517
QgsProxyFeatureSink subclass which reports feature addition errors to a QgsProcessingContext.
static QString formatHelpMapAsHtml(const QVariantMap &map, const QgsProcessingAlgorithm *algorithm)
Returns a HTML formatted version of the help text encoded in a variant map for a specified algorithm...
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
Definition: qgsproject.h:649
virtual QgsExpressionContextScope * createExpressionContextScope() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QMap< QString, QgsMapLayer * > mapLayers() const
Returns a map of all layers by layer ID.
QgsFeatureSource subclass for the selected features from a QgsVectorLayer.
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Abstract interface for generating an expression context scope.
QString defaultEncoding() const
Returns the default encoding to use for newly created files.
An interface for objects which provide features via a getFeatures method.
QString source() const
Returns the source for the layer.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
static QVariant generateIteratingDestination(const QVariant &input, const QVariant &id, QgsProcessingContext &context)
Converts an input parameter value for use in source iterating mode, where one individual sink is crea...
QString sourceName() const override
Returns a friendly display name for the source.
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
This class represents a coordinate reference system (CRS).
Base class for the definition of processing parameters.
Class for doing transforms between two map coordinate systems.
QString name
Definition: qgsmaplayer.h:60
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
static QList< QgsVectorLayer *> compatibleVectorLayers(QgsProject *project, const QList< QgsWkbTypes::GeometryType > &geometryTypes=QList< QgsWkbTypes::GeometryType >(), bool sort=true)
Returns a list of vector layers from a project which are compatible with the processing framework...
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a single feature to the sink.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, QgsWkbTypes::Type geometryType=QgsWkbTypes::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Creates a new memory layer using the specified parameters.
virtual QVariant maximumValue(int fieldIndex) const
Returns the maximum value for an attribute column or an invalid variant in case of error...
bool nextFeature(QgsFeature &f)
QgsFeatureSink * destinationSink()
Returns the destination QgsFeatureSink which the proxy will forward features to.
virtual QString sourceName() const =0
Returns a friendly display name for the source.
long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown...
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
Represents a vector layer which manages a vector based data sets.
virtual QgsFeatureIds allFeatureIds() const
Returns a list of all feature IDs for features present in the source.
Contains information about the context in which a processing algorithm is executed.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
QString description() const
Returns the description for the parameter.
QString database() const
Returns the database.
Setting options for loading raster layers.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
virtual long featureCount() const =0
Returns the number of features contained in the source, or -1 if the feature count is unknown...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsProcessingFeatureSink(QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink=false)
Constructor for QgsProcessingFeatureSink, accepting an original feature sink originalSink and process...