Skip to content

Commit

Permalink
Merge pull request #4111 from nyalldawson/refresh_layers
Browse files Browse the repository at this point in the history
[FEATURE] Allow layers to be automatically refreshed at a specified interval
  • Loading branch information
nyalldawson committed Feb 13, 2017
2 parents 787c846 + 38f87a6 commit f2ac60a
Show file tree
Hide file tree
Showing 19 changed files with 569 additions and 25 deletions.
20 changes: 9 additions & 11 deletions python/core/qgsmaplayer.sip
Expand Up @@ -603,6 +603,11 @@ class QgsMapLayer : QObject
*/ */
bool hasScaleBasedVisibility() const; bool hasScaleBasedVisibility() const;


bool hasAutoRefreshEnabled() const;
int autoRefreshInterval() const;
void setAutoRefreshInterval( int interval );
void setAutoRefreshEnabled( bool enabled );

public slots: public slots:


/** Event handler for when a coordinate transform fails due to bad vertex error */ /** Event handler for when a coordinate transform fails due to bad vertex error */
Expand Down Expand Up @@ -634,13 +639,7 @@ class QgsMapLayer : QObject
*/ */
void setScaleBasedVisibility( const bool enabled ); void setScaleBasedVisibility( const bool enabled );


/** void triggerRepaint( bool deferredUpdate = false );
* Will advice the map canvas (and any other interested party) that this layer requires to be repainted.
* Will emit a repaintRequested() signal.
*
* @note in 2.6 function moved from vector/raster subclasses to QgsMapLayer
*/
void triggerRepaint();


/** \brief Obtain Metadata for this layer */ /** \brief Obtain Metadata for this layer */
virtual QString metadata() const; virtual QString metadata() const;
Expand Down Expand Up @@ -687,10 +686,7 @@ class QgsMapLayer : QObject
/** Emit a signal that layer's CRS has been reset */ /** Emit a signal that layer's CRS has been reset */
void crsChanged(); void crsChanged();


/** By emitting this signal the layer tells that either appearance or content have been changed void repaintRequested( bool deferredUpdate = false );
* and any view showing the rendered layer should refresh itself.
*/
void repaintRequested();


/** This is used to send a request that any mapcanvas using this layer update its extents */ /** This is used to send a request that any mapcanvas using this layer update its extents */
void recalculateExtents() const; void recalculateExtents() const;
Expand Down Expand Up @@ -739,6 +735,8 @@ class QgsMapLayer : QObject
*/ */
void willBeDeleted(); void willBeDeleted();


void autoRefreshIntervalChanged( int interval );

protected: protected:
/** Set the extent */ /** Set the extent */
virtual void setExtent( const QgsRectangle &rect ); virtual void setExtent( const QgsRectangle &rect );
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -10408,7 +10408,7 @@ void QgisApp::layersWereAdded( const QList<QgsMapLayer *>& theLayers )


if ( provider ) if ( provider )
{ {
connect( provider, &QgsDataProvider::dataChanged, layer, &QgsMapLayer::triggerRepaint ); connect( provider, &QgsDataProvider::dataChanged, layer, [layer] { layer->triggerRepaint(); } );
connect( provider, &QgsDataProvider::dataChanged, mMapCanvas, &QgsMapCanvas::refresh ); connect( provider, &QgsDataProvider::dataChanged, mMapCanvas, &QgsMapCanvas::refresh );
} }
} }
Expand Down
9 changes: 9 additions & 0 deletions src/app/qgsrasterlayerproperties.cpp
Expand Up @@ -139,6 +139,8 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
// enable or disable Build Pyramids button depending on selection in pyramid list // enable or disable Build Pyramids button depending on selection in pyramid list
connect( lbxPyramidResolutions, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleBuildPyramidsButton() ) ); connect( lbxPyramidResolutions, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleBuildPyramidsButton() ) );


connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );

// set up the scale based layer visibility stuff.... // set up the scale based layer visibility stuff....
mScaleRangeWidget->setMapCanvas( mMapCanvas ); mScaleRangeWidget->setMapCanvas( mMapCanvas );
chkUseScaleDependentRendering->setChecked( lyr->hasScaleBasedVisibility() ); chkUseScaleDependentRendering->setChecked( lyr->hasScaleBasedVisibility() );
Expand Down Expand Up @@ -713,6 +715,10 @@ void QgsRasterLayerProperties::sync()
leNoDataValue->insert( QLatin1String( "" ) ); leNoDataValue->insert( QLatin1String( "" ) );
} }


mRefreshLayerCheckBox->setChecked( mRasterLayer->hasAutoRefreshEnabled() );
mRefreshLayerIntervalSpinBox->setEnabled( mRasterLayer->hasAutoRefreshEnabled() );
mRefreshLayerIntervalSpinBox->setValue( mRasterLayer->autoRefreshInterval() / 1000.0 );

populateTransparencyTable( mRasterLayer->renderer() ); populateTransparencyTable( mRasterLayer->renderer() );


QgsDebugMsg( "populate colormap tab" ); QgsDebugMsg( "populate colormap tab" );
Expand Down Expand Up @@ -940,6 +946,9 @@ void QgsRasterLayerProperties::apply()
mRasterLayer->setMaximumScale( 1.0 / mScaleRangeWidget->minimumScale() ); mRasterLayer->setMaximumScale( 1.0 / mScaleRangeWidget->minimumScale() );
mRasterLayer->setMinimumScale( 1.0 / mScaleRangeWidget->maximumScale() ); mRasterLayer->setMinimumScale( 1.0 / mScaleRangeWidget->maximumScale() );


mRasterLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
mRasterLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );

//update the legend pixmap //update the legend pixmap
// pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() ); // pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
// pixmapLegend->setScaledContents( true ); // pixmapLegend->setScaledContents( true );
Expand Down
10 changes: 10 additions & 0 deletions src/app/qgsvectorlayerproperties.cpp
Expand Up @@ -322,6 +322,9 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
} }


mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel.get() ); mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel.get() );

connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );

} // QgsVectorLayerProperties ctor } // QgsVectorLayerProperties ctor




Expand Down Expand Up @@ -446,6 +449,10 @@ void QgsVectorLayerProperties::syncToLayer()


mForceRasterCheckBox->setChecked( mLayer->renderer() && mLayer->renderer()->forceRasterRender() ); mForceRasterCheckBox->setChecked( mLayer->renderer() && mLayer->renderer()->forceRasterRender() );


mRefreshLayerCheckBox->setChecked( mLayer->hasAutoRefreshEnabled() );
mRefreshLayerIntervalSpinBox->setEnabled( mLayer->hasAutoRefreshEnabled() );
mRefreshLayerIntervalSpinBox->setValue( mLayer->autoRefreshInterval() / 1000.0 );

// load appropriate symbology page (V1 or V2) // load appropriate symbology page (V1 or V2)
updateSymbologyPage(); updateSymbologyPage();


Expand Down Expand Up @@ -583,6 +590,9 @@ void QgsVectorLayerProperties::apply()
if ( mLayer->renderer() ) if ( mLayer->renderer() )
mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() ); mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() );


mLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
mLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );

mOldJoins = mLayer->vectorJoins(); mOldJoins = mLayer->vectorJoins();


//save variables //save variables
Expand Down
2 changes: 1 addition & 1 deletion src/browser/qgsbrowser.cpp
Expand Up @@ -439,7 +439,7 @@ void QgsBrowser::updateCurrentTab()
QgsRasterLayer *rlayer = qobject_cast< QgsRasterLayer * >( mLayer ); QgsRasterLayer *rlayer = qobject_cast< QgsRasterLayer * >( mLayer );
if ( rlayer ) if ( rlayer )
{ {
connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, rlayer, &QgsRasterLayer::triggerRepaint ); connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, rlayer, [rlayer] { rlayer->triggerRepaint(); } );
connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, mapCanvas, &QgsMapCanvas::refresh ); connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, mapCanvas, &QgsMapCanvas::refresh );
} }
} }
Expand Down
45 changes: 43 additions & 2 deletions src/core/qgsmaplayer.cpp
Expand Up @@ -83,6 +83,7 @@ QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type,
mScaleBasedVisibility = false; mScaleBasedVisibility = false;


connect( mStyleManager, &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsMapLayer::styleChanged ); connect( mStyleManager, &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsMapLayer::styleChanged );
connect( &mRefreshTimer, &QTimer::timeout, this, [=] { triggerRepaint( true ); } );
} }


QgsMapLayer::~QgsMapLayer() QgsMapLayer::~QgsMapLayer()
Expand Down Expand Up @@ -420,6 +421,9 @@ bool QgsMapLayer::readLayerXml( const QDomElement& layerElement, const QgsProjec
setMinimumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() ); setMinimumScale( layerElement.attribute( QStringLiteral( "minimumScale" ) ).toDouble() );
setMaximumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() ); setMaximumScale( layerElement.attribute( QStringLiteral( "maximumScale" ) ).toDouble() );


setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), 0 ).toInt() );
setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );

QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) ); QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) );
if ( !extentNode.isNull() ) if ( !extentNode.isNull() )
{ {
Expand Down Expand Up @@ -537,6 +541,9 @@ bool QgsMapLayer::writeLayerXml( QDomElement& layerElement, QDomDocument& docume
layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) ); layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
} }


layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer.interval() ) );
layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer.isActive() ? 1 : 0 );

// ID // ID
QDomElement layerId = document.createElement( QStringLiteral( "id" ) ); QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
QDomText layerIdText = document.createTextNode( id() ); QDomText layerIdText = document.createTextNode( id() );
Expand Down Expand Up @@ -857,6 +864,40 @@ bool QgsMapLayer::hasScaleBasedVisibility() const
return mScaleBasedVisibility; return mScaleBasedVisibility;
} }


bool QgsMapLayer::hasAutoRefreshEnabled() const
{
return mRefreshTimer.isActive();
}

int QgsMapLayer::autoRefreshInterval() const
{
return mRefreshTimer.interval();
}

void QgsMapLayer::setAutoRefreshInterval( int interval )
{
if ( interval <= 0 )
{
mRefreshTimer.stop();
mRefreshTimer.setInterval( 0 );
}
else
{
mRefreshTimer.setInterval( interval );
}
emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
}

void QgsMapLayer::setAutoRefreshEnabled( bool enabled )
{
if ( !enabled )
mRefreshTimer.stop();
else if ( mRefreshTimer.interval() > 0 )
mRefreshTimer.start();

emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
}

void QgsMapLayer::setMinimumScale( double scale ) void QgsMapLayer::setMinimumScale( double scale )
{ {
mMinScale = scale; mMinScale = scale;
Expand Down Expand Up @@ -1591,9 +1632,9 @@ QgsMapLayerStyleManager* QgsMapLayer::styleManager() const
return mStyleManager; return mStyleManager;
} }


void QgsMapLayer::triggerRepaint() void QgsMapLayer::triggerRepaint( bool deferredUpdate )
{ {
emit repaintRequested(); emit repaintRequested( deferredUpdate );
} }


QString QgsMapLayer::metadata() const QString QgsMapLayer::metadata() const
Expand Down
60 changes: 57 additions & 3 deletions src/core/qgsmaplayer.h
Expand Up @@ -53,6 +53,7 @@ class CORE_EXPORT QgsMapLayer : public QObject
Q_OBJECT Q_OBJECT


Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged ) Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged )
Q_PROPERTY( int autoRefreshInterval READ autoRefreshInterval WRITE setAutoRefreshInterval NOTIFY autoRefreshIntervalChanged )


public: public:


Expand Down Expand Up @@ -646,6 +647,44 @@ class CORE_EXPORT QgsMapLayer : public QObject
*/ */
bool hasScaleBasedVisibility() const; bool hasScaleBasedVisibility() const;


/**
* Returns true if auto refresh is enabled for the layer.
* @note added in QGIS 3.0
* @see autoRefreshInterval()
* @see setAutoRefreshEnabled()
*/
bool hasAutoRefreshEnabled() const;

/**
* Returns the auto refresh interval (in milliseconds). Note that
* auto refresh is only active when hasAutoRefreshEnabled() is true.
* @note added in QGIS 3.0
* @see autoRefreshEnabled()
* @see setAutoRefreshInterval()
*/
int autoRefreshInterval() const;

/**
* Sets the auto refresh interval (in milliseconds) for the layer. This
* will cause the layer to be automatically redrawn on a matching interval.
* Note that auto refresh must be enabled by calling setAutoRefreshEnabled().
*
* Note that auto refresh triggers deferred repaints of the layer. Any map
* canvas must be refreshed separately in order to view the refreshed layer.
* @note added in QGIS 3.0
* @see autoRefreshInterval()
* @see setAutoRefreshEnabled()
*/
void setAutoRefreshInterval( int interval );

/**
* Sets whether auto refresh is enabled for the layer.
* @note added in QGIS 3.0
* @see hasAutoRefreshEnabled()
* @see setAutoRefreshInterval()
*/
void setAutoRefreshEnabled( bool enabled );

public slots: public slots:


//! Event handler for when a coordinate transform fails due to bad vertex error //! Event handler for when a coordinate transform fails due to bad vertex error
Expand Down Expand Up @@ -678,12 +717,14 @@ class CORE_EXPORT QgsMapLayer : public QObject
void setScaleBasedVisibility( const bool enabled ); void setScaleBasedVisibility( const bool enabled );


/** /**
* Will advice the map canvas (and any other interested party) that this layer requires to be repainted. * Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
* Will emit a repaintRequested() signal. * Will emit a repaintRequested() signal.
* If \a deferredUpdate is true then the layer will only be repainted when the canvas is next
* re-rendered, and will not trigger any canvas redraws itself.
* *
* @note in 2.6 function moved from vector/raster subclasses to QgsMapLayer * @note in 2.6 function moved from vector/raster subclasses to QgsMapLayer
*/ */
void triggerRepaint(); void triggerRepaint( bool deferredUpdate = false );


//! \brief Obtain Metadata for this layer //! \brief Obtain Metadata for this layer
virtual QString metadata() const; virtual QString metadata() const;
Expand Down Expand Up @@ -732,8 +773,10 @@ class CORE_EXPORT QgsMapLayer : public QObject


/** By emitting this signal the layer tells that either appearance or content have been changed /** By emitting this signal the layer tells that either appearance or content have been changed
* and any view showing the rendered layer should refresh itself. * and any view showing the rendered layer should refresh itself.
* If \a deferredUpdate is true then the layer will only be repainted when the canvas is next
* re-rendered, and will not trigger any canvas redraws itself.
*/ */
void repaintRequested(); void repaintRequested( bool deferredUpdate = false );


//! This is used to send a request that any mapcanvas using this layer update its extents //! This is used to send a request that any mapcanvas using this layer update its extents
void recalculateExtents() const; void recalculateExtents() const;
Expand Down Expand Up @@ -782,6 +825,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
*/ */
void willBeDeleted(); void willBeDeleted();


/**
* Emitted when the auto refresh interval changes.
* @see setAutoRefreshInterval()
* @note added in QGIS 3.0
*/
void autoRefreshIntervalChanged( int interval );

protected: protected:
//! Set the extent //! Set the extent
virtual void setExtent( const QgsRectangle &rect ); virtual void setExtent( const QgsRectangle &rect );
Expand Down Expand Up @@ -916,6 +966,10 @@ class CORE_EXPORT QgsMapLayer : public QObject


//! Manager of multiple styles available for a layer (may be null) //! Manager of multiple styles available for a layer (may be null)
QgsMapLayerStyleManager* mStyleManager; QgsMapLayerStyleManager* mStyleManager;

//! Timer for triggering automatic refreshes of the layer
QTimer mRefreshTimer;

}; };


Q_DECLARE_METATYPE( QgsMapLayer* ) Q_DECLARE_METATYPE( QgsMapLayer* )
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsvectorlayer.cpp
Expand Up @@ -164,7 +164,7 @@ QgsVectorLayer::QgsVectorLayer( const QString& vectorLayerPath,
setDataSource( vectorLayerPath, baseName, providerKey, loadDefaultStyleFlag ); setDataSource( vectorLayerPath, baseName, providerKey, loadDefaultStyleFlag );
} }


connect( this, &QgsVectorLayer::selectionChanged, this, &QgsVectorLayer::repaintRequested ); connect( this, &QgsVectorLayer::selectionChanged, this, [=] { emit repaintRequested(); } );
connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded ); connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded );


// Default simplify drawing settings // Default simplify drawing settings
Expand Down

0 comments on commit f2ac60a

Please sign in to comment.