diff --git a/src/core/vector/qgsvectorlayer.cpp b/src/core/vector/qgsvectorlayer.cpp index 2afaed9c963c..690ae1fdd73c 100644 --- a/src/core/vector/qgsvectorlayer.cpp +++ b/src/core/vector/qgsvectorlayer.cpp @@ -6110,6 +6110,14 @@ void QgsVectorLayer::emitDataChanged() if ( mDataChangedFired ) return; + // If we are asked to fire dataChanged from a layer we depend on, + // be sure that this layer is not in the process of committing its changes, because + // we will be asked to fire dataChanged at the end of his commit, and we don't + // want to fire this signal more than necessary. + if ( QgsVectorLayer *layerWeDependUpon = qobject_cast( sender() ); + layerWeDependUpon && layerWeDependUpon->mCommitChangesActive ) + return; + updateExtents(); // reset cached extent to reflect data changes mDataChangedFired = true; @@ -6144,7 +6152,7 @@ bool QgsVectorLayer::setDependencies( const QSet &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::reload ); + disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::emitDataChanged ); } } @@ -6168,7 +6176,7 @@ bool QgsVectorLayer::setDependencies( const QSet &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::reload ); + connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::emitDataChanged ); } } diff --git a/tests/src/python/test_layer_dependencies.py b/tests/src/python/test_layer_dependencies.py index 71bdcf5d7cfb..4001279f054f 100644 --- a/tests/src/python/test_layer_dependencies.py +++ b/tests/src/python/test_layer_dependencies.py @@ -192,11 +192,19 @@ def test_circular_dependencies_with_2_layers(self): self.assertEqual(len(spy_points_data_changed), 3) 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 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() + # commit changes fires dataChanged because external changes could happen (provider side) + self.pointsLayer.commitChanges(False) + self.assertEqual(len(spy_points_data_changed), 4) + self.assertEqual(len(spy_lines_data_changed), 3) + + # points fire dataChanged on geometryChanged + # line depends on point, so fire dataChanged + self.pointsLayer.changeGeometry(f.id(), QgsGeometry.fromWkt("POINT(0 2)")) + self.assertEqual(len(spy_points_data_changed), 5) + self.assertEqual(len(spy_lines_data_changed), 4) + + # commit changes fires dataChanged because external changes could happen (provider side) + self.assertTrue(self.pointsLayer.commitChanges()) self.assertEqual(len(spy_points_data_changed), 6) self.assertEqual(len(spy_lines_data_changed), 5) @@ -228,11 +236,9 @@ def test_circular_dependencies_with_1_layer(self): self.linesLayer.addFeatures([f]) 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 3 more signal dataChanged on - # depending line (on featureAdded and on featureDeleted and on afterCommitChanges) + # line fire dataChanged on commitChanges self.linesLayer.commitChanges(False) - self.assertEqual(len(spy_lines_data_changed), 5) + self.assertEqual(len(spy_lines_data_changed), 3) # 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) @@ -240,11 +246,11 @@ def test_circular_dependencies_with_1_layer(self): # 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) + self.assertEqual(len(spy_lines_data_changed), 4) - # line fire dataChanged on commitChanges + # commit changes fires dataChanged because external changes could happen (provider side) self.linesLayer.commitChanges() - self.assertEqual(len(spy_lines_data_changed), 7) + self.assertEqual(len(spy_lines_data_changed), 5) def test_layerDefinitionRewriteId(self): tmpfile = os.path.join(tempfile.tempdir, "test.qlr")