1 /***************************************************************************
2                          qgsalgorithmdropfields.cpp
3                          ---------------------------------
4     begin                : November 2020
5     copyright            : (C) 2020 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 "qgsalgorithmdropfields.h"
19 
20 ///@cond PRIVATE
21 
flags() const22 QgsProcessingAlgorithm::Flags QgsDropTableFieldsAlgorithm::flags() const
23 {
24   return QgsProcessingFeatureBasedAlgorithm::flags() & ~QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
25 }
26 
name() const27 QString QgsDropTableFieldsAlgorithm::name() const
28 {
29   return QStringLiteral( "deletecolumn" );
30 }
31 
displayName() const32 QString QgsDropTableFieldsAlgorithm::displayName() const
33 {
34   return QObject::tr( "Drop field(s)" );
35 }
36 
shortHelpString() const37 QString QgsDropTableFieldsAlgorithm::shortHelpString() const
38 {
39   return QObject::tr( "This algorithm takes a vector layer and generates a new one that has the exact same content but without the selected columns." );
40 }
41 
shortDescription() const42 QString QgsDropTableFieldsAlgorithm::shortDescription() const
43 {
44   return QObject::tr( "Deletes fields from a vector layer." );
45 }
46 
tags() const47 QStringList QgsDropTableFieldsAlgorithm::tags() const
48 {
49   return QObject::tr( "drop,delete,remove,fields,columns,attributes" ).split( ',' );
50 }
51 
group() const52 QString QgsDropTableFieldsAlgorithm::group() const
53 {
54   return QObject::tr( "Vector table" );
55 }
56 
groupId() const57 QString QgsDropTableFieldsAlgorithm::groupId() const
58 {
59   return QStringLiteral( "vectortable" );
60 }
61 
outputName() const62 QString QgsDropTableFieldsAlgorithm::outputName() const
63 {
64   return QObject::tr( "Remaining fields" );
65 }
66 
inputLayerTypes() const67 QList<int> QgsDropTableFieldsAlgorithm::inputLayerTypes() const
68 {
69   return QList<int>() << QgsProcessing::TypeVector;
70 }
71 
sourceFlags() const72 QgsProcessingFeatureSource::Flag QgsDropTableFieldsAlgorithm::sourceFlags() const
73 {
74   return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
75 }
76 
createInstance() const77 QgsDropTableFieldsAlgorithm *QgsDropTableFieldsAlgorithm::createInstance() const
78 {
79   return new QgsDropTableFieldsAlgorithm();
80 }
81 
initParameters(const QVariantMap &)82 void QgsDropTableFieldsAlgorithm::initParameters( const QVariantMap & )
83 {
84   addParameter( new QgsProcessingParameterField( QStringLiteral( "COLUMN" ), QObject::tr( "Fields to drop" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true ) );
85 }
86 
outputFields(const QgsFields & inputFields) const87 QgsFields QgsDropTableFieldsAlgorithm::outputFields( const QgsFields &inputFields ) const
88 {
89   QgsFields outFields = inputFields;
90   // loop through twice - first we need to build up a list of original attribute indices
91   for ( const QString &field : mFieldsToDelete )
92   {
93     const int index = inputFields.lookupField( field );
94     if ( index >= 0 )
95       mFieldIndices.append( index );
96   }
97 
98   // important - make sure we remove from the end so we aren't changing used indices as we go
99   std::sort( mFieldIndices.begin(), mFieldIndices.end(), std::greater< int >() );
100 
101   // this second time we make a cleaned version of the fields
102   for ( const int index : std::as_const( mFieldIndices ) )
103   {
104     outFields.remove( index );
105   }
106   return outFields;
107 }
108 
prepareAlgorithm(const QVariantMap & parameters,QgsProcessingContext & context,QgsProcessingFeedback * feedback)109 bool QgsDropTableFieldsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
110 {
111   mFieldsToDelete = parameterAsFields( parameters, QStringLiteral( "COLUMN" ), context );
112 
113   if ( feedback )
114   {
115     std::unique_ptr< QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
116     if ( source )
117     {
118       for ( const QString &field : std::as_const( mFieldsToDelete ) )
119       {
120         const int index = source->fields().lookupField( field );
121         if ( index < 0 )
122         {
123           feedback->pushInfo( QObject::tr( "Field “%1” does not exist in input layer " ).arg( field ) );
124         }
125       }
126     }
127   }
128 
129   return true;
130 }
131 
processFeature(const QgsFeature & feature,QgsProcessingContext &,QgsProcessingFeedback *)132 QgsFeatureList QgsDropTableFieldsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
133 {
134   QgsFeature f = feature;
135   QgsAttributes attributes = f.attributes();
136   for ( const int index : mFieldIndices )
137   {
138     attributes.remove( index );
139   }
140   f.setAttributes( attributes );
141   return QgsFeatureList() << f;
142 }
143 
supportInPlaceEdit(const QgsMapLayer * layer) const144 bool QgsDropTableFieldsAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
145 {
146   Q_UNUSED( layer )
147   return false;
148 }
149 
150 
151 
152 //
153 // QgsRetainTableFieldsAlgorithm
154 //
155 
flags() const156 QgsProcessingAlgorithm::Flags QgsRetainTableFieldsAlgorithm::flags() const
157 {
158   return QgsProcessingFeatureBasedAlgorithm::flags() & ~QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
159 }
160 
name() const161 QString QgsRetainTableFieldsAlgorithm::name() const
162 {
163   return QStringLiteral( "retainfields" );
164 }
165 
displayName() const166 QString QgsRetainTableFieldsAlgorithm::displayName() const
167 {
168   return QObject::tr( "Retain fields" );
169 }
170 
shortHelpString() const171 QString QgsRetainTableFieldsAlgorithm::shortHelpString() const
172 {
173   return QObject::tr( "This algorithm takes a vector layer and generates a new one that retains only the selected fields. All other fields will be dropped." );
174 }
175 
shortDescription() const176 QString QgsRetainTableFieldsAlgorithm::shortDescription() const
177 {
178   return QObject::tr( "Retains selected fields from a vector layer." );
179 }
180 
tags() const181 QStringList QgsRetainTableFieldsAlgorithm::tags() const
182 {
183   return QObject::tr( "drop,delete,remove,retain,keep,other,fields,columns,attributes" ).split( ',' );
184 }
185 
group() const186 QString QgsRetainTableFieldsAlgorithm::group() const
187 {
188   return QObject::tr( "Vector table" );
189 }
190 
groupId() const191 QString QgsRetainTableFieldsAlgorithm::groupId() const
192 {
193   return QStringLiteral( "vectortable" );
194 }
195 
outputName() const196 QString QgsRetainTableFieldsAlgorithm::outputName() const
197 {
198   return QObject::tr( "Retained fields" );
199 }
200 
inputLayerTypes() const201 QList<int> QgsRetainTableFieldsAlgorithm::inputLayerTypes() const
202 {
203   return QList<int>() << QgsProcessing::TypeVector;
204 }
205 
sourceFlags() const206 QgsProcessingFeatureSource::Flag QgsRetainTableFieldsAlgorithm::sourceFlags() const
207 {
208   return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
209 }
210 
createInstance() const211 QgsRetainTableFieldsAlgorithm *QgsRetainTableFieldsAlgorithm::createInstance() const
212 {
213   return new QgsRetainTableFieldsAlgorithm();
214 }
215 
initParameters(const QVariantMap &)216 void QgsRetainTableFieldsAlgorithm::initParameters( const QVariantMap & )
217 {
218   addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELDS" ), QObject::tr( "Fields to retain" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true ) );
219 }
220 
outputFields(const QgsFields & inputFields) const221 QgsFields QgsRetainTableFieldsAlgorithm::outputFields( const QgsFields &inputFields ) const
222 {
223   // loop through twice - first we need to build up a list of original attribute indices
224   for ( const QString &field : mFieldsToRetain )
225   {
226     const int index = inputFields.lookupField( field );
227     if ( index >= 0 )
228       mFieldIndices.append( index );
229   }
230 
231   std::sort( mFieldIndices.begin(), mFieldIndices.end() );
232 
233   // this second time we make a cleaned version of the fields
234   QgsFields outFields;
235   for ( const int index : std::as_const( mFieldIndices ) )
236   {
237     outFields.append( inputFields.at( index ) );
238   }
239   return outFields;
240 }
241 
prepareAlgorithm(const QVariantMap & parameters,QgsProcessingContext & context,QgsProcessingFeedback * feedback)242 bool QgsRetainTableFieldsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
243 {
244   mFieldsToRetain = parameterAsFields( parameters, QStringLiteral( "FIELDS" ), context );
245 
246   if ( feedback )
247   {
248     std::unique_ptr< QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
249     if ( source )
250     {
251       for ( const QString &field : std::as_const( mFieldsToRetain ) )
252       {
253         const int index = source->fields().lookupField( field );
254         if ( index < 0 )
255         {
256           feedback->pushInfo( QObject::tr( "Field “%1” does not exist in input layer " ).arg( field ) );
257         }
258       }
259     }
260   }
261 
262   return true;
263 }
264 
processFeature(const QgsFeature & feature,QgsProcessingContext &,QgsProcessingFeedback *)265 QgsFeatureList QgsRetainTableFieldsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
266 {
267   QgsFeature f = feature;
268   const QgsAttributes inputAttributes = f.attributes();
269   QgsAttributes outputAttributes;
270   outputAttributes.reserve( mFieldIndices.count() );
271   for ( const int index : mFieldIndices )
272   {
273     outputAttributes.append( inputAttributes.at( index ) );
274   }
275   f.setAttributes( outputAttributes );
276   return QgsFeatureList() << f;
277 }
278 
supportInPlaceEdit(const QgsMapLayer * layer) const279 bool QgsRetainTableFieldsAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
280 {
281   Q_UNUSED( layer )
282   return false;
283 }
284 
285 ///@endcond
286