Skip to content
Permalink
Browse files
Add API to "expand" out group layer children when querying QgsMapSett…
…ings

for layers

There's two reasons why someone would be calling this method:
- to determine which layers should be rendered by a render job
- to determine which layers are actually visible in the map

Depending on which is required, we either want to expand out
groups and remove the group layer itself from the list (or not)
  • Loading branch information
nyalldawson committed Nov 23, 2021
1 parent 9749706 commit a5b9c7b9a5bec59da4a360dff5f1fff397a70aa2
Showing with 86 additions and 9 deletions.
  1. +8 −2 python/core/auto_generated/qgsmapsettings.sip.in
  2. +33 −5 src/core/qgsmapsettings.cpp
  3. +8 −2 src/core/qgsmapsettings.h
  4. +37 −0 tests/src/core/testqgsmapsettings.cpp
@@ -234,23 +234,29 @@ Returns the magnification factor.
.. versionadded:: 2.16
%End

QStringList layerIds() const;
QStringList layerIds( bool expandGroupLayers = false ) const;
%Docstring
Returns the list of layer IDs which will be rendered in the map.

The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top).

Since QGIS 3.24, if the ``expandGroupLayers`` option is ``True`` then group layers will be converted to
all their child layers.

.. seealso:: :py:func:`layers`

.. seealso:: :py:func:`setLayers`
%End

QList<QgsMapLayer *> layers() const;
QList<QgsMapLayer *> layers( bool expandGroupLayers = false ) const;
%Docstring
Returns the list of layers which will be rendered in the map.

The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top)

Since QGIS 3.24, if the ``expandGroupLayers`` option is ``True`` then group layers will be converted to
all their child layers.

.. seealso:: :py:func:`setLayers`

.. seealso:: :py:func:`layerIds`
@@ -27,6 +27,7 @@
#include "qgsxmlutils.h"
#include "qgsexception.h"
#include "qgsgeometry.h"
#include "qgsgrouplayer.h"

Q_GUI_EXPORT extern int qt_defaultDpiX();

@@ -285,15 +286,42 @@ void QgsMapSettings::setDpiTarget( double dpi )
mDpiTarget = dpi;
}

QStringList QgsMapSettings::layerIds() const
QStringList QgsMapSettings::layerIds( bool expandGroupLayers ) const
{
return _qgis_listQPointerToIDs( mLayers );
const QList<QgsMapLayer * > mapLayers = layers( expandGroupLayers );
QStringList res;
res.reserve( mapLayers.size() );
for ( const QgsMapLayer *layer : mapLayers )
res << layer->id();
return res;
}


QList<QgsMapLayer *> QgsMapSettings::layers() const
QList<QgsMapLayer *> QgsMapSettings::layers( bool expandGroupLayers ) const
{
return _qgis_listQPointerToRaw( mLayers );
const QList<QgsMapLayer *> actualLayers = _qgis_listQPointerToRaw( mLayers );
if ( !expandGroupLayers )
return actualLayers;

QList< QgsMapLayer * > result;

std::function< void( const QList< QgsMapLayer * >& layers ) > expandLayers;
expandLayers = [&result, &expandLayers]( const QList< QgsMapLayer * > &layers )
{
for ( QgsMapLayer *layer : layers )
{
if ( QgsGroupLayer *groupLayer = qobject_cast< QgsGroupLayer * >( layer ) )
{
expandLayers( groupLayer->childLayers() );
}
else
{
result << layer;
}
}
};

expandLayers( actualLayers );
return result;
}

void QgsMapSettings::setLayers( const QList<QgsMapLayer *> &layers )
@@ -244,20 +244,26 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
*
* The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top).
*
* Since QGIS 3.24, if the \a expandGroupLayers option is TRUE then group layers will be converted to
* all their child layers.
*
* \see layers()
* \see setLayers()
*/
QStringList layerIds() const;
QStringList layerIds( bool expandGroupLayers = false ) const;

/**
* Returns the list of layers which will be rendered in the map.
*
* The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top)
*
* Since QGIS 3.24, if the \a expandGroupLayers option is TRUE then group layers will be converted to
* all their child layers.
*
* \see setLayers()
* \see layerIds()
*/
QList<QgsMapLayer *> layers() const;
QList<QgsMapLayer *> layers( bool expandGroupLayers = false ) const;

/**
* Sets the list of \a layers to render in the map.
@@ -31,6 +31,7 @@
#include "qgsexpressioncontextutils.h"
#include "qgsrenderedfeaturehandlerinterface.h"
#include "qgsrendercontext.h"
#include "qgsgrouplayer.h"

class TestHandler : public QgsRenderedFeatureHandlerInterface
{
@@ -66,6 +67,7 @@ class TestQgsMapSettings: public QObject
void testClippingRegions();
void testComputeExtentForScale();
void testComputeScaleForExtent();
void testLayersWithGroupLayers();

private:
QString toString( const QPolygonF &p, int decimalPlaces = 2 ) const;
@@ -685,5 +687,40 @@ void TestQgsMapSettings::testComputeScaleForExtent()
QGSCOMPARENEAR( scale, testScale, 0.001 );
}

void TestQgsMapSettings::testLayersWithGroupLayers()
{
// test retrieving layers from map settings when a QgsGroupLayer is present
QgsMapSettings settings;

std::unique_ptr< QgsVectorLayer > vlA = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point" ), QStringLiteral( "a" ), QStringLiteral( "memory" ) );
std::unique_ptr< QgsVectorLayer > vlB = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point" ), QStringLiteral( "b" ), QStringLiteral( "memory" ) );
std::unique_ptr< QgsVectorLayer > vlC = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point" ), QStringLiteral( "c" ), QStringLiteral( "memory" ) );

QgsGroupLayer::LayerOptions options( ( QgsCoordinateTransformContext() ) );
QgsGroupLayer groupLayer( QStringLiteral( "group" ), options );
groupLayer.setChildLayers( { vlB.get(), vlC.get() } );
settings.setLayers( { vlA.get(), &groupLayer } );

// without expanding groups
QCOMPARE( settings.layers().size(), 2 );
QCOMPARE( settings.layers().at( 0 ), vlA.get() );
QCOMPARE( settings.layers().at( 1 ), &groupLayer );

QCOMPARE( settings.layerIds().size(), 2 );
QCOMPARE( settings.layerIds().at( 0 ), vlA->id() );
QCOMPARE( settings.layerIds().at( 1 ), groupLayer.id() );

// with expanding groups
QCOMPARE( settings.layers( true ).size(), 3 );
QCOMPARE( settings.layers( true ).at( 0 ), vlA.get() );
QCOMPARE( settings.layers( true ).at( 1 ), vlB.get() );
QCOMPARE( settings.layers( true ).at( 2 ), vlC.get() );

QCOMPARE( settings.layerIds( true ).size(), 3 );
QCOMPARE( settings.layerIds( true ).at( 0 ), vlA->id() );
QCOMPARE( settings.layerIds( true ).at( 1 ), vlB->id() );
QCOMPARE( settings.layerIds( true ).at( 2 ), vlC->id() );
}

QGSTEST_MAIN( TestQgsMapSettings )
#include "testqgsmapsettings.moc"

0 comments on commit a5b9c7b

Please sign in to comment.