QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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
24QString QgsSaveFeaturesAlgorithm::name() const
25{
26 return QStringLiteral( "savefeatures" );
27}
28
29QString QgsSaveFeaturesAlgorithm::displayName() const
30{
31 return QObject::tr( "Save vector features to file" );
32}
33
34QStringList QgsSaveFeaturesAlgorithm::tags() const
35{
36 return QObject::tr( "save,write,export" ).split( ',' );
37}
38
39QString QgsSaveFeaturesAlgorithm::group() const
40{
41 return QObject::tr( "Vector general" );
42}
43
44QString QgsSaveFeaturesAlgorithm::groupId() const
45{
46 return QStringLiteral( "vectorgeneral" );
47}
48
49QString 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
57QgsSaveFeaturesAlgorithm *QgsSaveFeaturesAlgorithm::createInstance() const
58{
59 return new QgsSaveFeaturesAlgorithm();
60}
61
62void QgsSaveFeaturesAlgorithm::initAlgorithm( const QVariantMap & )
63{
64 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector features" ), QList<int>() << QgsProcessing::TypeVector ) );
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
81QVariantMap 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 const QStringList datasourceOptions = parameterAsString( parameters, QStringLiteral( "DATASOURCE_OPTIONS" ), context ).trimmed().split( ';', Qt::SkipEmptyParts );
97 const 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 const 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 if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
122 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
123 }
124
125 QString filePath = dest;
126 layerName.clear(); // value of final layer name will be extracted from the destination string
127 const int separatorIndex = dest.indexOf( '|' );
128 if ( separatorIndex > -1 )
129 {
130 const thread_local QRegularExpression layerNameRx( QStringLiteral( "\\|layername=([^\\|]*)" ) );
131 const QRegularExpressionMatch match = layerNameRx.match( dest );
132 if ( match.hasMatch() )
133 {
134 layerName = match.captured( 1 );
135 }
136 filePath = dest.mid( 0, separatorIndex );
137 }
138
139 QVariantMap outputs;
140 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
141 outputs.insert( QStringLiteral( "FILE_PATH" ), filePath );
142 outputs.insert( QStringLiteral( "LAYER_NAME" ), layerName );
143 return outputs;
144}
145
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:84
@ 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...
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:55
static QString fileFilterString(VectorFormatOptions options=SortRecommended)
Returns filter string that can be used for dialogs.