diff --git a/resources/function_help/json/is_layer_visible b/resources/function_help/json/is_layer_visible new file mode 100644 index 00000000000..21606d5bc47 --- /dev/null +++ b/resources/function_help/json/is_layer_visible @@ -0,0 +1,11 @@ +{ + "name": "is_layer_visible", + "type": "function", + "description": "Returns true if a specified layer is visible.", + "arguments": [ + {"arg":"layer", "description":"a string, representing either a layer name or layer ID"} + ], + "examples": [ + { "expression":"is_layer_visible('baseraster')", "returns":"True"} + ] +} diff --git a/src/core/qgsexpressioncontext.cpp b/src/core/qgsexpressioncontext.cpp index 7749b45629d..c4a2ea0060c 100644 --- a/src/core/qgsexpressioncontext.cpp +++ b/src/core/qgsexpressioncontext.cpp @@ -27,6 +27,8 @@ #include "qgsatlascomposition.h" #include "qgsapplication.h" #include "qgsmapsettings.h" +#include "qgsmaplayerlistutils.h" + #include #include @@ -644,6 +646,43 @@ class GetComposerItemVariables : public QgsScopedExpressionFunction }; +class GetLayerVisibility : public QgsScopedExpressionFunction +{ + public: + GetLayerVisibility( QList layers ) + : QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpression::ParameterList() << QgsExpression::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) ) + , mLayers( layers ) + {} + + virtual QVariant func( const QVariantList& values, const QgsExpressionContext*, QgsExpression* ) override + { + if ( mLayers.isEmpty() ) + { + return QVariant( false ); + } + + QgsMapLayer* layer = _qgis_findLayer( mLayers, values.at( 0 ).toString() ); + if ( layer ) + { + return QVariant( true ); + } + else + { + return QVariant( false ); + } + } + + QgsScopedExpressionFunction* clone() const override + { + return new GetLayerVisibility( mLayers ); + } + + private: + + const QList mLayers; + +}; + ///@endcond QgsExpressionContextScope* QgsExpressionContextUtils::projectScope( const QgsProject* project ) @@ -807,6 +846,8 @@ QgsExpressionContextScope* QgsExpressionContextUtils::mapSettingsScope( const Qg scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapSettings.destinationCrs().toProj4(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapSettings.mapUnits() ), true ) ); + scope->addFunction( QStringLiteral( "is_layer_visible" ), new GetLayerVisibility( mapSettings.layers() ) ); + return scope; } @@ -1013,6 +1054,7 @@ void QgsExpressionContextUtils::registerContextFunctions() { QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) ); QgsExpression::registerFunction( new GetComposerItemVariables( nullptr ) ); + QgsExpression::registerFunction( new GetLayerVisibility( QList() ) ); } bool QgsScopedExpressionFunction::usesGeometry( const QgsExpression::NodeFunction* node ) const diff --git a/src/core/qgsmaplayerlistutils.h b/src/core/qgsmaplayerlistutils.h index 3ebf8baa01d..b48680122a6 100644 --- a/src/core/qgsmaplayerlistutils.h +++ b/src/core/qgsmaplayerlistutils.h @@ -51,6 +51,48 @@ inline QStringList _qgis_listQPointerToIDs( const QList< QPointer > return lst; } +inline static QgsMapLayer* _qgis_findLayer( const QList< QgsMapLayer*> layers, const QString& identifier ) +{ + QgsMapLayer* matchId = nullptr; + QgsMapLayer* matchName = nullptr; + QgsMapLayer* matchNameInsensitive = nullptr; + + // Look for match against layer IDs + Q_FOREACH ( QgsMapLayer* layer, layers ) + { + if ( !matchId && layer->id() == identifier ) + { + matchId = layer; + break; + } + if ( !matchName && layer->name() == identifier ) + { + matchName = layer; + } + if ( !matchNameInsensitive && QString::compare( layer->name(), identifier, Qt::CaseInsensitive ) == 0 ) + { + matchNameInsensitive = layer; + } + } + + if ( matchId ) + { + return matchId; + } + else if ( matchName ) + { + return matchName; + } + else if ( matchNameInsensitive ) + { + return matchNameInsensitive; + } + else + { + return nullptr; + } +} + ///@endcond #endif // QGSMAPLAYERLISTUTILS_H diff --git a/tests/src/core/testqgsmapsettings.cpp b/tests/src/core/testqgsmapsettings.cpp index cf0a092d247..452af2d6d42 100644 --- a/tests/src/core/testqgsmapsettings.cpp +++ b/tests/src/core/testqgsmapsettings.cpp @@ -18,6 +18,8 @@ #include //header for class being tested +#include "qgsexpression.h" +#include "qgsexpressioncontext.h" #include "qgsrectangle.h" #include "qgsmapsettings.h" #include "qgspoint.h" @@ -34,6 +36,7 @@ class TestQgsMapSettings: public QObject void visibleExtent(); void mapUnitsPerPixel(); void visiblePolygon(); + void testIsLayerVisible(); void testMapLayerListUtils(); private: QString toString( const QPolygonF& p, int decimalPlaces = 2 ) const; @@ -149,6 +152,38 @@ void TestQgsMapSettings::visiblePolygon() QString( "32.32 28.03,103.03 -42.67,67.67 -78.03,-3.03 -7.32" ) ); } +void TestQgsMapSettings::testIsLayerVisible() +{ + QgsVectorLayer* vlA = new QgsVectorLayer( "Point", "a", "memory" ); + QgsVectorLayer* vlB = new QgsVectorLayer( "Point", "b", "memory" ); + + QList layers; + layers << vlA << vlB; + + QgsMapSettings ms; + ms.setLayers( layers ); + QgsExpressionContext context; + context << QgsExpressionContextUtils::mapSettingsScope( ms ); + + // test checking for visible layer by id + QgsExpression e( QString( "is_layer_visible( '%1' )" ).arg( vlA-> id() ) ); + QVariant r = e.evaluate( &context ); + QCOMPARE( r.toBool(), true ); + + // test checking for visible layer by name + QgsExpression e2( QString( "is_layer_visible( '%1' )" ).arg( vlB-> name() ) ); + r = e2.evaluate( &context ); + QCOMPARE( r.toBool(), true ); + + // test checking for non-existant layer + QgsExpression e3( QString( "is_layer_visible( 'non matching name' )" ) ); + r = e3.evaluate( &context ); + QCOMPARE( r.toBool(), false ); + + delete vlA; + delete vlB; +} + void TestQgsMapSettings::testMapLayerListUtils() { QgsVectorLayer* vlA = new QgsVectorLayer( "Point", "a", "memory" ); @@ -157,6 +192,12 @@ void TestQgsMapSettings::testMapLayerListUtils() QList listRawSource; listRawSource << vlA << vlB; + QgsMapLayer* l = _qgis_findLayer( listRawSource, QStringLiteral( "a" ) ); + QCOMPARE( l, vlA ); + + l = _qgis_findLayer( listRawSource, QStringLiteral( "z" ) ); + QCOMPARE( !l, true ); + QList< QPointer > listQPointer = _qgis_listRawToQPointer( listRawSource ); QCOMPARE( listQPointer.count(), 2 );