diff --git a/python/gui/auto_generated/qgsattributedialog.sip.in b/python/gui/auto_generated/qgsattributedialog.sip.in index fca8b4e59a0..31eb93f26ff 100644 --- a/python/gui/auto_generated/qgsattributedialog.sip.in +++ b/python/gui/auto_generated/qgsattributedialog.sip.in @@ -73,6 +73,14 @@ Intercept window activate/deactivate events to show/hide the highlighted feature :param e: The event :return: The same as the parent QDialog +%End + + void setExtraContextScope( QgsExpressionContextScope *extraScope /Transfer/ ); +%Docstring +Sets an additional expression context scope to be used +for calculations in this form. + +.. versionadded:: 3.16 %End public slots: diff --git a/python/gui/auto_generated/qgsattributeform.sip.in b/python/gui/auto_generated/qgsattributeform.sip.in index f4957d4f34f..2ee4d02c1dc 100644 --- a/python/gui/auto_generated/qgsattributeform.sip.in +++ b/python/gui/auto_generated/qgsattributeform.sip.in @@ -167,6 +167,14 @@ In this case it will return a combined expression according to the chosen filter on all attribute widgets. .. versionadded:: 3.0 +%End + + void setExtraContextScope( QgsExpressionContextScope *extraScope /Transfer/ ); +%Docstring +Sets an additional expression context scope to be used +for calculations in this form. + +.. versionadded:: 3.16 %End signals: diff --git a/src/app/qgsfeatureaction.cpp b/src/app/qgsfeatureaction.cpp index c5083d86a5d..a05bcb2ab44 100644 --- a/src/app/qgsfeatureaction.cpp +++ b/src/app/qgsfeatureaction.cpp @@ -65,6 +65,9 @@ QgsAttributeDialog *QgsFeatureAction::newDialog( bool cloneFeature ) QgsAttributeDialog *dialog = new QgsAttributeDialog( mLayer, f, cloneFeature, parentWidget(), true, context ); dialog->setWindowFlags( dialog->windowFlags() | Qt::Tool ); + if ( scope ) + dialog->setExtraContextScope( new QgsExpressionContextScope( *scope ) ); + dialog->setObjectName( QStringLiteral( "featureactiondlg:%1:%2" ).arg( mLayer->id() ).arg( f->id() ) ); @@ -255,6 +258,8 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, boo dialog->setAttribute( Qt::WA_DeleteOnClose ); dialog->setMode( QgsAttributeEditorContext::AddFeatureMode ); dialog->setEditCommandMessage( text() ); + if ( scope ) + dialog->setExtraContextScope( new QgsExpressionContextScope( *scope ) ); connect( dialog->attributeForm(), &QgsAttributeForm::featureSaved, this, &QgsFeatureAction::onFeatureSaved ); diff --git a/src/gui/qgsattributedialog.cpp b/src/gui/qgsattributedialog.cpp index 0656fb83d03..5a9cd31fb08 100644 --- a/src/gui/qgsattributedialog.cpp +++ b/src/gui/qgsattributedialog.cpp @@ -148,3 +148,8 @@ bool QgsAttributeDialog::event( QEvent *e ) return QDialog::event( e ); } + +void QgsAttributeDialog::setExtraContextScope( QgsExpressionContextScope *extraScope ) +{ + mAttributeForm->setExtraContextScope( extraScope ); +} diff --git a/src/gui/qgsattributedialog.h b/src/gui/qgsattributedialog.h index b622f69b816..35abada0370 100644 --- a/src/gui/qgsattributedialog.h +++ b/src/gui/qgsattributedialog.h @@ -95,6 +95,14 @@ class GUI_EXPORT QgsAttributeDialog : public QDialog */ bool event( QEvent *e ) override; + /** + * Sets an additional expression context scope to be used + * for calculations in this form. + * + * \since QGIS 3.16 + */ + void setExtraContextScope( QgsExpressionContextScope *extraScope SIP_TRANSFER ); + public slots: void accept() override; void reject() override; diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index f62aaa8bbf5..453d689dcdc 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -516,7 +516,8 @@ bool QgsAttributeForm::updateDefaultValues( const int originIdx ) if ( mAlreadyUpdatedFields.contains( eww->fieldIdx() ) ) continue; - QString value = mLayer->defaultValue( eww->fieldIdx(), updatedFeature ).toString(); + QgsExpressionContext context = createExpressionContext( updatedFeature ); + QString value = mLayer->defaultValue( eww->fieldIdx(), updatedFeature, &context ).toString(); eww->setValue( value ); } } @@ -832,6 +833,17 @@ QString QgsAttributeForm::createFilterExpression() const return filter; } +QgsExpressionContext QgsAttributeForm::createExpressionContext( const QgsFeature &feature ) const +{ + QgsExpressionContext context; + context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); + context.appendScope( QgsExpressionContextUtils::formScope( feature, mContext.attributeFormModeString() ) ); + if ( mExtraContextScope ) + context.appendScope( new QgsExpressionContextScope( *mExtraContextScope.get() ) ); + context.setFeature( feature ); + return context; +} + void QgsAttributeForm::onAttributeChanged( const QVariant &value, const QVariantList &additionalFieldValues ) { @@ -950,10 +962,7 @@ void QgsAttributeForm::updateConstraints( QgsEditorWidgetWrapper *eww ) // sync OK button status synchronizeEnabledState(); - QgsExpressionContext context; - context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); - context.appendScope( QgsExpressionContextUtils::formScope( ft, mContext.attributeFormModeString() ) ); - context.setFeature( ft ); + QgsExpressionContext context = createExpressionContext( ft ); // Recheck visibility for all containers which are controlled by this value const QVector infos = mContainerInformationDependency.value( eww->field().name() ); @@ -966,10 +975,7 @@ void QgsAttributeForm::updateConstraints( QgsEditorWidgetWrapper *eww ) void QgsAttributeForm::updateContainersVisibility() { - QgsExpressionContext context; - context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); - context.appendScope( QgsExpressionContextUtils::formScope( mFeature, mContext.attributeFormModeString() ) ); - context.setFeature( mFeature ); + QgsExpressionContext context = createExpressionContext( mFeature ); const QVector infos = mContainerVisibilityInformation; @@ -1017,10 +1023,7 @@ void QgsAttributeForm::updateLabels() QgsFeature currentFeature; if ( currentFormFeature( currentFeature ) ) { - QgsExpressionContext context; - context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); - context.appendScope( QgsExpressionContextUtils::formScope( currentFeature, mContext.attributeFormModeString() ) ); - context.setFeature( currentFeature ); + QgsExpressionContext context = createExpressionContext( currentFeature ); for ( auto it = mLabelDataDefinedProperties.constBegin() ; it != mLabelDataDefinedProperties.constEnd(); ++it ) { @@ -2380,6 +2383,11 @@ QString QgsAttributeForm::aggregateFilter() const return filters.join( QStringLiteral( " AND " ) ); } +void QgsAttributeForm::setExtraContextScope( QgsExpressionContextScope *extraScope ) +{ + mExtraContextScope.reset( extraScope ); +} + int QgsAttributeForm::messageTimeout() { QgsSettings settings; diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h index ece8b4fbfb1..e6319573a8e 100644 --- a/src/gui/qgsattributeform.h +++ b/src/gui/qgsattributeform.h @@ -183,6 +183,14 @@ class GUI_EXPORT QgsAttributeForm : public QWidget */ QString aggregateFilter() const; + /** + * Sets an additional expression context scope to be used + * for calculations in this form. + * + * \since QGIS 3.16 + */ + void setExtraContextScope( QgsExpressionContextScope *extraScope SIP_TRANSFER ); + signals: /** @@ -387,6 +395,8 @@ class GUI_EXPORT QgsAttributeForm : public QWidget QString createFilterExpression() const; + QgsExpressionContext createExpressionContext( const QgsFeature &feature ) const; + //! constraints management void updateAllConstraints(); void updateConstraints( QgsEditorWidgetWrapper *w ); @@ -407,6 +417,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget QgsMessageBarItem *mMultiEditMessageBarItem = nullptr; QList mWidgets; QgsAttributeEditorContext mContext; + std::unique_ptr mExtraContextScope; QDialogButtonBox *mButtonBox = nullptr; QWidget *mSearchButtonBox = nullptr; QList mInterfaces;