Branch data Line data Source code
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 : :
18 : : #include "qgsalgorithmsavefeatures.h"
19 : : #include "qgsvectorfilewriter.h"
20 : : #include <QRegularExpression>
21 : :
22 : : ///@cond PRIVATE
23 : :
24 : 0 : QString QgsSaveFeaturesAlgorithm::name() const
25 : : {
26 : 0 : return QStringLiteral( "savefeatures" );
27 : : }
28 : :
29 : 0 : QString QgsSaveFeaturesAlgorithm::displayName() const
30 : : {
31 : 0 : return QObject::tr( "Save vector features to file" );
32 : : }
33 : :
34 : 0 : QStringList QgsSaveFeaturesAlgorithm::tags() const
35 : : {
36 : 0 : return QObject::tr( "save,write,export" ).split( ',' );
37 : 0 : }
38 : :
39 : 0 : QString QgsSaveFeaturesAlgorithm::group() const
40 : : {
41 : 0 : return QObject::tr( "Vector general" );
42 : : }
43 : :
44 : 0 : QString QgsSaveFeaturesAlgorithm::groupId() const
45 : : {
46 : 0 : return QStringLiteral( "vectorgeneral" );
47 : : }
48 : :
49 : 0 : QString QgsSaveFeaturesAlgorithm::shortHelpString() const
50 : : {
51 : 0 : 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 : 0 : QgsSaveFeaturesAlgorithm *QgsSaveFeaturesAlgorithm::createInstance() const
58 : : {
59 : 0 : return new QgsSaveFeaturesAlgorithm();
60 : : }
61 : :
62 : 0 : void QgsSaveFeaturesAlgorithm::initAlgorithm( const QVariantMap & )
63 : : {
64 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector features" ) ) );
65 : 0 : addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Saved features" ), QgsVectorFileWriter::fileFilterString(), QVariant(), false ) );
66 : :
67 : 0 : std::unique_ptr< QgsProcessingParameterString > param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Layer name" ), QVariant(), false, true );
68 : 0 : param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
69 : 0 : addParameter( param.release() );
70 : 0 : param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "DATASOURCE_OPTIONS" ), QObject::tr( "GDAL dataset options (separate individual options with semicolons)" ), QVariant(), false, true );
71 : 0 : param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
72 : 0 : addParameter( param.release() );
73 : 0 : param = std::make_unique< QgsProcessingParameterString >( QStringLiteral( "LAYER_OPTIONS" ), QObject::tr( "GDAL layer options (separate individual options with semicolons)" ), QVariant(), false, true );
74 : 0 : param->setFlags( param->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
75 : 0 : addParameter( param.release() );
76 : :
77 : 0 : addOutput( new QgsProcessingOutputString( QStringLiteral( "FILE_PATH" ), QObject::tr( "File name and path" ) ) );
78 : 0 : addOutput( new QgsProcessingOutputString( QStringLiteral( "LAYER_NAME" ), QObject::tr( "Layer name" ) ) );
79 : 0 : }
80 : :
81 : 0 : QVariantMap QgsSaveFeaturesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
82 : : {
83 : 0 : std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
84 : :
85 : 0 : QString layerName = parameterAsString( parameters, QStringLiteral( "LAYER_NAME" ), context ).trimmed();
86 : 0 : QVariantMap createOptions;
87 : 0 : if ( !layerName.isEmpty() )
88 : : {
89 : 0 : createOptions[QStringLiteral( "layerName" )] = layerName;
90 : 0 : }
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 : 0 : QStringList datasourceOptions = parameterAsString( parameters, QStringLiteral( "DATASOURCE_OPTIONS" ), context ).trimmed().split( ';', Qt::SkipEmptyParts );
97 : 0 : QStringList layerOptions = parameterAsString( parameters, QStringLiteral( "LAYER_OPTIONS" ), context ).trimmed().split( ';', Qt::SkipEmptyParts );
98 : : #endif
99 : :
100 : 0 : QString dest;
101 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
102 : 0 : source->wkbType(), source->sourceCrs(), QgsFeatureSink::SinkFlags(), createOptions, datasourceOptions, layerOptions ) );
103 : 0 : if ( !sink )
104 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
105 : :
106 : 0 : double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
107 : 0 : long long i = 0;
108 : :
109 : 0 : QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest(), QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks );
110 : 0 : QgsFeature feat;
111 : 0 : while ( features.nextFeature( feat ) )
112 : : {
113 : 0 : i++;
114 : 0 : if ( feedback->isCanceled() )
115 : : {
116 : 0 : break;
117 : : }
118 : :
119 : 0 : feedback->setProgress( i * step );
120 : :
121 : 0 : sink->addFeature( feat, QgsFeatureSink::FastInsert );
122 : : }
123 : :
124 : 0 : QString filePath = dest;
125 : 0 : layerName.clear(); // value of final layer name will be extracted from the destination string
126 : 0 : int separatorIndex = dest.indexOf( '|' );
127 : 0 : if ( separatorIndex > -1 )
128 : : {
129 : 0 : QRegularExpression layerNameRx( QStringLiteral( "\\|layername=([^\\|]*)" ) );
130 : 0 : QRegularExpressionMatch match = layerNameRx.match( dest );
131 : 0 : if ( match.hasMatch() )
132 : : {
133 : 0 : layerName = match.captured( 1 );
134 : 0 : }
135 : 0 : filePath = dest.mid( 0, separatorIndex );
136 : 0 : }
137 : :
138 : 0 : QVariantMap outputs;
139 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest );
140 : 0 : outputs.insert( QStringLiteral( "FILE_PATH" ), filePath );
141 : 0 : outputs.insert( QStringLiteral( "LAYER_NAME" ), layerName );
142 : 0 : return outputs;
143 : 0 : }
144 : :
145 : : ///@endcond
|