void QgsFieldCalculator::accept() { builder->saveToRecent( "fieldcalc" ); if ( !mVectorLayer ) return; // Set up QgsDistanceArea each time we (re-)calculate QgsDistanceArea myDa; myDa.setSourceCrs( mVectorLayer->crs().srsid() ); myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapSettings().hasCrsTransformEnabled() ); myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); QString calcString = builder->expressionText(); QgsExpression exp( calcString ); exp.setGeomCalculator( myDa ); QgsExpressionContext expContext; expContext << QgsExpressionContextUtils::globalScope() << QgsExpressionContextUtils::projectScope() << QgsExpressionContextUtils::layerScope( mVectorLayer ); if ( !exp.prepare( &expContext ) ) { QMessageBox::critical( 0, tr( "Evaluation error" ), exp.evalErrorString() ); return; } // Test for creating expression field based on ! mUpdateExistingGroupBox checked rather // than on mNewFieldGroupBox checked, as if the provider does not support adding attributes // then mUpdateExistingGroupBox is set to not checkable, and hence is not checked. This // is a minimum fix to resolve this - better would be some GUI redesign... if ( ! mUpdateExistingGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) { mVectorLayer->addExpressionField( calcString, fieldDefinition() ); } else { if ( !mVectorLayer->isEditable() ) mVectorLayer->startEditing(); QApplication::setOverrideCursor( Qt::WaitCursor ); mVectorLayer->beginEditCommand( "Field calculator" ); //update existing field if ( mUpdateExistingGroupBox->isChecked() || !mNewFieldGroupBox->isEnabled() ) { QMap<QString, int>::const_iterator fieldIt = mFieldMap.find( mExistingFieldComboBox->currentText() ); if ( fieldIt != mFieldMap.end() ) { mAttributeId = fieldIt.value(); } } else { //create new field const QgsField newField = fieldDefinition(); if ( !mVectorLayer->addAttribute( newField ) ) { QApplication::restoreOverrideCursor(); QMessageBox::critical( 0, tr( "Provider error" ), tr( "Could not add the new field to the provider." ) ); mVectorLayer->destroyEditCommand(); return; } //get index of the new field const QgsFields& fields = mVectorLayer->fields(); for ( int idx = 0; idx < fields.count(); ++idx ) { if ( fields[idx].name() == mOutputFieldNameLineEdit->text() ) { mAttributeId = idx; break; } } //update expression context with new fields expContext.setFields( mVectorLayer->fields() ); if ( ! exp.prepare( &expContext ) ) { QApplication::restoreOverrideCursor(); QMessageBox::critical( 0, tr( "Evaluation error" ), exp.evalErrorString() ); return; } } if ( mAttributeId == -1 ) { mVectorLayer->destroyEditCommand(); QApplication::restoreOverrideCursor(); return; } //go through all the features and change the new attribute QgsFeature feature; bool calculationSuccess = true; QString error; bool onlySelected = mOnlyUpdateSelectedCheckBox->isChecked(); QgsFeatureIds selectedIds = mVectorLayer->selectedFeaturesIds(); bool useGeometry = exp.needsGeometry(); int rownum = 1; QgsField field = mVectorLayer->fields()[mAttributeId]; bool newField = !mUpdateExistingGroupBox->isChecked(); QVariant emptyAttribute; if ( newField ) emptyAttribute = QVariant( field.type() ); QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFlags( useGeometry ? QgsFeatureRequest::NoFlags : QgsFeatureRequest::NoGeometry ) ); while ( fit.nextFeature( feature ) ) { if ( onlySelected ) { if ( !selectedIds.contains( feature.id() ) ) { continue; } } expContext.setFeature( feature ); expContext.lastScope()->setVariable( QString( "row_number" ), rownum ); QVariant value = exp.evaluate( &expContext ); field.convertCompatible( value ); if ( exp.hasEvalError() ) { calculationSuccess = false; error = exp.evalErrorString(); break; } else { mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value, newField ? emptyAttribute : feature.attributes().value( mAttributeId ) ); } rownum++; } QApplication::restoreOverrideCursor(); if ( !calculationSuccess ) { QMessageBox::critical( 0, tr( "Error" ), tr( "An error occured while evaluating the calculation string:\n%1" ).arg( error ) ); mVectorLayer->destroyEditCommand(); return; } mVectorLayer->endEditCommand(); } QDialog::accept(); }
void QgsFieldCalculator::accept() { builder->saveToRecent( QStringLiteral( "fieldcalc" ) ); if ( !mVectorLayer ) return; // Set up QgsDistanceArea each time we (re-)calculate QgsDistanceArea myDa; myDa.setSourceCrs( mVectorLayer->crs().srsid() ); myDa.setEllipsoidalMode( true ); myDa.setEllipsoid( QgsProject::instance()->ellipsoid() ); QString calcString = builder->expressionText(); QgsExpression exp( calcString ); exp.setGeomCalculator( &myDa ); exp.setDistanceUnits( QgsProject::instance()->distanceUnits() ); exp.setAreaUnits( QgsProject::instance()->areaUnits() ); QgsExpressionContext expContext( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) ); if ( !exp.prepare( &expContext ) ) { QMessageBox::critical( nullptr, tr( "Evaluation error" ), exp.evalErrorString() ); return; } bool updatingGeom = false; // Test for creating expression field based on ! mUpdateExistingGroupBox checked rather // than on mNewFieldGroupBox checked, as if the provider does not support adding attributes // then mUpdateExistingGroupBox is set to not checkable, and hence is not checked. This // is a minimum fix to resolve this - better would be some GUI redesign... if ( ! mUpdateExistingGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) { mVectorLayer->addExpressionField( calcString, fieldDefinition() ); } else { if ( !mVectorLayer->isEditable() ) mVectorLayer->startEditing(); QApplication::setOverrideCursor( Qt::WaitCursor ); mVectorLayer->beginEditCommand( QStringLiteral( "Field calculator" ) ); //update existing field if ( mUpdateExistingGroupBox->isChecked() || !mNewFieldGroupBox->isEnabled() ) { if ( mExistingFieldComboBox->currentData().toString() == QLatin1String( "geom" ) ) { //update geometry mAttributeId = -1; updatingGeom = true; } else { QMap<QString, int>::const_iterator fieldIt = mFieldMap.constFind( mExistingFieldComboBox->currentText() ); if ( fieldIt != mFieldMap.constEnd() ) { mAttributeId = fieldIt.value(); } } } else { //create new field const QgsField newField = fieldDefinition(); if ( !mVectorLayer->addAttribute( newField ) ) { QApplication::restoreOverrideCursor(); QMessageBox::critical( nullptr, tr( "Provider error" ), tr( "Could not add the new field to the provider." ) ); mVectorLayer->destroyEditCommand(); return; } //get index of the new field const QgsFields& fields = mVectorLayer->fields(); for ( int idx = 0; idx < fields.count(); ++idx ) { if ( fields.at( idx ).name() == mOutputFieldNameLineEdit->text() ) { mAttributeId = idx; break; } } //update expression context with new fields expContext.setFields( mVectorLayer->fields() ); if ( ! exp.prepare( &expContext ) ) { QApplication::restoreOverrideCursor(); QMessageBox::critical( nullptr, tr( "Evaluation error" ), exp.evalErrorString() ); return; } } if ( mAttributeId == -1 && !updatingGeom ) { mVectorLayer->destroyEditCommand(); QApplication::restoreOverrideCursor(); return; } //go through all the features and change the new attribute QgsFeature feature; bool calculationSuccess = true; QString error; bool useGeometry = exp.needsGeometry(); int rownum = 1; QgsField field = !updatingGeom ? mVectorLayer->fields().at( mAttributeId ) : QgsField(); bool newField = !mUpdateExistingGroupBox->isChecked(); QVariant emptyAttribute; if ( newField ) emptyAttribute = QVariant( field.type() ); QgsFeatureRequest req = QgsFeatureRequest().setFlags( useGeometry ? QgsFeatureRequest::NoFlags : QgsFeatureRequest::NoGeometry ); if ( mOnlyUpdateSelectedCheckBox->isChecked() ) { req.setFilterFids( mVectorLayer->selectedFeatureIds() ); } QgsFeatureIterator fit = mVectorLayer->getFeatures( req ); while ( fit.nextFeature( feature ) ) { expContext.setFeature( feature ); expContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), rownum, true ) ); QVariant value = exp.evaluate( &expContext ); if ( exp.hasEvalError() ) { calculationSuccess = false; error = exp.evalErrorString(); break; } else if ( updatingGeom ) { if ( value.canConvert< QgsGeometry >() ) { QgsGeometry geom = value.value< QgsGeometry >(); mVectorLayer->changeGeometry( feature.id(), geom ); } } else { field.convertCompatible( value ); mVectorLayer->changeAttributeValue( feature.id(), mAttributeId, value, newField ? emptyAttribute : feature.attributes().value( mAttributeId ) ); } rownum++; } QApplication::restoreOverrideCursor(); if ( !calculationSuccess ) { QMessageBox::critical( nullptr, tr( "Error" ), tr( "An error occurred while evaluating the calculation string:\n%1" ).arg( error ) ); mVectorLayer->destroyEditCommand(); return; } mVectorLayer->endEditCommand(); } QDialog::accept(); }