static QgsExpressionContext _getExpressionContext( const void* context ) { const QgsComposition* composition = ( const QgsComposition* ) context; if ( !composition ) { return QgsExpressionContext(); } QScopedPointer< QgsExpressionContext > expContext( composition->createExpressionContext() ); return QgsExpressionContext( *expContext ); }
static QgsExpressionContext _getExpressionContext( const void* context ) { const QgsComposerObject* composerObject = ( const QgsComposerObject* ) context; if ( !composerObject ) { return QgsExpressionContext(); } QScopedPointer< QgsExpressionContext > expContext( composerObject->createExpressionContext() ); return QgsExpressionContext( *expContext ); }
QgsExpressionContext QgsSymbolsListWidget::createExpressionContext() const { if ( mContext.expressionContext() ) return QgsExpressionContext( *mContext.expressionContext() ); //otherwise create a default symbol context QgsExpressionContext expContext( mContext.globalProjectAtlasMapLayerScopes( layer() ) ); // additional scopes const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes(); for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes ) { expContext.appendScope( new QgsExpressionContextScope( scope ) ); } expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE << QgsExpressionContext::EXPR_SYMBOL_COLOR << QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT << QgsExpressionContext::EXPR_GEOMETRY_PART_NUM << QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT << QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM << QgsExpressionContext::EXPR_CLUSTER_COLOR << QgsExpressionContext::EXPR_CLUSTER_SIZE ); return expContext; }
QgsFieldCalculator::QgsFieldCalculator( QgsVectorLayer* vl, QWidget* parent ) : QDialog( parent ) , mVectorLayer( vl ) , mAttributeId( -1 ) { setupUi( this ); if ( !vl ) return; QgsExpressionContext expContext( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) ); expContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), 1, true ) ); expContext.setHighlightedVariables( QStringList() << QStringLiteral( "row_number" ) ); builder->setLayer( vl ); builder->loadFieldNames(); builder->setExpressionContext( expContext ); populateFields(); populateOutputFieldTypes(); connect( builder, SIGNAL( expressionParsed( bool ) ), this, SLOT( setOkButtonState() ) ); connect( mOutputFieldWidthSpinBox, SIGNAL( editingFinished() ), this, SLOT( setPrecisionMinMax() ) ); QgsDistanceArea myDa; myDa.setSourceCrs( vl->crs().srsid() ); myDa.setEllipsoidalMode( true ); myDa.setEllipsoid( QgsProject::instance()->ellipsoid() ); builder->setGeomCalculator( myDa ); //default values for field width and precision mOutputFieldWidthSpinBox->setValue( 10 ); mOutputFieldPrecisionSpinBox->setValue( 3 ); setPrecisionMinMax(); if ( vl->providerType() == QLatin1String( "ogr" ) && vl->storageType() == QLatin1String( "ESRI Shapefile" ) ) { mOutputFieldNameLineEdit->setMaxLength( 10 ); } if ( !( vl->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes ) ) { mCreateVirtualFieldCheckbox->setChecked( true ); mCreateVirtualFieldCheckbox->setEnabled( false ); mOnlyVirtualFieldsInfoLabel->setVisible( true ); mInfoIcon->setVisible( true ); } else { mOnlyVirtualFieldsInfoLabel->setVisible( false ); mInfoIcon->setVisible( false ); } if ( !( vl->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ) { mUpdateExistingGroupBox->setEnabled( false ); mCreateVirtualFieldCheckbox->setChecked( true ); mCreateVirtualFieldCheckbox->setEnabled( false ); } Q_ASSERT( mNewFieldGroupBox->isEnabled() || mUpdateExistingGroupBox->isEnabled() ); if ( mNewFieldGroupBox->isEnabled() ) { mNewFieldGroupBox->setChecked( true ); } else { mNewFieldGroupBox->setToolTip( tr( "Not available for layer" ) ); mUpdateExistingGroupBox->setChecked( true ); mUpdateExistingGroupBox->setCheckable( false ); } if ( mUpdateExistingGroupBox->isEnabled() ) { mUpdateExistingGroupBox->setChecked( !mNewFieldGroupBox->isEnabled() ); } else { mUpdateExistingGroupBox->setToolTip( tr( "Not available for layer" ) ); mNewFieldGroupBox->setChecked( true ); mNewFieldGroupBox->setCheckable( false ); } if (( mNewFieldGroupBox->isChecked() && mCreateVirtualFieldCheckbox->isChecked() ) || mVectorLayer->isEditable() ) { mEditModeAutoTurnOnLabel->setVisible( false ); mInfoIcon->setVisible( false ); } else { mInfoIcon->setVisible( true ); } bool hasselection = vl->selectedFeatureCount() > 0; mOnlyUpdateSelectedCheckBox->setChecked( hasselection ); mOnlyUpdateSelectedCheckBox->setEnabled( hasselection ); mOnlyUpdateSelectedCheckBox->setText( tr( "Only update %1 selected features" ).arg( vl->selectedFeatureCount() ) ); builder->loadRecent( QStringLiteral( "fieldcalc" ) ); mInfoIcon->setPixmap( style()->standardPixmap( QStyle::SP_MessageBoxInformation ) ); setOkButtonState(); QSettings settings; restoreGeometry( settings.value( QStringLiteral( "/Windows/QgsFieldCalculator/geometry" ) ).toByteArray() ); }
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(); }