From 9e42c5bc7f7c16c39e227598f4689918e1bf9020 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Tue, 25 Mar 2014 18:55:51 +0100 Subject: [PATCH] Fix support for setCacheImage() to enforce refresh of a layer --- python/core/qgsmaplayer.sip | 9 +++--- src/core/qgsmaplayer.cpp | 6 ++++ src/core/qgsmaplayer.h | 11 ++++---- src/core/qgsmaprenderercache.cpp | 47 ++++++++++++++++++++++++++++---- src/core/qgsmaprenderercache.h | 17 ++++++++++-- src/core/qgsmaprendererjob.cpp | 2 +- src/gui/qgsmapcanvas.cpp | 16 ++--------- src/gui/qgsmapcanvas.h | 3 -- 8 files changed, 74 insertions(+), 37 deletions(-) diff --git a/python/core/qgsmaplayer.sip b/python/core/qgsmaplayer.sip index 4b28461b0e5..9c6030f3828 100644 --- a/python/core/qgsmaplayer.sip +++ b/python/core/qgsmaplayer.sip @@ -209,12 +209,12 @@ class QgsMapLayer : QObject Layer definitions can be used to load a layer and styling all from a single file. */ - QDomDocument asLayerDefinition ( ); + QDomDocument asLayerDefinition( ); /** Creates a new layer from a layer defininition document */ static QgsMapLayer* fromLayerDefinition( QDomDocument& document ); - static QgsMapLayer* fromLayerDefinitionFile(const QString qlrfile ); + static QgsMapLayer* fromLayerDefinitionFile( const QString qlrfile ); /** Set a custom property for layer. Properties are stored in a map and saved in project file. * @note Added in v1.4 */ @@ -355,7 +355,7 @@ class QgsMapLayer : QObject /** @deprecated since 2.4 - returns NULL */ QImage *cacheImage() /Deprecated/; - /** @deprecated since 2.4 - does nothing */ + /** @deprecated since 2.4 - caches listen to repaintRequested() signal to invalidate the cached image */ void setCacheImage( QImage * thepImage /Transfer/ ) /Deprecated/; /** @deprecated since 2.4 - does nothing */ virtual void onCacheImageDelete() /Deprecated/; @@ -377,7 +377,8 @@ class QgsMapLayer : QObject void toggleScaleBasedVisibility( bool theVisibilityFlag ); bool hasScaleBasedVisibility() const; - /** @deprecated since 2.4 - does nothing */ + /** Clear cached image + * @deprecated in 2.4 - caches listen to repaintRequested() signal to invalidate the cached image */ void clearCacheImage() /Deprecated/; /** \brief Obtain Metadata for this layer */ diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp index f3e1d386102..b186ad39c45 100644 --- a/src/core/qgsmaplayer.cpp +++ b/src/core/qgsmaplayer.cpp @@ -1402,8 +1402,14 @@ void QgsMapLayer::setValid( bool valid ) mValid = valid; } +void QgsMapLayer::setCacheImage( QImage * ) +{ + emit repaintRequested(); +} + void QgsMapLayer::clearCacheImage() { + emit repaintRequested(); } QString QgsMapLayer::metadata() diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index 1bfc9317f03..edb46263b65 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -222,12 +222,12 @@ class CORE_EXPORT QgsMapLayer : public QObject Layer definitions can be used to load a layer and styling all from a single file. */ - QDomDocument asLayerDefinition ( ); + QDomDocument asLayerDefinition( ); /** Creates a new layer from a layer defininition document */ static QgsMapLayer* fromLayerDefinition( QDomDocument& document ); - static QgsMapLayer* fromLayerDefinitionFile(const QString qlrfile ); + static QgsMapLayer* fromLayerDefinitionFile( const QString qlrfile ); /** Set a custom property for layer. Properties are stored in a map and saved in project file. * @note Added in v1.4 */ @@ -370,8 +370,8 @@ class CORE_EXPORT QgsMapLayer : public QObject /** @deprecated since 2.4 - returns NULL */ Q_DECL_DEPRECATED QImage *cacheImage() { return 0; } - /** @deprecated since 2.4 - does nothing */ - Q_DECL_DEPRECATED void setCacheImage( QImage * ) {} + /** @deprecated since 2.4 - caches listen to repaintRequested() signal to invalidate the cached image */ + Q_DECL_DEPRECATED void setCacheImage( QImage * ); /** @deprecated since 2.4 - does nothing */ Q_DECL_DEPRECATED virtual void onCacheImageDelete() {} @@ -393,8 +393,7 @@ class CORE_EXPORT QgsMapLayer : public QObject bool hasScaleBasedVisibility() const; /** Clear cached image - * added in 1.5 */ - //! @deprecated in 2.4 - does nothing + * @deprecated in 2.4 - caches listen to repaintRequested() signal to invalidate the cached image */ Q_DECL_DEPRECATED void clearCacheImage(); /** \brief Obtain Metadata for this layer */ diff --git a/src/core/qgsmaprenderercache.cpp b/src/core/qgsmaprenderercache.cpp index 1d7e41bc21c..7c982248954 100644 --- a/src/core/qgsmaprenderercache.cpp +++ b/src/core/qgsmaprenderercache.cpp @@ -1,6 +1,8 @@ #include "qgsmaprenderercache.h" +#include "qgsmaplayerregistry.h" +#include "qgsmaplayer.h" QgsMapRendererCache::QgsMapRendererCache() { @@ -10,8 +12,23 @@ QgsMapRendererCache::QgsMapRendererCache() void QgsMapRendererCache::clear() { QMutexLocker lock( &mMutex ); + clearInternal(); +} + +void QgsMapRendererCache::clearInternal() +{ mExtent.setMinimal(); mScale = 0; + + // make sure we are disconnected from all layers + foreach ( QString layerId, mCachedImages.keys() ) + { + QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId ); + if ( layer ) + { + disconnect( layer, SIGNAL( repaintRequested() ), this, SLOT( layerRequestedRepaint() ) ); + } + } mCachedImages.clear(); } @@ -24,13 +41,12 @@ bool QgsMapRendererCache::init( QgsRectangle extent, double scale ) scale == mScale ) return true; + clearInternal(); + // set new params mExtent = extent; mScale = scale; - // invalidate cache - mCachedImages.clear(); - return false; } @@ -38,6 +54,13 @@ void QgsMapRendererCache::setCacheImage( QString layerId, const QImage& img ) { QMutexLocker lock( &mMutex ); mCachedImages[layerId] = img; + + // connect to the layer to listen to layer's repaintRequested() signals + QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId ); + if ( layer ) + { + connect( layer, SIGNAL( repaintRequested() ), this, SLOT( layerRequestedRepaint() ) ); + } } QImage QgsMapRendererCache::cacheImage( QString layerId ) @@ -46,10 +69,22 @@ QImage QgsMapRendererCache::cacheImage( QString layerId ) return mCachedImages.value( layerId ); } -void QgsMapRendererCache::layerDataChanged() +void QgsMapRendererCache::layerRequestedRepaint() { - // TODO! - qDebug( "nothing here yet" ); + QgsMapLayer* layer = qobject_cast( sender() ); + if ( layer ) + clearCacheImage( layer->id() ); } +void QgsMapRendererCache::clearCacheImage( QString layerId ) +{ + QMutexLocker lock( &mMutex ); + mCachedImages.remove( layerId ); + + QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId ); + if ( layer ) + { + disconnect( layer, SIGNAL( repaintRequested() ), this, SLOT( layerRequestedRepaint() ) ); + } +} diff --git a/src/core/qgsmaprenderercache.h b/src/core/qgsmaprenderercache.h index 0617cffc893..e9b73c30f03 100644 --- a/src/core/qgsmaprenderercache.h +++ b/src/core/qgsmaprenderercache.h @@ -11,7 +11,11 @@ /** * This class is responsible for keeping cache of rendered images of individual layers. * - * The class is thread-safe (multiple classes can access the same instance safely). + * Once a layer has rendered image stored in the cache (using setCacheImage(...)), + * the cache listens to repaintRequested() signals from layer. If triggered, the cache + * removes the rendered image (and disconnects from the layer). + * + * The class is thread-safe (multiple classes can access the same instance safely). * * @note added in 2.4 */ @@ -35,9 +39,16 @@ class CORE_EXPORT QgsMapRendererCache : public QObject //! get cached image for the specified layer ID. Returns null image if it is not cached. QImage cacheImage( QString layerId ); - public slots: + //! remove layer from the cache + void clearCacheImage( QString layerId ); + + protected slots: //! remove layer (that emitted the signal) from the cache - void layerDataChanged(); + void layerRequestedRepaint(); + + protected: + //! invalidate cache contents (without locking) + void clearInternal(); protected: QMutex mMutex; diff --git a/src/core/qgsmaprendererjob.cpp b/src/core/qgsmaprendererjob.cpp index 76b2e24d8e6..50add621558 100644 --- a/src/core/qgsmaprendererjob.cpp +++ b/src/core/qgsmaprendererjob.cpp @@ -589,7 +589,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin { QgsVectorLayer* vl = qobject_cast( ml ); if ( vl->isEditable() || ( labelingEngine && labelingEngine->willUseLayer( vl ) ) ) - mCache->setCacheImage( ml->id(), QImage() ); + mCache->clearCacheImage( ml->id() ); } layerJobs.append( LayerRenderJob() ); diff --git a/src/gui/qgsmapcanvas.cpp b/src/gui/qgsmapcanvas.cpp index e614507fdba..647d7bd1422 100644 --- a/src/gui/qgsmapcanvas.cpp +++ b/src/gui/qgsmapcanvas.cpp @@ -380,7 +380,7 @@ void QgsMapCanvas::setLayerSet( QList &layers ) // Add check if vector layer when disconnecting from selectionChanged slot // Ticket #811 - racicot QgsMapLayer *currentLayer = layer( i ); - disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( layerRequestedRepaint() ) ); + disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) ); QgsVectorLayer *isVectLyr = qobject_cast( currentLayer ); if ( isVectLyr ) { @@ -395,7 +395,7 @@ void QgsMapCanvas::setLayerSet( QList &layers ) // Add check if vector layer when connecting to selectionChanged slot // Ticket #811 - racicot QgsMapLayer *currentLayer = layer( i ); - connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( layerRequestedRepaint() ) ); + connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) ); QgsVectorLayer *isVectLyr = qobject_cast( currentLayer ); if ( isVectLyr ) { @@ -681,18 +681,6 @@ void QgsMapCanvas::refreshMap() mMapUpdateTimer.start(); } -void QgsMapCanvas::layerRequestedRepaint() -{ - // make sure to clear the cached image - if ( mCache ) - { - QgsMapLayer* layer = qobject_cast( sender() ); - if ( layer ) - mCache->setCacheImage( layer->id(), QImage() ); - } - - refresh(); -} void QgsMapCanvas::rendererJobFinished() { diff --git a/src/gui/qgsmapcanvas.h b/src/gui/qgsmapcanvas.h index c7cb4e697a0..38c9f5bb9ff 100644 --- a/src/gui/qgsmapcanvas.h +++ b/src/gui/qgsmapcanvas.h @@ -382,9 +382,6 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView void refreshMap(); - //! Layer says something has changed that affects its appearance - void layerRequestedRepaint(); - signals: /** Let the owner know how far we are with render operations */ //! @deprecated since 2.4 - already unused in 2.0 anyway