Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE] expression engine's is_layer_visible() (#4045)
  • Loading branch information
nirvn committed Jan 25, 2017
1 parent a61b922 commit ecf1f5a
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
11 changes: 11 additions & 0 deletions 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"}
]
}
42 changes: 42 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -27,6 +27,8 @@
#include "qgsatlascomposition.h"
#include "qgsapplication.h"
#include "qgsmapsettings.h"
#include "qgsmaplayerlistutils.h"

#include <QSettings>
#include <QDir>

Expand Down Expand Up @@ -644,6 +646,43 @@ class GetComposerItemVariables : public QgsScopedExpressionFunction

};

class GetLayerVisibility : public QgsScopedExpressionFunction
{
public:
GetLayerVisibility( QList<QgsMapLayer*> 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<QgsMapLayer*> mLayers;

};

///@endcond

QgsExpressionContextScope* QgsExpressionContextUtils::projectScope( const QgsProject* project )
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -1013,6 +1054,7 @@ void QgsExpressionContextUtils::registerContextFunctions()
{
QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
QgsExpression::registerFunction( new GetComposerItemVariables( nullptr ) );
QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer*>() ) );
}

bool QgsScopedExpressionFunction::usesGeometry( const QgsExpression::NodeFunction* node ) const
Expand Down
42 changes: 42 additions & 0 deletions src/core/qgsmaplayerlistutils.h
Expand Up @@ -51,6 +51,48 @@ inline QStringList _qgis_listQPointerToIDs( const QList< QPointer<QgsMapLayer> >
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
41 changes: 41 additions & 0 deletions tests/src/core/testqgsmapsettings.cpp
Expand Up @@ -18,6 +18,8 @@
#include <math.h>

//header for class being tested
#include "qgsexpression.h"
#include "qgsexpressioncontext.h"
#include "qgsrectangle.h"
#include "qgsmapsettings.h"
#include "qgspoint.h"
Expand All @@ -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;
Expand Down Expand Up @@ -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<QgsMapLayer*> 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" );
Expand All @@ -157,6 +192,12 @@ void TestQgsMapSettings::testMapLayerListUtils()
QList<QgsMapLayer*> 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<QgsMapLayer> > listQPointer = _qgis_listRawToQPointer( listRawSource );

QCOMPARE( listQPointer.count(), 2 );
Expand Down

0 comments on commit ecf1f5a

Please sign in to comment.