QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsalgorithmsavefeatures.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmsavefeatures.cpp
3  ---------------------
4  begin : July 2020
5  copyright : (C) 2020 by Mathieu Pellerin
6  email : nirvn dot asia 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 
19 #include "qgsvectorfilewriter.h"
20 #include <QRegularExpression>
21 
23 
24 QString QgsSaveFeaturesAlgorithm::name() const
25 {
26  return QStringLiteral( "savefeatures" );
27 }
28 
29 QString QgsSaveFeaturesAlgorithm::displayName() const
30 {
31  return QObject::tr( "Save vector features to file" );
32 }
33 
34 QStringList QgsSaveFeaturesAlgorithm::tags() const
35 {
36  return QObject::tr( "save,write,export" ).split( ',' );
37 }
38 
39 QString QgsSaveFeaturesAlgorithm::group() const
40 {
41  return QObject::tr( "Vector general" );
42 }
43 
44 QString QgsSaveFeaturesAlgorithm::groupId() const
45 {
46  return QStringLiteral( "vectorgeneral" );
47 }
48 
49 QString QgsSaveFeaturesAlgorithm::shortHelpString() const
50 {
51  return QObject::tr( "This algorithm saves vector features to a specified file dataset.\n\n"
52  "For dataset formats supporting layers, an optional layer name parameter can be used to specify a custom string.\n\n"
53  "Optional GDAL-defined dataset and layer options can be specified. For more information on this, "
54  "read the online GDAL documentation." );
55 }
56 
57 QgsSaveFeaturesAlgorithm *QgsSaveFeaturesAlgorithm::createInstance() const
58 {
59  return new QgsSaveFeaturesAlgorithm();
60 }
61 
62 void QgsSaveFeaturesAlgorithm::initAlgorithm( const QVariantMap & )
63 {
64  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector features" ) ) );
65  addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Saved features" ), QgsVectorFileWriter::fileFilterString(), QVariant(), false ) );
66 
67  std::unique_ptr< QgsProcessingParameterString > param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Layer name" ), QVariant(), false, true );
68  param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
69  addParameter( param.release() );
70  param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "DATASOURCE_OPTIONS" ), QObject::tr( "GDAL dataset options (separate individual options with semicolons)" ), QVariant(), false, true );
71  param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
72  addParameter( param.release() );
73  param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "LAYER_OPTIONS" ), QObject::tr( "GDAL layer options (separate individual options with semicolons)" ), QVariant(), false, true );
74  param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
75  addParameter( param.release() );
76 
77  addOutput( new QgsProcessingOutputString( QStringLiteral( "FILE_PATH" ), QObject::tr( "File name and path" ) ) );
78  addOutput( new QgsProcessingOutputString( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Layer name" ) ) );
79 }
80 
81 QVariantMap QgsSaveFeaturesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
82 {
83  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
84 
85  QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context ).trimmed();
86  QVariantMap createOptions;
87  if ( !layerName.isEmpty() )
88  {
89  createOptions[QStringLiteral( "layerName" )] = layerName;
90  }
91 
92 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
93  QStringList datasourceOptions = parameterAsString( parameters, QStringLiteral( "DATASOURCE_OPTIONS" ), context ).trimmed().split( ';', QString::SkipEmptyParts );
94  QStringList layerOptions = parameterAsString( parameters, QStringLiteral( "LAYER_OPTIONS" ), context ).trimmed().split( ';', QString::SkipEmptyParts );
95 #else
96  QStringList datasourceOptions = parameterAsString( parameters, QStringLiteral( "DATASOURCE_OPTIONS" ), context ).trimmed().split( ';', Qt::SkipEmptyParts );
97  QStringList layerOptions = parameterAsString( parameters, QStringLiteral( "LAYER_OPTIONS" ), context ).trimmed().split( ';', Qt::SkipEmptyParts );
98 #endif
99 
100  QString dest;
101  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
102  source->wkbType(), source->sourceCrs(), QgsFeatureSink::SinkFlags(), createOptions, datasourceOptions, layerOptions ) );
103  if ( !sink )
104  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
105 
106  double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
107  long long i = 0;
108 
110  QgsFeature feat;
111  while ( features.nextFeature( feat ) )
112  {
113  i++;
114  if ( feedback->isCanceled() )
115  {
116  break;
117  }
118 
119  feedback->setProgress( i * step );
120 
121  sink->addFeature( feat, QgsFeatureSink::FastInsert );
122  }
123 
124  QString filePath = dest;
125  layerName.clear(); // value of final layer name will be extracted from the destination string
126  int separatorIndex = dest.indexOf( '|' );
127  if ( separatorIndex > -1 )
128  {
129  QRegularExpression layerNameRx( QStringLiteral( "\\|layername=([^\\|]*)" ) );
130  QRegularExpressionMatch match = layerNameRx.match( dest );
131  if ( match.hasMatch() )
132  {
133  layerName = match.captured( 1 );
134  }
135  filePath = dest.mid( 0, separatorIndex );
136  }
137 
138  QVariantMap outputs;
139  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
140  outputs.insert( QStringLiteral( "FILE_PATH" ), filePath );
141  outputs.insert( QStringLiteral( "LAYER_NAME" ), layerName );
142  return outputs;
143 }
144 
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
A string output for processing algorithms.
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
An input feature source (such as vector layers) parameter for processing algorithms.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
static QString fileFilterString(VectorFormatOptions options=SortRecommended)
Returns filter string that can be used for dialogs.