Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add a bunch of layer related variables, including things like
metadata, extent, crs, feature count, geometry types, etc...
  • Loading branch information
nyalldawson committed Aug 22, 2015
1 parent 1c7a5b2 commit d654227
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 10 deletions.
19 changes: 19 additions & 0 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -385,6 +385,25 @@ class QgsExpressionContextUtils
*/
static QgsExpressionContext createFeatureBasedContext( const QgsFeature& feature, const QgsFields& fields );

/** Sets a layer context variable. This variable will be contained within scopes retrieved via
* layerScope().
* @param layer map layer
* @param name variable name
* @param value variable value
* @see setLayerVariables()
* @see layerScope()
*/
static void setLayerVariable( QgsMapLayer* layer, const QString& name, const QVariant& value );

/** Sets all layer context variables. Existing layer variables will be removed and replaced
* with the variables specified.
* @param layer map layer
* @param variables new set of layer variables
* @see setLayerVariable()
* @see layerScope()
*/
static void setLayerVariables( QgsMapLayer* layer, const QgsStringMap variables );

/** Registers all known core functions provided by QgsExpressionContextScope objects.
*/
static void registerContextFunctions();
Expand Down
10 changes: 10 additions & 0 deletions src/app/qgsvectorlayerproperties.cpp
Expand Up @@ -50,6 +50,7 @@
#include "qgsquerybuilder.h"
#include "qgsdatasourceuri.h"
#include "qgsrendererv2.h"
#include "qgsexpressioncontext.h"

#include <QMessageBox>
#include <QDir>
Expand Down Expand Up @@ -500,6 +501,12 @@ void QgsVectorLayerProperties::syncToLayer( void )
}
}

mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope() );
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::layerScope( layer ) );
mVariableEditor->reloadContext();
mVariableEditor->setEditableScopeIndex( 2 );

} // syncToLayer()


Expand Down Expand Up @@ -610,6 +617,9 @@ void QgsVectorLayerProperties::apply()

mOldJoins = layer->vectorJoins();

//save variables
QgsExpressionContextUtils::setLayerVariables( layer, mVariableEditor->variablesInActiveScope() );

// update symbology
emit refreshLegend( layer->id() );

Expand Down
79 changes: 78 additions & 1 deletion src/core/qgsexpressioncontext.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsvectorlayer.h"
#include "qgsproject.h"
#include "qgssymbollayerv2utils.h"
#include "qgsgeometry.h"
#include <QSettings>
#include <QDir>

Expand Down Expand Up @@ -497,18 +498,94 @@ QgsExpressionContextScope* QgsExpressionContextUtils::layerScope( QgsMapLayer* l
if ( !layer )
return scope;

//add variables defined in layer properties
QStringList variableNames = layer->customProperty( "variableNames" ).toStringList();
QStringList variableValues = layer->customProperty( "variableValues" ).toStringList();

int varIndex = 0;
foreach ( QString variableName, variableNames )
{
if ( varIndex >= variableValues.length() )
{
break;
}

QVariant varValue = variableValues.at( varIndex );
varIndex++;
scope->setVariable( variableName, varValue );
}

//TODO - add tests for all of these:
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_name", layer->name(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_id", layer->id(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_title", layer->title(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_abstract", layer->abstract(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_keywords", layer->keywordList(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_dataurl", layer->dataUrl(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_attribution", layer->attribution(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_attributionurl", layer->attributionUrl(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_source", layer->publicSource(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_minscale", layer->minimumScale(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_maxscale", layer->maximumScale(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_crs", layer->crs().authid(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_crsdefinition", layer->crs().toProj4(), true ) );

QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_extent", QVariant::fromValue( *extentGeom ), true ) );
delete extentGeom;

QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
if ( vLayer )
{
scope->addVariable( QgsExpressionContextScope::StaticVariable( "_fields_", QVariant::fromValue( vLayer->pendingFields() ), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_geometrytype", vLayer->type(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_storagetype", vLayer->storageType(), true ) );
QString typeString( QGis::vectorGeometryType( vLayer->geometryType() ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_geometrytype", typeString, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "layer_featurecount", QVariant::fromValue( vLayer->featureCount() ), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( "_fields_", QVariant::fromValue( vLayer->fields() ), true ) );
}

//TODO - add functions. Possibilities include:
//is_selected
//field summary stats

return scope;
}

void QgsExpressionContextUtils::setLayerVariable( QgsMapLayer* layer, const QString& name, const QVariant& value )
{
if ( !layer )
return;

//write variable to layer
QStringList variableNames = layer->customProperty( "variableNames" ).toStringList();
QStringList variableValues = layer->customProperty( "variableValues" ).toStringList();

variableNames << name;
variableValues << value.toString();

layer->setCustomProperty( "variableNames", variableNames );
layer->setCustomProperty( "variableValues", variableValues );
}

void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer* layer, const QgsStringMap variables )
{
if ( !layer )
return;

QStringList variableNames;
QStringList variableValues;

Q_FOREACH ( QString variable, variables.keys() )
{
variableNames << variable;
variableValues << variables.value( variable );
}

layer->setCustomProperty( "variableNames", variableNames );
layer->setCustomProperty( "variableValues", variableValues );
}

QgsExpressionContext QgsExpressionContextUtils::createFeatureBasedContext( const QgsFeature &feature, const QgsFields &fields )
{
QgsExpressionContextScope* scope = new QgsExpressionContextScope();
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -411,6 +411,25 @@ class CORE_EXPORT QgsExpressionContextUtils
*/
static QgsExpressionContextScope* layerScope( QgsMapLayer* layer );

/** Sets a layer context variable. This variable will be contained within scopes retrieved via
* layerScope().
* @param layer map layer
* @param name variable name
* @param value variable value
* @see setLayerVariables()
* @see layerScope()
*/
static void setLayerVariable( QgsMapLayer* layer, const QString& name, const QVariant& value );

/** Sets all layer context variables. Existing layer variables will be removed and replaced
* with the variables specified.
* @param layer map layer
* @param variables new set of layer variables
* @see setLayerVariable()
* @see layerScope()
*/
static void setLayerVariables( QgsMapLayer* layer, const QgsStringMap variables );

/** Helper function for creating an expression context which contains just a feature and fields
* collection. Generally this method should not be used as the created context does not include
* standard scopes such as the global and project scopes.
Expand Down
3 changes: 3 additions & 0 deletions src/gui/qgsvariableeditorwidget.cpp
Expand Up @@ -368,6 +368,9 @@ void QgsVariableEditorTree::refreshScopeVariables( QgsExpressionContextScope* sc

foreach ( QString name, scope->variableNames() )
{
if ( name.startsWith( QChar( '_' ) ) )
continue;

QTreeWidgetItem* item;
if ( mVariableToItem.contains( qMakePair( scopeIndex, name ) ) )
{
Expand Down
53 changes: 44 additions & 9 deletions src/ui/qgsvectorlayerpropertiesbase.ui
Expand Up @@ -225,6 +225,15 @@
<normaloff>:/images/themes/default/propertyicons/metadata.svg</normaloff>:/images/themes/default/propertyicons/metadata.svg</iconset>
</property>
</item>
<item>
<property name="text">
<string>Variables</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconExpression.svg</normaloff>:/images/themes/default/mIconExpression.svg</iconset>
</property>
</item>
</widget>
</item>
</layout>
Expand Down Expand Up @@ -264,7 +273,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
<number>11</number>
</property>
<widget class="QWidget" name="mOptsPage_General">
<layout class="QVBoxLayout" name="verticalLayout_14">
Expand Down Expand Up @@ -591,8 +600,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>730</width>
<height>537</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_18">
Expand Down Expand Up @@ -692,8 +701,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>730</width>
<height>537</height>
<width>123</width>
<height>38</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_28">
Expand Down Expand Up @@ -774,8 +783,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>730</width>
<height>537</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_20">
Expand Down Expand Up @@ -834,8 +843,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>730</width>
<height>537</height>
<width>721</width>
<height>199</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_32">
Expand Down Expand Up @@ -1735,6 +1744,26 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Variables</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QgsVariableEditorWidget" name="mVariableEditor" native="true">
<property name="settingGroup" stdset="0">
<string notr="true">projectProperties</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
Expand Down Expand Up @@ -1806,6 +1835,12 @@
<extends>QWidget</extends>
<header>qgsscalerangewidget.h</header>
</customwidget>
<customwidget>
<class>QgsVariableEditorWidget</class>
<extends>QWidget</extends>
<header location="global">qgsvariableeditorwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mOptionsListWidget</tabstop>
Expand Down
16 changes: 16 additions & 0 deletions tests/src/core/testqgsexpressioncontext.cpp
Expand Up @@ -554,6 +554,22 @@ void TestQgsExpressionContext::layerScope()
//check that fields were set
QgsFields fromVar = qvariant_cast<QgsFields>( context.variable( QgsExpressionContext::EXPR_FIELDS ) );
QCOMPARE( fromVar, vectorLayer->pendingFields() );

//test setting layer variables
QgsExpressionContextUtils::setLayerVariable( vectorLayer.data(), "testvar", "testval" );
delete layerScope;
layerScope = QgsExpressionContextUtils::layerScope( vectorLayer.data() );
QCOMPARE( layerScope->variable( "testvar" ).toString(), QString( "testval" ) );

QgsStringMap variables;
variables.insert( "var1", "val1" );
variables.insert( "var2", "val2" );
QgsExpressionContextUtils::setLayerVariables( vectorLayer.data(), variables );
delete layerScope;
layerScope = QgsExpressionContextUtils::layerScope( vectorLayer.data() );
QCOMPARE( layerScope->variable( "testvar" ), QVariant() );
QCOMPARE( layerScope->variable( "var1" ).toString(), QString( "val1" ) );
QCOMPARE( layerScope->variable( "var2" ).toString(), QString( "val2" ) );
}

void TestQgsExpressionContext::featureBasedContext()
Expand Down

0 comments on commit d654227

Please sign in to comment.