Skip to content

Commit

Permalink
Fix #43901 No update of virtual fields considering layer dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
domi4484 committed Nov 23, 2021
1 parent 6eda6e4 commit c179587
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 4 deletions.
Expand Up @@ -242,6 +242,19 @@ Forward the signal to the embedded form
virtual bool valid() const;


signals:

void relatedFeaturesChanged();
%Docstring
Emit this signal, whenever the related features changed.
This happens for example when related features are added, removed,
linked or unlinked.

:param vectorLayer: The modified layer

.. versionadded:: 3.22
%End

public slots:
virtual void setFeature( const QgsFeature &feature );

Expand Down
14 changes: 14 additions & 0 deletions python/gui/auto_generated/qgsabstractrelationeditorwidget.sip.in
Expand Up @@ -167,11 +167,25 @@ Returns the widget configuration
Defines the widget configuration
%End

<<<<<<< HEAD
bool multiEditModeActive() const;
%Docstring
Returns true if editing multiple features at a time

.. versionadded:: 3.24
=======
signals:

void relatedFeaturesChanged();
%Docstring
Emit this signal, whenever the related features changed.
This happens for example when related features are added, removed,
linked or unlinked.

:param vectorLayer: The modified layer

.. versionadded:: 3.22
>>>>>>> 65130bccde (Fix #43901 No update of virtual fields considering layer dependencies)
%End

public slots:
Expand Down
16 changes: 12 additions & 4 deletions src/gui/editorwidgets/qgsrelationwidgetwrapper.cpp
Expand Up @@ -42,15 +42,17 @@ QWidget *QgsRelationWidgetWrapper::createWidget( QWidget *parent )
if ( form )
connect( form, &QgsAttributeForm::widgetValueChanged, this, &QgsRelationWidgetWrapper::widgetValueChanged );

QWidget *widget = QgsGui::instance()->relationWidgetRegistry()->create( mRelationEditorId, widgetConfig(), parent );
QgsAbstractRelationEditorWidget *relationEditorWidget = QgsGui::instance()->relationWidgetRegistry()->create( mRelationEditorId, widgetConfig(), parent );

if ( !widget )
if ( !relationEditorWidget )
{
QgsLogger::warning( QStringLiteral( "Failed to create relation widget \"%1\", fallback to \"basic\" relation widget" ).arg( mRelationEditorId ) );
widget = QgsGui::instance()->relationWidgetRegistry()->create( QStringLiteral( "relation_editor" ), widgetConfig(), parent );
relationEditorWidget = QgsGui::instance()->relationWidgetRegistry()->create( QStringLiteral( "relation_editor" ), widgetConfig(), parent );
}

return widget;
connect( relationEditorWidget, &QgsAbstractRelationEditorWidget::relatedFeaturesChanged, this, &QgsRelationWidgetWrapper::onRelatedFeaturesChanged );

return relationEditorWidget;
}

void QgsRelationWidgetWrapper::setFeature( const QgsFeature &feature )
Expand All @@ -71,6 +73,11 @@ void QgsRelationWidgetWrapper::setVisible( bool visible )
mWidget->setVisible( visible );
}

void QgsRelationWidgetWrapper::onRelatedFeaturesChanged()
{
emit relatedFeaturesChanged();
}

void QgsRelationWidgetWrapper::aboutToSave()
{
if ( !mRelation.isValid() || !widget() || !widget()->isVisible() || mRelation.referencingLayer() == mRelation.referencedLayer() )
Expand Down Expand Up @@ -108,6 +115,7 @@ void QgsRelationWidgetWrapper::widgetValueChanged( const QString &attribute, con
{
if ( mWidget && attributeChanged )
{
// Maybe from here the other bug? jump to first feature?
QgsFeature feature { mWidget->feature() };
if ( feature.attribute( attribute ) != newValue )
{
Expand Down
16 changes: 16 additions & 0 deletions src/gui/editorwidgets/qgsrelationwidgetwrapper.h
Expand Up @@ -210,6 +210,18 @@ class GUI_EXPORT QgsRelationWidgetWrapper : public QgsWidgetWrapper
void initWidget( QWidget *editor ) override;
bool valid() const override;

signals:

/**
* Emit this signal, whenever the related features changed.
* This happens for example when related features are added, removed,
* linked or unlinked.
*
* \param vectorLayer The modified layer
* \since QGIS 3.22
*/
void relatedFeaturesChanged();

public slots:
void setFeature( const QgsFeature &feature ) override;

Expand All @@ -227,6 +239,10 @@ class GUI_EXPORT QgsRelationWidgetWrapper : public QgsWidgetWrapper
*/
void setVisible( bool visible );

private slots:

void onRelatedFeaturesChanged();

private:
void aboutToSave() override;
QgsRelation mRelation;
Expand Down
14 changes: 14 additions & 0 deletions src/gui/qgsabstractrelationeditorwidget.cpp
Expand Up @@ -297,12 +297,16 @@ QgsFeatureIds QgsAbstractRelationEditorWidget::addFeature( const QgsGeometry &ge

updateUi();

emit relatedFeaturesChanged();

return addedFeatureIds;
}

void QgsAbstractRelationEditorWidget::deleteFeature( const QgsFeatureId fid )
{
deleteFeatures( QgsFeatureIds() << fid );

emit relatedFeaturesChanged();
}

void QgsAbstractRelationEditorWidget::deleteFeatures( const QgsFeatureIds &fids )
Expand Down Expand Up @@ -419,6 +423,8 @@ void QgsAbstractRelationEditorWidget::deleteFeatures( const QgsFeatureIds &fids
}

updateUi();

emit relatedFeaturesChanged();
}
}

Expand Down Expand Up @@ -561,6 +567,8 @@ void QgsAbstractRelationEditorWidget::onLinkFeatureDlgAccepted()
}

updateUi();

emit relatedFeaturesChanged();
}

void QgsAbstractRelationEditorWidget::unlinkFeature( const QgsFeatureId fid )
Expand Down Expand Up @@ -654,6 +662,8 @@ void QgsAbstractRelationEditorWidget::unlinkFeatures( const QgsFeatureIds &fids
}

updateUi();

emit relatedFeaturesChanged();
}

void QgsAbstractRelationEditorWidget::updateUi()
Expand Down Expand Up @@ -685,6 +695,8 @@ void QgsAbstractRelationEditorWidget::afterSetRelations()
void QgsAbstractRelationEditorWidget::duplicateFeature( const QgsFeatureId &fid )
{
duplicateFeatures( QgsFeatureIds() << fid );

emit relatedFeaturesChanged();
}

void QgsAbstractRelationEditorWidget::duplicateFeatures( const QgsFeatureIds &fids )
Expand All @@ -698,6 +710,8 @@ void QgsAbstractRelationEditorWidget::duplicateFeatures( const QgsFeatureIds &fi
QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
}

emit relatedFeaturesChanged();
}

void QgsAbstractRelationEditorWidget::showEvent( QShowEvent * )
Expand Down
12 changes: 12 additions & 0 deletions src/gui/qgsabstractrelationeditorwidget.h
Expand Up @@ -183,6 +183,18 @@ class GUI_EXPORT QgsAbstractRelationEditorWidget : public QWidget
*/
bool multiEditModeActive() const;

signals:

/**
* Emit this signal, whenever the related features changed.
* This happens for example when related features are added, removed,
* linked or unlinked.
*
* \param vectorLayer The modified layer
* \since QGIS 3.22
*/
void relatedFeaturesChanged();

public slots:

/**
Expand Down
102 changes: 102 additions & 0 deletions src/gui/qgsattributeform.cpp
Expand Up @@ -621,6 +621,77 @@ void QgsAttributeForm::updateValuesDependenciesVirtualFields( const int originId
}
}

void QgsAttributeForm::updateRelatedLayerFields()
{
// Synchronize dependencies
for ( QgsWidgetWrapper *ww : std::as_const( mWidgets ) )
{
QgsEditorWidgetWrapper *eww = qobject_cast<QgsEditorWidgetWrapper *>( ww );
if ( ! eww )
continue;

updateRelatedLayerFieldsDependencies( eww );
}

if ( mRelatedLayerFieldsDependencies.isEmpty() )
return;

if ( !mFeature.isValid() )
return;

QgsAttributes featureAttributes = mFeature.attributes();
for ( QgsWidgetWrapper *ww : std::as_const( mWidgets ) )
{
QgsEditorWidgetWrapper *eww = qobject_cast<QgsEditorWidgetWrapper *>( ww );
if ( !eww )
continue;

QVariantList dstVars = QVariantList() << featureAttributes.at( eww->fieldIdx() );
QVariantList srcVars = QVariantList() << eww->value();
QList<int> fieldIndexes = QList<int>() << eww->fieldIdx();

// append additional fields
const QStringList additionalFields = eww->additionalFields();
for ( const QString &fieldName : additionalFields )
{
int idx = eww->layer()->fields().lookupField( fieldName );
fieldIndexes << idx;
dstVars << featureAttributes.at( idx );
}
srcVars.append( eww->additionalFieldValues() );

Q_ASSERT( dstVars.count() == srcVars.count() );

for ( int i = 0; i < dstVars.count(); i++ )
{
if ( !qgsVariantEqual( dstVars[i], srcVars[i] ) && srcVars[i].isValid() && fieldIsEditable( fieldIndexes[i] ) )
featureAttributes[fieldIndexes[i]] = srcVars[i];
}
}

// go through depending fields and update the fields with virtual field
for ( QgsWidgetWrapper *ww : std::as_const( mRelatedLayerFieldsDependencies ) )
{
QgsEditorWidgetWrapper *eww = qobject_cast<QgsEditorWidgetWrapper *>( ww );
if ( !eww )
continue;

//do not update when this widget is already updating (avoid recursions)
if ( mAlreadyUpdatedFields.contains( eww->fieldIdx() ) )
continue;

// create updated Feature
QgsFeature updatedFeature = QgsFeature( mFeature );
updatedFeature.setAttributes( featureAttributes );
QgsExpressionContext context = createExpressionContext( updatedFeature );

QgsExpression exp( mLayer->expressionField( eww->fieldIdx() ) );
QVariant value = exp.evaluate( &context );

eww->setValue( value );
}
}

void QgsAttributeForm::resetMultiEdit( bool promptToSave )
{
if ( promptToSave )
Expand Down Expand Up @@ -1279,6 +1350,11 @@ void QgsAttributeForm::onAttributeDeleted( int idx )
setFeature( mFeature );
}

void QgsAttributeForm::onRelatedFeaturesChanged()
{
updateRelatedLayerFields();
}

void QgsAttributeForm::onUpdatedFields()
{
mPreventFeatureRefresh = false;
Expand Down Expand Up @@ -2428,6 +2504,14 @@ void QgsAttributeForm::afterWidgetInit()
connect( eww, &QgsEditorWidgetWrapper::valuesChanged, this, &QgsAttributeForm::onAttributeChanged );
connect( eww, &QgsEditorWidgetWrapper::constraintStatusChanged, this, &QgsAttributeForm::onConstraintStatusChanged );
}
else
{
QgsRelationWidgetWrapper *relationWidgetWrapper = qobject_cast<QgsRelationWidgetWrapper *>( ww );
if ( relationWidgetWrapper )
{
connect( relationWidgetWrapper, &QgsRelationWidgetWrapper::relatedFeaturesChanged, this, &QgsAttributeForm::onRelatedFeaturesChanged );
}
}
}
}

Expand Down Expand Up @@ -2714,6 +2798,7 @@ void QgsAttributeForm::updateFieldDependencies()
{
mDefaultValueDependencies.clear();
mVirtualFieldsDependencies.clear();
mRelatedLayerFieldsDependencies.clear();

//create defaultValueDependencies
for ( QgsWidgetWrapper *ww : std::as_const( mWidgets ) )
Expand All @@ -2725,6 +2810,8 @@ void QgsAttributeForm::updateFieldDependencies()
updateFieldDependenciesDefaultValue( eww );

updateFieldDependenciesVirtualFields( eww );

updateRelatedLayerFieldsDependencies( eww );
}
}

Expand Down Expand Up @@ -2775,6 +2862,21 @@ void QgsAttributeForm::updateFieldDependenciesVirtualFields( QgsEditorWidgetWrap
}
}

void QgsAttributeForm::updateRelatedLayerFieldsDependencies(QgsEditorWidgetWrapper *eww)
{
for ( QgsAttributeFormWidget *formWidget : mFormWidgets )
{
QgsAttributeFormRelationEditorWidget *relationEditorWidget = dynamic_cast<QgsAttributeFormRelationEditorWidget *>( formWidget );
if ( !relationEditorWidget )
continue;

QString expressionField = eww->layer()->expressionField( eww->fieldIdx() );
if ( expressionField.contains( QStringLiteral( "relation_aggregate" ) )
|| expressionField.contains( QStringLiteral( "get_features" ) ) )
mRelatedLayerFieldsDependencies.insert( eww );
}
}

void QgsAttributeForm::setMultiEditFeatureIdsRelations( const QgsFeatureIds &fids )
{
for ( QgsAttributeFormWidget *formWidget : mFormWidgets )
Expand Down
9 changes: 9 additions & 0 deletions src/gui/qgsattributeform.h
Expand Up @@ -341,6 +341,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
void onAttributeChanged( const QVariant &value, const QVariantList &additionalFieldValues );
void onAttributeAdded( int idx );
void onAttributeDeleted( int idx );
void onRelatedFeaturesChanged();
void onUpdatedFields();
void onConstraintStatusChanged( const QString &constraint,
const QString &description, const QString &err, QgsEditorWidgetWrapper::ConstraintResult result );
Expand Down Expand Up @@ -380,6 +381,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
void updateFieldDependencies();
void updateFieldDependenciesDefaultValue( QgsEditorWidgetWrapper *eww );
void updateFieldDependenciesVirtualFields( QgsEditorWidgetWrapper *eww );
void updateRelatedLayerFieldsDependencies( QgsEditorWidgetWrapper *eww );

void setMultiEditFeatureIdsRelations( const QgsFeatureIds &fids );

Expand Down Expand Up @@ -415,6 +417,8 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
void updateValuesDependenciesDefaultValues( const int originIdx );
void updateValuesDependenciesVirtualFields( const int originIdx );

void updateRelatedLayerFields();

void clearMultiEditMessages();
void pushSelectedFeaturesMessage();
void runSearchSelect( Qgis::SelectBehavior behavior );
Expand Down Expand Up @@ -527,6 +531,11 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
*/
QMap<int, QgsWidgetWrapper *> mVirtualFieldsDependencies;

/**
* Dependency list for values depending on related layers.
*/
QSet<QgsWidgetWrapper *> mRelatedLayerFieldsDependencies;

//! List of updated fields to avoid recursion on the setting of defaultValues
QList<int> mAlreadyUpdatedFields;

Expand Down

0 comments on commit c179587

Please sign in to comment.