Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Explicitly tag static variables
  • Loading branch information
m-kuhn committed May 1, 2017
1 parent b9ec373 commit 6593754
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 34 deletions.
15 changes: 13 additions & 2 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -76,7 +76,7 @@ class QgsExpressionContextScope
* @param value initial variable value
* @param readOnly true if variable should not be editable by users
*/
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false );
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false, bool isStatic = false );

/** Variable name */
QString name;
Expand All @@ -86,6 +86,9 @@ class QgsExpressionContextScope

/** True if variable should not be editable by users */
bool readOnly;

//! A static variable can be cached for the lifetime of a context
bool isStatic;
};

/** Constructor for QgsExpressionContextScope
Expand All @@ -109,7 +112,7 @@ class QgsExpressionContextScope
* @param value variable value
* @see addVariable()
*/
void setVariable( const QString &name, const QVariant &value );
void setVariable( const QString &name, const QVariant &value, bool isStatic = false );

/** Adds a variable into the context scope. If a variable with the same name is already set then its
* value is overwritten, otherwise a new variable is added to the scope.
Expand Down Expand Up @@ -162,6 +165,14 @@ class QgsExpressionContextScope
*/
bool isReadOnly( const QString &name ) const;

/**
* Tests whether the variable with the specified \a name is static and can
* be cached.
*
* \note Added in QGIS 3.0
*/
bool isStatic( const QString &name ) const;

/** Returns the count of variables contained within the scope.
*/
int variableCount() const;
Expand Down
13 changes: 8 additions & 5 deletions src/core/qgsexpression.cpp
Expand Up @@ -4322,9 +4322,10 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
varFunction->setIsStaticFunction(
[]( const NodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
{
/* A variable node is static if it has a static name and the name is defined at prepare time
* (e.g. global or layer variables)
* It is not static if a variable is set during iteration (e.g. geom_part variable)
/* A variable node is static if it has a static name and the name can be found at prepare
* time and is tagged with isStatic.
* It is not static if a variable is set during iteration or not tagged isStatic.
* (e.g. geom_part variable)
*/
if ( node->args()->count() > 0 )
{
Expand All @@ -4333,8 +4334,10 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
if ( !argNode->isStatic( parent, context ) )
return false;

if ( fcnGetVariable( QVariantList() << argNode->eval( parent, context ), context, parent ).isValid() )
return true;
QString varName = argNode->eval( parent, context ).toString();

const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
return scope ? scope->isStatic( varName ) : false;
}
return false;
}
Expand Down
54 changes: 30 additions & 24 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -90,17 +90,18 @@ QgsExpressionContextScope::~QgsExpressionContextScope()
qDeleteAll( mFunctions );
}

void QgsExpressionContextScope::setVariable( const QString &name, const QVariant &value )
void QgsExpressionContextScope::setVariable( const QString &name, const QVariant &value, bool isStatic )
{
if ( mVariables.contains( name ) )
{
StaticVariable existing = mVariables.value( name );
existing.value = value;
existing.isStatic = isStatic;
addVariable( existing );
}
else
{
addVariable( QgsExpressionContextScope::StaticVariable( name, value ) );
addVariable( QgsExpressionContextScope::StaticVariable( name, value, false, isStatic ) );
}
}

Expand Down Expand Up @@ -179,6 +180,11 @@ bool QgsExpressionContextScope::isReadOnly( const QString &name ) const
return hasVariable( name ) ? mVariables.value( name ).readOnly : false;
}

bool QgsExpressionContextScope::isStatic( const QString &name ) const
{
return hasVariable( name ) ? mVariables.value( name ).isStatic : false;
}

bool QgsExpressionContextScope::hasFunction( const QString &name ) const
{
return mFunctions.contains( name );
Expand Down Expand Up @@ -545,19 +551,19 @@ QgsExpressionContextScope *QgsExpressionContextUtils::globalScope()

for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
{
scope->setVariable( it.key(), it.value() );
scope->setVariable( it.key(), it.value(), true );
}

//add some extra global variables
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::QGIS_VERSION, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version_no" ), Qgis::QGIS_VERSION_INT, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_short_version" ), QStringLiteral( "%1.%2" ).arg( Qgis::QGIS_VERSION_INT / 10000 ).arg( Qgis::QGIS_VERSION_INT / 100 % 100 ), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::QGIS_RELEASE_NAME, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::QGIS_VERSION, true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version_no" ), Qgis::QGIS_VERSION_INT, true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_short_version" ), QStringLiteral( "%1.%2" ).arg( Qgis::QGIS_VERSION_INT / 10000 ).arg( Qgis::QGIS_VERSION_INT / 100 % 100 ), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::QGIS_RELEASE_NAME, true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true, true ) );

return scope;
}
Expand Down Expand Up @@ -715,17 +721,17 @@ QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsPro

for ( ; it != vars.constEnd(); ++it )
{
scope->setVariable( it.key(), it.value() );
scope->setVariable( it.key(), it.value(), true );
}

//add other known project variables
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), project->fileInfo().filePath(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), project->fileInfo().dir().path(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), project->fileInfo().fileName(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), project->fileInfo().filePath(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), project->fileInfo().dir().path(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), project->fileInfo().fileName(), true, true ) );
QgsCoordinateReferenceSystem projectCrs = project->crs();
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true, true ) );

scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) );
return scope;
Expand Down Expand Up @@ -772,14 +778,14 @@ QgsExpressionContextScope *QgsExpressionContextUtils::layerScope( const QgsMapLa

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

scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true, true ) );

const QgsVectorLayer *vLayer = dynamic_cast< const QgsVectorLayer * >( layer );
const QgsVectorLayer *vLayer = qobject_cast< const QgsVectorLayer * >( layer );
if ( vLayer )
{
scope->setFields( vLayer->fields() );
Expand Down
16 changes: 14 additions & 2 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -127,10 +127,11 @@ class CORE_EXPORT QgsExpressionContextScope
* \param value initial variable value
* \param readOnly true if variable should not be editable by users
*/
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false )
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false, bool isStatic = false )
: name( name )
, value( value )
, readOnly( readOnly )
, isStatic( isStatic )
{}

//! Variable name
Expand All @@ -141,6 +142,9 @@ class CORE_EXPORT QgsExpressionContextScope

//! True if variable should not be editable by users
bool readOnly;

//! A static variable can be cached for the lifetime of a context
bool isStatic;
};

/** Constructor for QgsExpressionContextScope
Expand All @@ -166,7 +170,7 @@ class CORE_EXPORT QgsExpressionContextScope
* \param value variable value
* \see addVariable()
*/
void setVariable( const QString &name, const QVariant &value );
void setVariable( const QString &name, const QVariant &value, bool isStatic = false );

/** Adds a variable into the context scope. If a variable with the same name is already set then its
* value is overwritten, otherwise a new variable is added to the scope.
Expand Down Expand Up @@ -219,6 +223,14 @@ class CORE_EXPORT QgsExpressionContextScope
*/
bool isReadOnly( const QString &name ) const;

/**
* Tests whether the variable with the specified \a name is static and can
* be cached.
*
* \note Added in QGIS 3.0
*/
bool isStatic( const QString &name ) const;

/** Returns the count of variables contained within the scope.
*/
int variableCount() const { return mVariables.count(); }
Expand Down
2 changes: 1 addition & 1 deletion tests/src/python/test_qgsatlascomposition.py
Expand Up @@ -122,7 +122,7 @@ def filename_test(self):
for i in range(0, self.mAtlas.numFeatures()):
self.mAtlas.prepareForFeature(i)
expected = "output_%d" % (i + 1)
assert self.mAtlas.currentFilename() == expected
self.assertEqual(self.mAtlas.currentFilename(), expected)
self.mAtlas.endRender()

def autoscale_render_test(self):
Expand Down

0 comments on commit 6593754

Please sign in to comment.