Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmrefactorfields.h 3 : : --------------------------------- 4 : : begin : June 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 "qgsalgorithmrefactorfields.h" 19 : : #include "qgsprocessingparameterfieldmap.h" 20 : : 21 : : ///@cond PRIVATE 22 : : 23 : 0 : QString QgsRefactorFieldsAlgorithm::name() const 24 : : { 25 : 0 : return QStringLiteral( "refactorfields" ); 26 : : } 27 : : 28 : 0 : QString QgsRefactorFieldsAlgorithm::displayName() const 29 : : { 30 : 0 : return QObject::tr( "Refactor fields" ); 31 : : } 32 : : 33 : 0 : QString QgsRefactorFieldsAlgorithm::shortHelpString() const 34 : : { 35 : 0 : return QObject::tr( "This algorithm allows editing the structure of the attributes table of a vector layer. Fields can be modified " 36 : : "in their type and name, using a fields mapping.\n\n" 37 : : "The original layer is not modified. A new layer is generated, which contains a modified attribute table, according " 38 : : "to the provided fields mapping.\n\n" 39 : : "Rows in orange have constraints in the template layer from which these fields were loaded. Treat this information " 40 : : "as a hint during configuration. No constraints will be added on an output layer nor will they be checked or " 41 : : "enforced by the algorithm." ); 42 : : } 43 : : 44 : 0 : QStringList QgsRefactorFieldsAlgorithm::tags() const 45 : : { 46 : 0 : return QObject::tr( "attributes,table" ).split( ',' ); 47 : 0 : } 48 : : 49 : 0 : QString QgsRefactorFieldsAlgorithm::group() const 50 : : { 51 : 0 : return QObject::tr( "Vector table" ); 52 : : } 53 : : 54 : 0 : QString QgsRefactorFieldsAlgorithm::groupId() const 55 : : { 56 : 0 : return QStringLiteral( "vectortable" ); 57 : : } 58 : : 59 : 0 : QString QgsRefactorFieldsAlgorithm::outputName() const 60 : : { 61 : 0 : return QObject::tr( "Refactored" ); 62 : : } 63 : : 64 : 0 : QList<int> QgsRefactorFieldsAlgorithm::inputLayerTypes() const 65 : : { 66 : 0 : return QList<int>() << QgsProcessing::TypeVector; 67 : 0 : } 68 : : 69 : 0 : QgsProcessingFeatureSource::Flag QgsRefactorFieldsAlgorithm::sourceFlags() const 70 : : { 71 : 0 : return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks; 72 : : } 73 : : 74 : 0 : QgsRefactorFieldsAlgorithm *QgsRefactorFieldsAlgorithm::createInstance() const 75 : : { 76 : 0 : return new QgsRefactorFieldsAlgorithm(); 77 : 0 : } 78 : : 79 : 0 : void QgsRefactorFieldsAlgorithm::initParameters( const QVariantMap & ) 80 : : { 81 : 0 : std::unique_ptr< QgsProcessingParameterFieldMapping > param = std::make_unique< QgsProcessingParameterFieldMapping> ( QStringLiteral( "FIELDS_MAPPING" ), QObject::tr( "Fields mapping" ), QStringLiteral( "INPUT" ) ); 82 : 0 : addParameter( param.release() ); 83 : 0 : } 84 : : 85 : 0 : QgsFields QgsRefactorFieldsAlgorithm::outputFields( const QgsFields & ) const 86 : : { 87 : 0 : return mFields; 88 : : } 89 : : 90 : 0 : bool QgsRefactorFieldsAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 91 : : { 92 : 0 : std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); 93 : 0 : if ( !source ) 94 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); 95 : : 96 : 0 : mDa.setSourceCrs( source->sourceCrs(), context.transformContext() ); 97 : 0 : mDa.setEllipsoid( context.ellipsoid() ); 98 : : 99 : 0 : mExpressionContext = createExpressionContext( parameters, context, source.get() ); 100 : : 101 : 0 : const QVariantList mapping = parameters.value( QStringLiteral( "FIELDS_MAPPING" ) ).toList(); 102 : 0 : for ( const QVariant &map : mapping ) 103 : : { 104 : 0 : const QVariantMap fieldDef = map.toMap(); 105 : 0 : const QString name = fieldDef.value( QStringLiteral( "name" ) ).toString(); 106 : 0 : if ( name.isEmpty() ) 107 : 0 : throw QgsProcessingException( QObject::tr( "Field name cannot be empty" ) ); 108 : : 109 : 0 : const QVariant::Type type = static_cast< QVariant::Type >( fieldDef.value( QStringLiteral( "type" ) ).toInt() ); 110 : : 111 : 0 : const int length = fieldDef.value( QStringLiteral( "length" ), 0 ).toInt(); 112 : 0 : const int precision = fieldDef.value( QStringLiteral( "precision" ), 0 ).toInt(); 113 : : 114 : 0 : mFields.append( QgsField( name, type, QString(), length, precision ) ); 115 : : 116 : 0 : const QString expressionString = fieldDef.value( QStringLiteral( "expression" ) ).toString(); 117 : 0 : if ( !expressionString.isEmpty() ) 118 : : { 119 : 0 : QgsExpression expression( expressionString ); 120 : 0 : expression.setGeomCalculator( &mDa ); 121 : 0 : expression.setDistanceUnits( context.distanceUnit() ); 122 : 0 : expression.setAreaUnits( context.areaUnit() ); 123 : 0 : if ( expression.hasParserError() ) 124 : : { 125 : 0 : throw QgsProcessingException( QObject::tr( "Parser error for field \"%1\" with expression \"%2\": %3" ) 126 : 0 : .arg( 127 : : name, 128 : : expressionString, 129 : 0 : expression.parserErrorString() ) ); 130 : : } 131 : 0 : mExpressions.append( expression ); 132 : 0 : } 133 : : else 134 : : { 135 : 0 : mExpressions.append( QgsExpression() ); 136 : : } 137 : 0 : } 138 : : 139 : : return true; 140 : 0 : } 141 : : 142 : 0 : QgsFeatureList QgsRefactorFieldsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * ) 143 : : { 144 : 0 : if ( !mExpressionsPrepared ) 145 : : { 146 : 0 : for ( auto it = mExpressions.begin(); it != mExpressions.end(); ++it ) 147 : : { 148 : 0 : if ( it->isValid() ) 149 : 0 : it->prepare( &mExpressionContext ); 150 : 0 : } 151 : 0 : } 152 : : 153 : 0 : QgsAttributes attributes; 154 : 0 : attributes.reserve( mExpressions.size() ); 155 : 0 : for ( auto it = mExpressions.begin(); it != mExpressions.end(); ++it ) 156 : : { 157 : 0 : if ( it->isValid() ) 158 : : { 159 : 0 : mExpressionContext.setFeature( feature ); 160 : 0 : mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber ); 161 : 0 : const QVariant value = it->evaluate( &mExpressionContext ); 162 : 0 : if ( it->hasEvalError() ) 163 : : { 164 : 0 : throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" ).arg( it->expression(), it->evalErrorString() ) ); 165 : : } 166 : 0 : attributes.append( value ); 167 : 0 : } 168 : : else 169 : : { 170 : 0 : attributes.append( QVariant() ); 171 : : } 172 : 0 : } 173 : : 174 : 0 : QgsFeature f = feature; 175 : 0 : f.setAttributes( attributes ); 176 : 0 : mRowNumber++; 177 : 0 : return QgsFeatureList() << f; 178 : 0 : } 179 : : 180 : 0 : bool QgsRefactorFieldsAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const 181 : : { 182 : : Q_UNUSED( layer ) 183 : 0 : return false; 184 : : } 185 : : 186 : : ///@endcond