1 /*************************************************************************** 2 qgsprocessingutils.h 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 #ifndef QGSPROCESSINGUTILS_H 19 #define QGSPROCESSINGUTILS_H 20 21 #include "qgis_core.h" 22 23 #include "qgsrasterlayer.h" 24 #include "qgsmessagelog.h" 25 #include "qgsspatialindex.h" 26 #include "qgsprocessing.h" 27 #include "qgsfeaturesink.h" 28 #include "qgsfeaturesource.h" 29 #include "qgsproxyfeaturesink.h" 30 #include "qgsremappingproxyfeaturesink.h" 31 32 class QgsMeshLayer; 33 class QgsProject; 34 class QgsProcessingContext; 35 class QgsMapLayerStore; 36 class QgsProcessingFeedback; 37 class QgsProcessingFeatureSource; 38 class QgsProcessingAlgorithm; 39 class QgsVectorTileLayer; 40 41 #include <QString> 42 #include <QVariant> 43 44 /** 45 * \class QgsProcessingUtils 46 * \ingroup core 47 * \brief Utility functions for use with processing classes. 48 * \since QGIS 3.0 49 */ 50 class CORE_EXPORT QgsProcessingUtils 51 { 52 public: 53 54 /** 55 * Returns a list of raster layers from a \a project which are compatible with the processing 56 * framework. 57 * 58 * If the \a sort argument is TRUE then the layers will be sorted by their QgsMapLayer::name() 59 * value. 60 * \see compatibleVectorLayers() 61 * \see compatibleMeshLayers() 62 * \see compatibleLayers() 63 */ 64 static QList< QgsRasterLayer * > compatibleRasterLayers( QgsProject *project, bool sort = true ); 65 66 /** 67 * Returns a list of vector layers from a \a project which are compatible with the processing 68 * framework. 69 * 70 * The \a sourceTypes list should be filled with a list of QgsProcessing::SourceType values. 71 * If the \a sourceTypes list is non-empty then the layers will be sorted so that only 72 * layers with the specified source type included in the list will be returned. Leaving the \a sourceTypes 73 * list empty will cause all vector layers, regardless of their geometry type, to be returned. 74 * 75 * If the \a sort argument is TRUE then the layers will be sorted by their QgsMapLayer::name() 76 * value. 77 * \see compatibleRasterLayers() 78 * \see compatibleMeshLayers() 79 * \see compatibleLayers() 80 */ 81 static QList< QgsVectorLayer * > compatibleVectorLayers( QgsProject *project, 82 const QList< int > &sourceTypes = QList< int >(), 83 bool sort = true ); 84 85 /** 86 * Returns a list of mesh layers from a \a project which are compatible with the processing 87 * framework. 88 * 89 * If the \a sort argument is TRUE then the layers will be sorted by their QgsMapLayer::name() 90 * value. 91 * 92 * \see compatibleRasterLayers() 93 * \see compatibleVectorLayers() 94 * \see compatibleLayers() 95 * 96 * \since QGIS 3.6 97 */ 98 static QList<QgsMeshLayer *> compatibleMeshLayers( QgsProject *project, bool sort = true ); 99 100 /** 101 * Returns a list of map layers from a \a project which are compatible with the processing 102 * framework. 103 * 104 * If the \a sort argument is TRUE then the layers will be sorted by their QgsMapLayer::name() 105 * value. 106 * \see compatibleRasterLayers() 107 * \see compatibleVectorLayers() 108 */ 109 static QList< QgsMapLayer * > compatibleLayers( QgsProject *project, bool sort = true ); 110 111 /** 112 * Encodes a provider key and layer \a uri to a single string, for use with 113 * decodeProviderKeyAndUri() 114 * 115 * \since QGIS 3.14 116 */ 117 static QString encodeProviderKeyAndUri( const QString &providerKey, const QString &uri ); 118 119 /** 120 * Decodes a provider key and layer \a uri from an encoded string, for use with 121 * encodeProviderKeyAndUri() 122 * 123 * \param string encoded string, as returned by encodeProviderKeyAndUri() 124 * \param providerKey ID key for corresponding data provider 125 * \param uri decoded layer uri 126 * \returns TRUE if \a string was successfully decoded 127 * 128 * \since QGIS 3.14 129 */ 130 static bool decodeProviderKeyAndUri( const QString &string, QString &providerKey SIP_OUT, QString &uri SIP_OUT ); 131 132 /** 133 * Layer type hints. 134 * \since QGIS 3.4 135 */ 136 enum class LayerHint SIP_MONKEYPATCH_SCOPEENUM : int 137 { 138 UnknownType, //!< Unknown layer type 139 Vector, //!< Vector layer type 140 Raster, //!< Raster layer type 141 Mesh, //!< Mesh layer type, since QGIS 3.6 142 }; 143 144 /** 145 * Interprets a string as a map layer within the supplied \a context. 146 * 147 * The method will attempt to 148 * load a layer matching the passed \a string. E.g. if the string matches a layer ID or name 149 * within the context's project or temporary layer store then this layer will be returned. 150 * If the string is a file path and \a allowLoadingNewLayers is TRUE, then the layer at this 151 * file path will be loaded and added to the context's temporary layer store. 152 * Ownership of the layer remains with the \a context or the context's current project. 153 * 154 * The \a typeHint can be used to dictate the type of map layer expected. 155 */ 156 static QgsMapLayer *mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers = true, QgsProcessingUtils::LayerHint typeHint = QgsProcessingUtils::LayerHint::UnknownType ); 157 158 /** 159 * Converts a variant \a value to a new feature source. 160 * 161 * Sources will either be taken from \a context's active project, or loaded from external 162 * sources and stored temporarily in the \a context. 163 * 164 * The optional \a fallbackValue can be used to specify a "default" value which is used 165 * if \a value cannot be successfully converted to a source. 166 * 167 * This function creates a new object and the caller takes responsibility for deleting the returned object. 168 */ 169 static QgsProcessingFeatureSource *variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue = QVariant() ) SIP_FACTORY; 170 171 /** 172 * Converts a variant \a value to a coordinate reference system. 173 * 174 * The optional \a fallbackValue can be used to specify a "default" value which is used 175 * if \a value cannot be successfully converted to a CRS. 176 * 177 * \since QGIS 3.12 178 */ 179 static QgsCoordinateReferenceSystem variantToCrs( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue = QVariant() ); 180 181 /** 182 * Normalizes a layer \a source string for safe comparison across different 183 * operating system environments. 184 */ 185 static QString normalizeLayerSource( const QString &source ); 186 187 /** 188 * Converts a variant to a Python literal. 189 * 190 * \see stringToPythonLiteral() 191 * \since QGSIS 3.6 192 */ 193 static QString variantToPythonLiteral( const QVariant &value ); 194 195 /** 196 * Converts a string to a Python string literal. E.g. by replacing ' with \'. 197 * 198 * \see variantToPythonLiteral() 199 */ 200 static QString stringToPythonLiteral( const QString &string ); 201 202 /** 203 * Creates a feature sink ready for adding features. The \a destination specifies a destination 204 * URI for the resultant layer. It may be updated in place to reflect the actual destination 205 * for the layer. 206 * 207 * Sink parameters such as desired \a encoding, \a fields, \a geometryType and \a crs must be specified. 208 * 209 * The \a createOptions map can be used to specify additional sink creation options, which 210 * are passed to the underlying provider when creating new layers. Known options also 211 * include 'fileEncoding', which is used to specify a file encoding to use for created 212 * files. If 'fileEncoding' is not specified, the default encoding from the \a context will be used. 213 * 214 * If a layer is created for the feature sink, the layer will automatically be added to the \a context's 215 * temporary layer store. 216 * 217 * The caller takes responsibility for deleting the returned sink. 218 */ 219 #ifndef SIP_RUN 220 static QgsFeatureSink *createFeatureSink( QString &destination, 221 QgsProcessingContext &context, 222 const QgsFields &fields, 223 QgsWkbTypes::Type geometryType, 224 const QgsCoordinateReferenceSystem &crs, 225 const QVariantMap &createOptions = QVariantMap(), 226 const QStringList &datasourceOptions = QStringList(), 227 const QStringList &layerOptions = QStringList(), 228 QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags(), 229 QgsRemappingSinkDefinition *remappingDefinition = nullptr ) SIP_FACTORY; 230 #endif 231 232 /** 233 * Creates a feature sink ready for adding features. The \a destination specifies a destination 234 * URI for the resultant layer. It may be updated in place to reflect the actual destination 235 * for the layer. 236 * 237 * Sink parameters such as desired \a fields, \a geometryType and \a crs must be specified. 238 * 239 * The \a createOptions map can be used to specify additional sink creation options, which 240 * are passed to the underlying provider when creating new layers. Known options also 241 * include 'fileEncoding', which is used to specify a file encoding to use for created 242 * files. If 'fileEncoding' is not specified, the default encoding from the \a context will be used. 243 * 244 * If a layer is created for the feature sink, the layer will automatically be added to the \a context's 245 * temporary layer store. 246 * 247 * \note this version of the createFeatureSink() function has an API designed around use from the 248 * SIP bindings. c++ code should call the other createFeatureSink() version. 249 * \note available in Python bindings as createFeatureSink() 250 */ 251 static void createFeatureSinkPython( QgsFeatureSink **sink SIP_OUT SIP_TRANSFERBACK, QString &destination SIP_INOUT, QgsProcessingContext &context, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, const QVariantMap &createOptions = QVariantMap() ) SIP_THROW( QgsProcessingException ) SIP_PYNAME( createFeatureSink ); 252 253 254 /** 255 * Combines the extent of several map \a layers. If specified, the target \a crs 256 * will be used to transform the layer's extent to the desired output reference system 257 * using the specified \a context. 258 * \since QGIS 3.8 259 */ 260 static QgsRectangle combineLayerExtents( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context ); 261 262 /** 263 * Combines the extent of several map \a layers. If specified, the target \a crs 264 * will be used to transform the layer's extent to the desired output reference system. 265 * \deprecated Use version with QgsProcessingContext argument instead 266 */ 267 Q_DECL_DEPRECATED static QgsRectangle combineLayerExtents( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) SIP_DEPRECATED; 268 269 /** 270 * Converts an \a input parameter value for use in source iterating mode, where one individual sink 271 * is created per input feature. 272 * The \a id parameter represents the unique ID for this output, which is embedded into the resulting 273 * parameter value. 274 */ 275 static QVariant generateIteratingDestination( const QVariant &input, const QVariant &id, QgsProcessingContext &context ); 276 277 /** 278 * Returns a session specific processing temporary folder for use in processing algorithms. 279 * \see generateTempFilename() 280 */ 281 static QString tempFolder(); 282 283 /** 284 * Returns a temporary filename for a given file, putting it into 285 * a temporary folder (creating that folder in the process), 286 * but not changing the \a basename. 287 * \see tempFolder() 288 */ 289 static QString generateTempFilename( const QString &basename ); 290 291 /** 292 * Returns a HTML formatted version of the help text encoded in a variant \a map for 293 * a specified \a algorithm. 294 */ 295 static QString formatHelpMapAsHtml( const QVariantMap &map, const QgsProcessingAlgorithm *algorithm ); 296 297 /** 298 * Converts a source vector \a layer to a file path of a vector layer of compatible format. 299 * 300 * If the specified \a layer is not of the format listed in the 301 * \a compatibleFormats argument, then the layer will first be exported to a compatible format 302 * in a temporary location using \a baseName. The function will then return the path to that temporary file. 303 * 304 * \a compatibleFormats should consist entirely of lowercase file extensions, e.g. 'shp'. 305 * 306 * The \a preferredFormat argument is used to specify to desired file extension to use when a temporary 307 * layer export is required. This defaults to shapefiles. 308 * 309 * The \a featureLimit argument can be used to specify a limit on the number of features read from the layer. 310 * 311 * When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable 312 * to use convertToCompatibleFormatAndLayerName() which may avoid conversion in more situations. 313 * 314 * \see convertToCompatibleFormatAndLayerName() 315 */ 316 static QString convertToCompatibleFormat( const QgsVectorLayer *layer, 317 bool selectedFeaturesOnly, 318 const QString &baseName, 319 const QStringList &compatibleFormats, 320 const QString &preferredFormat, 321 QgsProcessingContext &context, 322 QgsProcessingFeedback *feedback, long long featureLimit = -1 ); 323 324 /** 325 * Converts a source vector \a layer to a file path and layer name of a vector layer of compatible format. 326 * 327 * If the specified \a layer is not of the format listed in the 328 * \a compatibleFormats argument, then the layer will first be exported to a compatible format 329 * in a temporary location using \a baseName. The function will then return the path to that temporary file. 330 * 331 * \a compatibleFormats should consist entirely of lowercase file extensions, e.g. 'shp'. 332 * 333 * The \a featureLimit argument can be used to specify a limit on the number of features read from the layer. 334 * 335 * The \a preferredFormat argument is used to specify to desired file extension to use when a temporary 336 * layer export is required. This defaults to shapefiles. 337 * 338 * This method should be preferred over convertToCompatibleFormat() when an algorithm is able 339 * to correctly handle files with multiple layers. Unlike convertToCompatibleFormat(), it will not force 340 * a conversion in this case and will return the target layer name in the \a layerName argument. 341 * 342 * \param layer source layer to convert (if required) 343 * \param selectedFeaturesOnly TRUE if only selected features from the layer should be used 344 * \param baseName base file name for converted layer, if required 345 * \param compatibleFormats a list of lowercase file extensions compatible with the algorithm 346 * \param preferredFormat preferred format extension to use if conversion if required 347 * \param context processing context 348 * \param feedback feedback object 349 * \param layerName will be set to the target layer name for multi-layer sources (e.g. Geopackage) 350 * \param featureLimit can be used to place a limit on the maximum number of features read from the layer 351 * 352 * \returns path to source layer, or nearly converted compatible layer 353 * 354 * \see convertToCompatibleFormat() 355 * \since QGIS 3.10 356 */ 357 static QString convertToCompatibleFormatAndLayerName( const QgsVectorLayer *layer, 358 bool selectedFeaturesOnly, 359 const QString &baseName, 360 const QStringList &compatibleFormats, 361 const QString &preferredFormat, 362 QgsProcessingContext &context, 363 QgsProcessingFeedback *feedback, 364 QString &layerName SIP_OUT, long long featureLimit = -1 ); 365 366 /** 367 * Combines two field lists, avoiding duplicate field names (in a case-insensitive manner). 368 * 369 * Duplicate field names will be altered to "name_2", "name_3", etc, finding the first 370 * non-duplicate name. 371 * 372 * \note Some output file formats (e.g. shapefiles) have restrictions on the maximum 373 * length of field names, so be aware that the results of calling this method may 374 * be truncated when saving to these formats. 375 */ 376 static QgsFields combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix = QString() ); 377 378 /** 379 * Returns a list of field indices parsed from the given list of field names. Unknown field names are ignored. 380 * If the list of field names is empty, it is assumed that all fields are required. 381 * \since QGIS 3.2 382 */ 383 static QList<int> fieldNamesToIndices( const QStringList &fieldNames, const QgsFields &fields ); 384 385 /** 386 * Returns a subset of fields based on the indices of desired fields. 387 * \since QGIS 3.2 388 */ 389 static QgsFields indicesToFields( const QList<int> &indices, const QgsFields &fields ); 390 391 /** 392 * Returns the default vector extension to use, in the absence of all other constraints (e.g. 393 * provider based support for extensions). 394 * 395 * This method returns the user-set default extension from the processing settings, or 396 * a fallback value of "gpkg". 397 * 398 * \see defaultRasterExtension() 399 * \since QGIS 3.10 400 */ 401 static QString defaultVectorExtension(); 402 403 /** 404 * Returns the default raster extension to use, in the absence of all other constraints (e.g. 405 * provider based support for extensions). 406 * 407 * This method returns the user-set default extension from the processing settings, or 408 * a fallback value of "tif". 409 * 410 * \see defaultVectorExtension() 411 * \since QGIS 3.10 412 */ 413 static QString defaultRasterExtension(); 414 415 private: 416 static bool canUseLayer( const QgsRasterLayer *layer ); 417 static bool canUseLayer( const QgsMeshLayer *layer ); 418 static bool canUseLayer( const QgsVectorTileLayer *layer ); 419 static bool canUseLayer( const QgsVectorLayer *layer, 420 const QList< int > &sourceTypes = QList< int >() ); 421 422 /** 423 * Interprets a \a string as a map layer from a store. 424 * 425 * This method attempts to match a string to a store map layer, using 426 * first the layer ID, then layer names, and finally layer source. 427 * If the string matches a normalized version of any layer source 428 * for layers in the specified \a store, then those matching layers will be 429 * returned. 430 * \see mapLayerFromString() 431 */ 432 static QgsMapLayer *mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint = QgsProcessingUtils::LayerHint::UnknownType ); 433 434 /** 435 * Interprets a string as a map layer. The method will attempt to 436 * load a layer matching the passed \a string using the given coordinate 437 * \a transformContext. 438 * E.g. if the string is a file path, 439 * then the layer at this file path will be loaded. 440 * The caller takes responsibility for deleting the returned map layer. 441 * 442 * \since QGIS 3.8 443 */ 444 static QgsMapLayer *loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint = LayerHint::UnknownType ); 445 446 /** 447 * Interprets a string as a map layer. The method will attempt to 448 * load a layer matching the passed \a string. E.g. if the string is a file path, 449 * then the layer at this file path will be loaded. 450 * The caller takes responsibility for deleting the returned map layer. 451 * 452 * \deprecated use mapLayerFromString() that takes QgsCoordinateTransformContext as an argument instead 453 */ 454 Q_DECL_DEPRECATED static QgsMapLayer *loadMapLayerFromString( const QString &string, LayerHint typeHint = LayerHint::UnknownType ) SIP_DEPRECATED ; 455 456 static void parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter, QString &extension ); 457 458 friend class TestQgsProcessing; 459 friend class QgsProcessingProvider; 460 461 }; 462 463 /** 464 * \class QgsProcessingFeatureSource 465 * \ingroup core 466 * \brief QgsFeatureSource subclass which proxies methods to an underlying QgsFeatureSource, modifying 467 * results according to the settings in a QgsProcessingContext. 468 * \since QGIS 3.0 469 */ 470 class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource 471 { 472 public: 473 474 //! Flags controlling how QgsProcessingFeatureSource fetches features 475 enum Flag 476 { 477 FlagSkipGeometryValidityChecks = 1 << 1, //!< Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always require invalid geometries, regardless of any user settings (e.g. "repair geometry" type algorithms). 478 }; 479 Q_DECLARE_FLAGS( Flags, Flag ) 480 481 /** 482 * Constructor for QgsProcessingFeatureSource, accepting an original feature source \a originalSource 483 * and processing \a context. 484 * Ownership of \a originalSource is dictated by \a ownsOriginalSource. If \a ownsOriginalSource is FALSE, 485 * ownership is not transferred, and callers must ensure that \a originalSource exists for the lifetime of this object. 486 * If \a ownsOriginalSource is TRUE, then this object will take ownership of \a originalSource. 487 * 488 * If \a featureLimit is set to a value > 0, then a limit is placed on the maximum number of features which will be 489 * read from the source. 490 */ 491 QgsProcessingFeatureSource( QgsFeatureSource *originalSource, const QgsProcessingContext &context, bool ownsOriginalSource = false, 492 long long featureLimit = -1 ); 493 494 ~QgsProcessingFeatureSource() override; 495 496 /** 497 * Returns an iterator for the features in the source, respecting the supplied feature \a flags. 498 * An optional \a request can be used to optimise the returned 499 * iterator, eg by restricting the returned attributes or geometry. 500 */ 501 QgsFeatureIterator getFeatures( const QgsFeatureRequest &request, Flags flags ) const; 502 503 QgsFeatureSource::FeatureAvailability hasFeatures() const override; 504 505 QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override; 506 QgsCoordinateReferenceSystem sourceCrs() const override; 507 QgsFields fields() const override; 508 QgsWkbTypes::Type wkbType() const override; 509 long featureCount() const override; 510 QString sourceName() const override; 511 QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override; 512 QVariant minimumValue( int fieldIndex ) const override; 513 QVariant maximumValue( int fieldIndex ) const override; 514 QgsRectangle sourceExtent() const override; 515 QgsFeatureIds allFeatureIds() const override; 516 SpatialIndexPresence hasSpatialIndex() const override; 517 518 /** 519 * Returns an expression context scope suitable for this source. 520 */ 521 QgsExpressionContextScope *createExpressionContextScope() const SIP_FACTORY; 522 523 /** 524 * Overrides the default geometry check method for the source. 525 * 526 * \since QGIS 3.14 527 */ 528 void setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck method ); 529 530 private: 531 532 QgsFeatureSource *mSource = nullptr; 533 bool mOwnsSource = false; 534 QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck; 535 std::function< void( const QgsFeature & ) > mInvalidGeometryCallback; 536 std::function< void( const QgsFeature & ) > mTransformErrorCallback; 537 538 std::function< void( const QgsFeature & ) > mInvalidGeometryCallbackSkip; 539 std::function< void( const QgsFeature & ) > mInvalidGeometryCallbackAbort; 540 541 long long mFeatureLimit = -1; 542 543 }; 544 545 #ifndef SIP_RUN 546 547 /** 548 * \class QgsProcessingFeatureSink 549 * \ingroup core 550 * \brief QgsProxyFeatureSink subclass which reports feature addition errors to a QgsProcessingContext. 551 * \note Not available in Python bindings. 552 * \since QGIS 3.0 553 */ 554 class CORE_EXPORT QgsProcessingFeatureSink : public QgsProxyFeatureSink 555 { 556 public: 557 558 559 /** 560 * Constructor for QgsProcessingFeatureSink, accepting an original feature sink \a originalSink 561 * and processing \a context. Any added features are added to the \a originalSink, with feature 562 * writing errors being reports to \a context. 563 * 564 * The \a context must exist for the lifetime of this object. 565 * 566 * The \a sinkName is used to identify the destination sink when reporting errors. 567 * 568 * Ownership of \a originalSink is dictated by \a ownsOriginalSource. If \a ownsOriginalSink is FALSE, 569 * ownership is not transferred, and callers must ensure that \a originalSink exists for the lifetime of this object. 570 * If \a ownsOriginalSink is TRUE, then this object will take ownership of \a originalSink. 571 */ 572 QgsProcessingFeatureSink( QgsFeatureSink *originalSink, const QString &sinkName, QgsProcessingContext &context, bool ownsOriginalSink = false ); 573 ~QgsProcessingFeatureSink() override; 574 bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override; 575 bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override; 576 bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override; 577 578 private: 579 580 QgsProcessingContext &mContext; 581 QString mSinkName; 582 bool mOwnsSink = false; 583 584 }; 585 #endif 586 587 #endif // QGSPROCESSINGUTILS_H 588 589 590