Skip to content
Permalink
Browse files

Avoid emitting QgsProject::snappingConfigChanged multiple times when …

…reading or clearing projects

(cherry picked from commit 78cdadf)
  • Loading branch information
nyalldawson committed Dec 21, 2020
1 parent c40c55c commit 0befc290609e2b4edcffd56776b0818c93879ea1
Showing with 101 additions and 4 deletions.
  1. +61 −4 src/core/qgsproject.cpp
  2. +2 −0 src/core/qgsproject.h
  3. +38 −0 tests/src/python/test_qgsproject.py
@@ -84,6 +84,39 @@
// canonical project instance
QgsProject *QgsProject::sProject = nullptr;

///@cond PRIVATE
class ScopedIntIncrementor
{
public:

ScopedIntIncrementor( int *variable )
: mVariable( variable )
{
( *mVariable )++;
}

ScopedIntIncrementor( const ScopedIntIncrementor &other ) = delete;
ScopedIntIncrementor &operator=( const ScopedIntIncrementor &other ) = delete;

void release()
{
if ( mVariable )
( *mVariable )--;

mVariable = nullptr;
}

~ScopedIntIncrementor()
{
release();
}

private:
int *mVariable = nullptr;
};
///@endcond


/**
Take the given scope and key and convert them to a string list of key
tokens that will be used to navigate through a Property hierarchy
@@ -779,6 +812,8 @@ void QgsProject::setTransformContext( const QgsCoordinateTransformContext &conte

void QgsProject::clear()
{
ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );

QgsSettings settings;

mProjectScope.reset();
@@ -816,7 +851,6 @@ void QgsProject::clear()
mTimeSettings->reset();
mDisplaySettings->reset();
mSnappingConfig.reset();
emit snappingConfigChanged( mSnappingConfig );
emit avoidIntersectionsModeChanged();
emit topologicalEditingChanged();

@@ -857,11 +891,18 @@ void QgsProject::clear()
int alpha = settings.value( QStringLiteral( "qgis/default_selection_color_alpha" ), 255 ).toInt();
setSelectionColor( QColor( red, green, blue, alpha ) );

mSnappingConfig.clearIndividualLayerSettings();

removeAllMapLayers();
mRootGroup->clear();
if ( mMainAnnotationLayer )
mMainAnnotationLayer->reset();

snapSingleBlocker.release();

if ( !mBlockSnappingUpdates )
emit snappingConfigChanged( mSnappingConfig );

setDirty( false );
emit homePathChanged();
emit cleared();
@@ -1280,6 +1321,9 @@ bool QgsProject::read( QgsProject::ReadFlags flags )

bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags flags )
{
// avoid multiple emission of snapping updated signals
ScopedIntIncrementor snapSignalBlock( &mBlockSnappingUpdates );

QFile projectFile( filename );
clearError();

@@ -1702,7 +1746,11 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags
emit readProjectWithContext( *doc, context );

profile.switchTask( tr( "Updating interface" ) );
emit snappingConfigChanged( mSnappingConfig );

snapSignalBlock.release();
if ( !mBlockSnappingUpdates )
emit snappingConfigChanged( mSnappingConfig );

emit avoidIntersectionsModeChanged();
emit topologicalEditingChanged();
emit projectColorsChanged();
@@ -2008,13 +2056,13 @@ void QgsProject::onMapLayersAdded( const QList<QgsMapLayer *> &layers )
}
}

if ( mSnappingConfig.addLayers( layers ) )
if ( !mBlockSnappingUpdates && mSnappingConfig.addLayers( layers ) )
emit snappingConfigChanged( mSnappingConfig );
}

void QgsProject::onMapLayersRemoved( const QList<QgsMapLayer *> &layers )
{
if ( mSnappingConfig.removeLayers( layers ) )
if ( !mBlockSnappingUpdates && mSnappingConfig.removeLayers( layers ) )
emit snappingConfigChanged( mSnappingConfig );
}

@@ -3422,8 +3470,17 @@ QgsAnnotationLayer *QgsProject::mainAnnotationLayer()

void QgsProject::removeAllMapLayers()
{
if ( mLayerStore->count() == 0 )
return;

ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
mProjectScope.reset();
mLayerStore->removeAllMapLayers();

snapSingleBlocker.release();
mSnappingConfig.clearIndividualLayerSettings();
if ( !mBlockSnappingUpdates )
emit snappingConfigChanged( mSnappingConfig );
}

void QgsProject::reloadAllLayers()
@@ -2069,6 +2069,8 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera

mutable std::unique_ptr< QgsExpressionContextScope > mProjectScope;

int mBlockSnappingUpdates = 0;

friend class QgsProjectDirtyBlocker;

// Required to avoid creating a new project in it's destructor
@@ -807,6 +807,44 @@ def testUpgradeOtfFrom2x(self):
self.assertTrue(prj.crs().isValid())
self.assertEqual(prj.crs().authid(), 'EPSG:2056')

def testSnappingChangedSignal(self):
"""
Test the snappingConfigChanged signal
"""
project = QgsProject()
spy = QSignalSpy(project.snappingConfigChanged)
l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr")
l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr")
l2 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp"), "polys", "ogr")
project.addMapLayers([l0, l1])
self.assertEqual(len(spy), 1)
project.addMapLayer(l2)
self.assertEqual(len(spy), 2)

self.assertEqual(len(project.snappingConfig().individualLayerSettings()), 3)

tmpDir = QTemporaryDir()
tmpFile = "{}/project_snap.qgs".format(tmpDir.path())
self.assertTrue(project.write(tmpFile))

# only ONE signal!
project.clear()
self.assertEqual(len(spy), 3)

self.assertFalse(project.snappingConfig().individualLayerSettings())

p2 = QgsProject()
spy2 = QSignalSpy(p2.snappingConfigChanged)
p2.read(tmpFile)
# only ONE signal!
self.assertEqual(len(spy2), 1)

self.assertEqual(len(p2.snappingConfig().individualLayerSettings()), 3)

p2.removeAllMapLayers()
self.assertEqual(len(spy2), 2)
self.assertFalse(p2.snappingConfig().individualLayerSettings())

def testRelativePaths(self):
"""
Test whether paths to layer sources are stored as relative to the project path

0 comments on commit 0befc29

Please sign in to comment.
You can’t perform that action at this time.