Skip to content

Commit f2ac60a

Browse files
authored
Merge pull request #4111 from nyalldawson/refresh_layers
[FEATURE] Allow layers to be automatically refreshed at a specified interval
2 parents 787c846 + 38f87a6 commit f2ac60a

19 files changed

+569
-25
lines changed

python/core/qgsmaplayer.sip

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,11 @@ class QgsMapLayer : QObject
603603
*/
604604
bool hasScaleBasedVisibility() const;
605605

606+
bool hasAutoRefreshEnabled() const;
607+
int autoRefreshInterval() const;
608+
void setAutoRefreshInterval( int interval );
609+
void setAutoRefreshEnabled( bool enabled );
610+
606611
public slots:
607612

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

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

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

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

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

738+
void autoRefreshIntervalChanged( int interval );
739+
742740
protected:
743741
/** Set the extent */
744742
virtual void setExtent( const QgsRectangle &rect );

src/app/qgisapp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10408,7 +10408,7 @@ void QgisApp::layersWereAdded( const QList<QgsMapLayer *>& theLayers )
1040810408

1040910409
if ( provider )
1041010410
{
10411-
connect( provider, &QgsDataProvider::dataChanged, layer, &QgsMapLayer::triggerRepaint );
10411+
connect( provider, &QgsDataProvider::dataChanged, layer, [layer] { layer->triggerRepaint(); } );
1041210412
connect( provider, &QgsDataProvider::dataChanged, mMapCanvas, &QgsMapCanvas::refresh );
1041310413
}
1041410414
}

src/app/qgsrasterlayerproperties.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
139139
// enable or disable Build Pyramids button depending on selection in pyramid list
140140
connect( lbxPyramidResolutions, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleBuildPyramidsButton() ) );
141141

142+
connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
143+
142144
// set up the scale based layer visibility stuff....
143145
mScaleRangeWidget->setMapCanvas( mMapCanvas );
144146
chkUseScaleDependentRendering->setChecked( lyr->hasScaleBasedVisibility() );
@@ -713,6 +715,10 @@ void QgsRasterLayerProperties::sync()
713715
leNoDataValue->insert( QLatin1String( "" ) );
714716
}
715717

718+
mRefreshLayerCheckBox->setChecked( mRasterLayer->hasAutoRefreshEnabled() );
719+
mRefreshLayerIntervalSpinBox->setEnabled( mRasterLayer->hasAutoRefreshEnabled() );
720+
mRefreshLayerIntervalSpinBox->setValue( mRasterLayer->autoRefreshInterval() / 1000.0 );
721+
716722
populateTransparencyTable( mRasterLayer->renderer() );
717723

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

949+
mRasterLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
950+
mRasterLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
951+
943952
//update the legend pixmap
944953
// pixmapLegend->setPixmap( mRasterLayer->legendAsPixmap() );
945954
// pixmapLegend->setScaledContents( true );

src/app/qgsvectorlayerproperties.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
322322
}
323323

324324
mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel.get() );
325+
326+
connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
327+
325328
} // QgsVectorLayerProperties ctor
326329

327330

@@ -446,6 +449,10 @@ void QgsVectorLayerProperties::syncToLayer()
446449

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

452+
mRefreshLayerCheckBox->setChecked( mLayer->hasAutoRefreshEnabled() );
453+
mRefreshLayerIntervalSpinBox->setEnabled( mLayer->hasAutoRefreshEnabled() );
454+
mRefreshLayerIntervalSpinBox->setValue( mLayer->autoRefreshInterval() / 1000.0 );
455+
449456
// load appropriate symbology page (V1 or V2)
450457
updateSymbologyPage();
451458

@@ -583,6 +590,9 @@ void QgsVectorLayerProperties::apply()
583590
if ( mLayer->renderer() )
584591
mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() );
585592

593+
mLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
594+
mLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
595+
586596
mOldJoins = mLayer->vectorJoins();
587597

588598
//save variables

src/browser/qgsbrowser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ void QgsBrowser::updateCurrentTab()
439439
QgsRasterLayer *rlayer = qobject_cast< QgsRasterLayer * >( mLayer );
440440
if ( rlayer )
441441
{
442-
connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, rlayer, &QgsRasterLayer::triggerRepaint );
442+
connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, rlayer, [rlayer] { rlayer->triggerRepaint(); } );
443443
connect( rlayer->dataProvider(), &QgsRasterDataProvider::dataChanged, mapCanvas, &QgsMapCanvas::refresh );
444444
}
445445
}

src/core/qgsmaplayer.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type,
8383
mScaleBasedVisibility = false;
8484

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

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

424+
setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), 0 ).toInt() );
425+
setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
426+
423427
QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) );
424428
if ( !extentNode.isNull() )
425429
{
@@ -537,6 +541,9 @@ bool QgsMapLayer::writeLayerXml( QDomElement& layerElement, QDomDocument& docume
537541
layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
538542
}
539543

544+
layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer.interval() ) );
545+
layerElement.setAttribute( QStringLiteral( "autoRefreshEnabled" ), mRefreshTimer.isActive() ? 1 : 0 );
546+
540547
// ID
541548
QDomElement layerId = document.createElement( QStringLiteral( "id" ) );
542549
QDomText layerIdText = document.createTextNode( id() );
@@ -857,6 +864,40 @@ bool QgsMapLayer::hasScaleBasedVisibility() const
857864
return mScaleBasedVisibility;
858865
}
859866

867+
bool QgsMapLayer::hasAutoRefreshEnabled() const
868+
{
869+
return mRefreshTimer.isActive();
870+
}
871+
872+
int QgsMapLayer::autoRefreshInterval() const
873+
{
874+
return mRefreshTimer.interval();
875+
}
876+
877+
void QgsMapLayer::setAutoRefreshInterval( int interval )
878+
{
879+
if ( interval <= 0 )
880+
{
881+
mRefreshTimer.stop();
882+
mRefreshTimer.setInterval( 0 );
883+
}
884+
else
885+
{
886+
mRefreshTimer.setInterval( interval );
887+
}
888+
emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
889+
}
890+
891+
void QgsMapLayer::setAutoRefreshEnabled( bool enabled )
892+
{
893+
if ( !enabled )
894+
mRefreshTimer.stop();
895+
else if ( mRefreshTimer.interval() > 0 )
896+
mRefreshTimer.start();
897+
898+
emit autoRefreshIntervalChanged( mRefreshTimer.isActive() ? mRefreshTimer.interval() : 0 );
899+
}
900+
860901
void QgsMapLayer::setMinimumScale( double scale )
861902
{
862903
mMinScale = scale;
@@ -1591,9 +1632,9 @@ QgsMapLayerStyleManager* QgsMapLayer::styleManager() const
15911632
return mStyleManager;
15921633
}
15931634

1594-
void QgsMapLayer::triggerRepaint()
1635+
void QgsMapLayer::triggerRepaint( bool deferredUpdate )
15951636
{
1596-
emit repaintRequested();
1637+
emit repaintRequested( deferredUpdate );
15971638
}
15981639

15991640
QString QgsMapLayer::metadata() const

src/core/qgsmaplayer.h

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class CORE_EXPORT QgsMapLayer : public QObject
5353
Q_OBJECT
5454

5555
Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged )
56+
Q_PROPERTY( int autoRefreshInterval READ autoRefreshInterval WRITE setAutoRefreshInterval NOTIFY autoRefreshIntervalChanged )
5657

5758
public:
5859

@@ -646,6 +647,44 @@ class CORE_EXPORT QgsMapLayer : public QObject
646647
*/
647648
bool hasScaleBasedVisibility() const;
648649

650+
/**
651+
* Returns true if auto refresh is enabled for the layer.
652+
* @note added in QGIS 3.0
653+
* @see autoRefreshInterval()
654+
* @see setAutoRefreshEnabled()
655+
*/
656+
bool hasAutoRefreshEnabled() const;
657+
658+
/**
659+
* Returns the auto refresh interval (in milliseconds). Note that
660+
* auto refresh is only active when hasAutoRefreshEnabled() is true.
661+
* @note added in QGIS 3.0
662+
* @see autoRefreshEnabled()
663+
* @see setAutoRefreshInterval()
664+
*/
665+
int autoRefreshInterval() const;
666+
667+
/**
668+
* Sets the auto refresh interval (in milliseconds) for the layer. This
669+
* will cause the layer to be automatically redrawn on a matching interval.
670+
* Note that auto refresh must be enabled by calling setAutoRefreshEnabled().
671+
*
672+
* Note that auto refresh triggers deferred repaints of the layer. Any map
673+
* canvas must be refreshed separately in order to view the refreshed layer.
674+
* @note added in QGIS 3.0
675+
* @see autoRefreshInterval()
676+
* @see setAutoRefreshEnabled()
677+
*/
678+
void setAutoRefreshInterval( int interval );
679+
680+
/**
681+
* Sets whether auto refresh is enabled for the layer.
682+
* @note added in QGIS 3.0
683+
* @see hasAutoRefreshEnabled()
684+
* @see setAutoRefreshInterval()
685+
*/
686+
void setAutoRefreshEnabled( bool enabled );
687+
649688
public slots:
650689

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

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

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

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

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

828+
/**
829+
* Emitted when the auto refresh interval changes.
830+
* @see setAutoRefreshInterval()
831+
* @note added in QGIS 3.0
832+
*/
833+
void autoRefreshIntervalChanged( int interval );
834+
785835
protected:
786836
//! Set the extent
787837
virtual void setExtent( const QgsRectangle &rect );
@@ -916,6 +966,10 @@ class CORE_EXPORT QgsMapLayer : public QObject
916966

917967
//! Manager of multiple styles available for a layer (may be null)
918968
QgsMapLayerStyleManager* mStyleManager;
969+
970+
//! Timer for triggering automatic refreshes of the layer
971+
QTimer mRefreshTimer;
972+
919973
};
920974

921975
Q_DECLARE_METATYPE( QgsMapLayer* )

src/core/qgsvectorlayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ QgsVectorLayer::QgsVectorLayer( const QString& vectorLayerPath,
164164
setDataSource( vectorLayerPath, baseName, providerKey, loadDefaultStyleFlag );
165165
}
166166

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

170170
// Default simplify drawing settings

0 commit comments

Comments
 (0)