Skip to content

Commit

Permalink
fix(layer-dependencies): emit QgsVectorLayer::dataChanged on commitCh…
Browse files Browse the repository at this point in the history
…anges

Now when a feature is externally modified on save (database trigger for
example), the dataChanged signal is emitted for indexes and caches
reconstruction.
  • Loading branch information
Djedouas committed Aug 29, 2024
1 parent 3b912d1 commit c0c4bf6
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 21 deletions.
13 changes: 2 additions & 11 deletions src/core/vector/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6101,15 +6101,6 @@ void QgsVectorLayer::emitDataChanged()
mDataChangedFired = false;
}

void QgsVectorLayer::onAfterCommitChangesDependency()
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS

mDataChangedFired = true;
reload();
mDataChangedFired = false;
}

bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Expand All @@ -6135,7 +6126,7 @@ bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
disconnect( lyr, &QgsVectorLayer::repaintRequested, this, &QgsVectorLayer::triggerRepaint );
disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::reload );
}

// assign new dependencies
Expand All @@ -6156,7 +6147,7 @@ bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
connect( lyr, &QgsVectorLayer::repaintRequested, this, &QgsVectorLayer::triggerRepaint );
connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::reload );
}

// if new layers are present, emit a data change
Expand Down
1 change: 0 additions & 1 deletion src/core/vector/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2794,7 +2794,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
void onSymbolsCounted();
void onDirtyTransaction( const QString &sql, const QString &name );
void emitDataChanged();
void onAfterCommitChangesDependency();

private:
void updateDefaultValues( QgsFeatureId fid, QgsFeature feature = QgsFeature(), QgsExpressionContext *context = nullptr );
Expand Down
25 changes: 16 additions & 9 deletions tests/src/python/test_layer_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
QgsRectangle,
QgsSnappingConfig,
QgsSnappingUtils,
QgsTolerance,
QgsVectorLayer,
)
import unittest
Expand Down Expand Up @@ -194,12 +193,12 @@ def test_circular_dependencies_with_2_layers(self):
self.assertEqual(len(spy_lines_data_changed), 2)

# added feature is deleted and added with its new defined id
# (it was -1 before) so it fires 2 more signal dataChanged on
# depending line (on featureAdded and on featureDeleted)
# (it was -1 before) so it fires 3 more signal dataChanged on
# depending line (on featureAdded and on featureDeleted and on afterCommitChanges)
# and so 2 more signal on points because it depends on line
self.pointsLayer.commitChanges()
self.assertEqual(len(spy_points_data_changed), 5)
self.assertEqual(len(spy_lines_data_changed), 4)
self.assertEqual(len(spy_points_data_changed), 6)
self.assertEqual(len(spy_lines_data_changed), 5)

# repaintRequested is called on commit changes on point
# so it is on depending line
Expand Down Expand Up @@ -230,15 +229,23 @@ def test_circular_dependencies_with_1_layer(self):
self.assertEqual(len(spy_lines_data_changed), 2)

# added feature is deleted and added with its new defined id
# (it was -1 before) so it fires 2 more signal dataChanged on
# depending line (on featureAdded and on featureDeleted)
self.linesLayer.commitChanges()
self.assertEqual(len(spy_lines_data_changed), 4)
# (it was -1 before) so it fires 3 more signal dataChanged on
# depending line (on featureAdded and on featureDeleted and on afterCommitChanges)
self.linesLayer.commitChanges(False)
self.assertEqual(len(spy_lines_data_changed), 5)

# repaintRequested is called only once on commit changes on line
# (ideally only one repaintRequested signal is fired, but it's harmless to fire multiple ones)
self.assertGreaterEqual(len(spy_lines_repaint_requested), 2)

# line fire dataChanged on geometryChanged
self.linesLayer.changeGeometry(f.id(), QgsGeometry.fromWkt("LINESTRING(0 0, 2 2)"))
self.assertEqual(len(spy_lines_data_changed), 6)

# line fire dataChanged on commitChanges
self.linesLayer.commitChanges()
self.assertEqual(len(spy_lines_data_changed), 7)

def test_layerDefinitionRewriteId(self):
tmpfile = os.path.join(tempfile.tempdir, "test.qlr")

Expand Down

0 comments on commit c0c4bf6

Please sign in to comment.