Skip to content

Commit

Permalink
[annotations] Add linked layer option for annotation layers
Browse files Browse the repository at this point in the history
Adds a new "Linked layer" setting to the render page for annotation
layers, which allows users to optionally set a linked visibility
layer for the annotation layer. If set, then the annotations will
only be drawn when the linked layer is visible in the map.

This is designed to mimic the similar linked layer option for
the older annotation framework, in order to close the feature
gap between old vs new annotations

Refs qgis/QGIS-Enhancement-Proposals#269
  • Loading branch information
nyalldawson committed Aug 1, 2024
1 parent ea64be6 commit 5f4d6ff
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@




class QgsAnnotationLayer : QgsMapLayer
{
%Docstring(signature="appended")
Expand Down Expand Up @@ -170,6 +169,8 @@ Returns ``True`` if the operation was successfully applied.

virtual QString htmlMetadata() const;

virtual void resolveReferences( QgsProject *project );


QgsPaintEffect *paintEffect() const;
%Docstring
Expand All @@ -189,6 +190,26 @@ Ownership is transferred to the renderer.
.. seealso:: :py:func:`paintEffect`

.. versionadded:: 3.22
%End

QgsMapLayer *linkedVisibilityLayer();
%Docstring
Returns a linked layer, where the items in this annotation layer
will only be visible when the linked layer is also visible.

.. seealso:: :py:func:`setLinkedVisibilityLayer`

.. versionadded:: 3.40
%End

void setLinkedVisibilityLayer( QgsMapLayer *layer );
%Docstring
Sets a linked ``layer``, where the items in this annotation layer
will only be visible when the linked layer is also visible.

.. seealso:: :py:func:`linkedVisibilityLayer`

.. versionadded:: 3.40
%End

};
Expand Down
23 changes: 22 additions & 1 deletion python/core/auto_generated/annotations/qgsannotationlayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@




class QgsAnnotationLayer : QgsMapLayer
{
%Docstring(signature="appended")
Expand Down Expand Up @@ -170,6 +169,8 @@ Returns ``True`` if the operation was successfully applied.

virtual QString htmlMetadata() const;

virtual void resolveReferences( QgsProject *project );


QgsPaintEffect *paintEffect() const;
%Docstring
Expand All @@ -189,6 +190,26 @@ Ownership is transferred to the renderer.
.. seealso:: :py:func:`paintEffect`

.. versionadded:: 3.22
%End

QgsMapLayer *linkedVisibilityLayer();
%Docstring
Returns a linked layer, where the items in this annotation layer
will only be visible when the linked layer is also visible.

.. seealso:: :py:func:`setLinkedVisibilityLayer`

.. versionadded:: 3.40
%End

void setLinkedVisibilityLayer( QgsMapLayer *layer );
%Docstring
Sets a linked ``layer``, where the items in this annotation layer
will only be visible when the linked layer is also visible.

.. seealso:: :py:func:`linkedVisibilityLayer`

.. versionadded:: 3.40
%End

};
Expand Down
6 changes: 6 additions & 0 deletions src/app/annotations/qgsannotationlayerproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ QgsAnnotationLayerProperties::QgsAnnotationLayerProperties( QgsAnnotationLayer *
{
setupUi( this );

mLayerComboBox->setAllowEmptyLayer( true );

connect( this, &QDialog::accepted, this, &QgsAnnotationLayerProperties::apply );
connect( this, &QDialog::rejected, this, &QgsAnnotationLayerProperties::rollback );
connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsAnnotationLayerProperties::apply );
Expand Down Expand Up @@ -98,6 +100,8 @@ void QgsAnnotationLayerProperties::apply()
if ( mPaintEffect )
mLayer->setPaintEffect( mPaintEffect->clone() );

mLayer->setLinkedVisibilityLayer( mLayerComboBox->currentLayer() );

for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
w->apply();

Expand Down Expand Up @@ -145,6 +149,8 @@ void QgsAnnotationLayerProperties::syncToLayer()
mEffectWidget->setPaintEffect( mPaintEffect.get() );
}

mLayerComboBox->setLayer( mLayer->linkedVisibilityLayer() );

for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
w->syncToLayer( mLayer );
}
Expand Down
38 changes: 38 additions & 0 deletions src/core/annotations/qgsannotationlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ QgsAnnotationLayer *QgsAnnotationLayer::clone() const
if ( mPaintEffect )
layer->setPaintEffect( mPaintEffect->clone() );

layer->mLinkedLayer = mLinkedLayer;

return layer.release();
}

Expand Down Expand Up @@ -387,6 +389,14 @@ bool QgsAnnotationLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext
readItems( layerNode, errorMsg, context );
readSymbology( layerNode, errorMsg, context );

{
const QString layerId = layerNode.toElement().attribute( QStringLiteral( "linkedLayer" ) );
const QString layerName = layerNode.toElement().attribute( QStringLiteral( "linkedLayerName" ) );
const QString layerSource = layerNode.toElement().attribute( QStringLiteral( "linkedLayerSource" ) );
const QString layerProvider = layerNode.toElement().attribute( QStringLiteral( "linkedLayerProvider" ) );
mLinkedLayer = QgsMapLayerRef( layerId, layerName, layerSource, layerProvider );
}

triggerRepaint();

return mValid;
Expand All @@ -407,6 +417,14 @@ bool QgsAnnotationLayer::writeXml( QDomNode &layer_node, QDomDocument &doc, cons

mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( Qgis::LayerType::Annotation ) );

if ( mLinkedLayer )
{
mapLayerNode.setAttribute( QStringLiteral( "linkedLayer" ), mLinkedLayer.layerId );
mapLayerNode.setAttribute( QStringLiteral( "linkedLayerName" ), mLinkedLayer.name );
mapLayerNode.setAttribute( QStringLiteral( "linkedLayerSource" ), mLinkedLayer.source );
mapLayerNode.setAttribute( QStringLiteral( "linkedLayerProvider" ), mLinkedLayer.provider );
}

QString errorMsg;
writeItems( layer_node, doc, errorMsg, context );

Expand Down Expand Up @@ -642,6 +660,11 @@ QString QgsAnnotationLayer::htmlMetadata() const
return metadata;
}

void QgsAnnotationLayer::resolveReferences( QgsProject *project )
{
mLinkedLayer.resolve( project );
}

QgsPaintEffect *QgsAnnotationLayer::paintEffect() const
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Expand All @@ -656,6 +679,21 @@ void QgsAnnotationLayer::setPaintEffect( QgsPaintEffect *effect )
mPaintEffect.reset( effect );
}

QgsMapLayer *QgsAnnotationLayer::linkedVisibilityLayer()
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS

return mLinkedLayer.get();
}

void QgsAnnotationLayer::setLinkedVisibilityLayer( QgsMapLayer *layer )
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS

mLinkedLayer.setLayer( layer );
triggerRepaint();
}


//
// QgsAnnotationLayerDataProvider
Expand Down
23 changes: 22 additions & 1 deletion src/core/annotations/qgsannotationlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include "qgis_sip.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerrenderer.h"

#include "qgsmaplayerref.h"

class QgsAnnotationItem;
class QgsAbstractAnnotationItemEditOperation;
Expand Down Expand Up @@ -185,6 +185,7 @@ class CORE_EXPORT QgsAnnotationLayer : public QgsMapLayer
QgsDataProvider *dataProvider() override;
const QgsDataProvider *dataProvider() const override SIP_SKIP;
QString htmlMetadata() const override;
void resolveReferences( QgsProject *project ) override;

/**
* Returns the current paint effect for the layer.
Expand All @@ -203,6 +204,24 @@ class CORE_EXPORT QgsAnnotationLayer : public QgsMapLayer
*/
void setPaintEffect( QgsPaintEffect *effect SIP_TRANSFER );

/**
* Returns a linked layer, where the items in this annotation layer
* will only be visible when the linked layer is also visible.
*
* \see setLinkedVisibilityLayer()
* \since QGIS 3.40
*/
QgsMapLayer *linkedVisibilityLayer();

/**
* Sets a linked \a layer, where the items in this annotation layer
* will only be visible when the linked layer is also visible.
*
* \see linkedVisibilityLayer()
* \since QGIS 3.40
*/
void setLinkedVisibilityLayer( QgsMapLayer *layer );

private:

QStringList queryIndex( const QgsRectangle &bounds, QgsFeedback *feedback = nullptr ) const;
Expand All @@ -219,6 +238,8 @@ class CORE_EXPORT QgsAnnotationLayer : public QgsMapLayer

std::unique_ptr< QgsPaintEffect > mPaintEffect;

QgsMapLayerRef mLinkedLayer;

friend class QgsAnnotationLayerRenderer;

};
Expand Down
9 changes: 9 additions & 0 deletions src/core/annotations/qgsannotationlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ QgsAnnotationLayerRenderer::QgsAnnotationLayerRenderer( QgsAnnotationLayer *laye
, mFeedback( std::make_unique< QgsFeedback >() )
, mLayerOpacity( layer->opacity() )
{
if ( QgsMapLayer *linkedLayer = layer->linkedVisibilityLayer() )
{
if ( !context.customProperties().value( QStringLiteral( "visible_layer_ids" ) ).toList().contains( linkedLayer->id() ) )
{
mReadyToCompose = true;
return;
}
}

// Clone items from layer which fall inside the rendered extent
// Because some items have scale dependent bounds, we have to accept some limitations here.
// first, we can use the layer's spatial index to very quickly retrieve items we know will fall within the visible
Expand Down
1 change: 1 addition & 0 deletions src/core/project/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2375,6 +2375,7 @@ bool QgsProject::readProjectFile( const QString &filename, Qgis::ProjectReadFlag
{
it.value()->resolveReferences( this );
}
mMainAnnotationLayer->resolveReferences( this );

mLayerTreeRegistryBridge->setEnabled( true );

Expand Down
31 changes: 24 additions & 7 deletions src/gui/qgsmapcanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,13 @@ void QgsMapCanvas::setLayers( const QList<QgsMapLayer *> &layers )

void QgsMapCanvas::setLayersPrivate( const QList<QgsMapLayer *> &layers )
{
QList<QgsMapLayer *> oldLayers = mSettings.layers();
const QList<QgsMapLayer *> oldLayers = mSettings.layers();

// update only if needed
if ( layers == oldLayers )
return;

const auto constOldLayers = oldLayers;
for ( QgsMapLayer *layer : constOldLayers )
for ( QgsMapLayer *layer : oldLayers )
{
disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapCanvas::layerRepaintRequested );
disconnect( layer, &QgsMapLayer::autoRefreshIntervalChanged, this, &QgsMapCanvas::updateAutoRefreshTimer );
Expand Down Expand Up @@ -451,8 +450,7 @@ void QgsMapCanvas::setLayersPrivate( const QList<QgsMapLayer *> &layers )

mSettings.setLayers( layers );

const auto constLayers = layers;
for ( QgsMapLayer *layer : constLayers )
for ( QgsMapLayer *layer : std::as_const( layers ) )
{
if ( !layer )
continue;
Expand Down Expand Up @@ -754,6 +752,24 @@ void QgsMapCanvas::refresh()
mRenderedItemResultsOutdated = true;
}

QList< QgsMapLayer * > filterLayersForRender( const QList< QgsMapLayer * > &layers )
{
QList<QgsMapLayer *> filteredLayers;
for ( QgsMapLayer *layer : layers )
{
if ( QgsAnnotationLayer *annotationLayer = qobject_cast< QgsAnnotationLayer * >( layer ) )
{
if ( QgsMapLayer *linkedLayer = annotationLayer->linkedVisibilityLayer() )
{
if ( !layers.contains( linkedLayer ) )
continue;
}
}
filteredLayers.append( layer );
}
return filteredLayers;
}

void QgsMapCanvas::refreshMap()
{
Q_ASSERT( mRefreshScheduled );
Expand Down Expand Up @@ -810,7 +826,8 @@ void QgsMapCanvas::refreshMap()
QgsMapSettings renderSettings = mSettings;
QList<QgsMapLayer *> allLayers = renderSettings.layers();
allLayers.insert( 0, QgsProject::instance()->mainAnnotationLayer() );
renderSettings.setLayers( allLayers );

renderSettings.setLayers( filterLayersForRender( allLayers ) );

// create the renderer job

Expand Down Expand Up @@ -3577,7 +3594,7 @@ void QgsMapCanvas::startPreviewJob( int number )
{
previewLayers.insert( 0, QgsProject::instance()->mainAnnotationLayer() );
}
jobSettings.setLayers( previewLayers );
jobSettings.setLayers( filterLayersForRender( previewLayers ) );

QgsMapRendererQImageJob *job = new QgsMapRendererSequentialJob( jobSettings );
job->setProperty( "number", number );
Expand Down
Loading

0 comments on commit 5f4d6ff

Please sign in to comment.