Explicitly tag static variables

This commit is contained in:
Matthias Kuhn 2017-05-02 00:40:24 +02:00
parent b9ec373f4c
commit 6593754f9d
5 changed files with 66 additions and 34 deletions

View File

@ -76,7 +76,7 @@ class QgsExpressionContextScope
* @param value initial variable value * @param value initial variable value
* @param readOnly true if variable should not be editable by users * @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 */ /** Variable name */
QString name; QString name;
@ -86,6 +86,9 @@ class QgsExpressionContextScope
/** True if variable should not be editable by users */ /** True if variable should not be editable by users */
bool readOnly; bool readOnly;
//! A static variable can be cached for the lifetime of a context
bool isStatic;
}; };
/** Constructor for QgsExpressionContextScope /** Constructor for QgsExpressionContextScope
@ -109,7 +112,7 @@ class QgsExpressionContextScope
* @param value variable value * @param value variable value
* @see addVariable() * @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 /** 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. * value is overwritten, otherwise a new variable is added to the scope.
@ -162,6 +165,14 @@ class QgsExpressionContextScope
*/ */
bool isReadOnly( const QString &name ) const; 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. /** Returns the count of variables contained within the scope.
*/ */
int variableCount() const; int variableCount() const;

View File

@ -4322,9 +4322,10 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
varFunction->setIsStaticFunction( varFunction->setIsStaticFunction(
[]( const NodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context ) []( 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 /* A variable node is static if it has a static name and the name can be found at prepare
* (e.g. global or layer variables) * time and is tagged with isStatic.
* It is not static if a variable is set during iteration (e.g. geom_part variable) * 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 ) if ( node->args()->count() > 0 )
{ {
@ -4333,8 +4334,10 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
if ( !argNode->isStatic( parent, context ) ) if ( !argNode->isStatic( parent, context ) )
return false; return false;
if ( fcnGetVariable( QVariantList() << argNode->eval( parent, context ), context, parent ).isValid() ) QString varName = argNode->eval( parent, context ).toString();
return true;
const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
return scope ? scope->isStatic( varName ) : false;
} }
return false; return false;
} }

View File

@ -90,17 +90,18 @@ QgsExpressionContextScope::~QgsExpressionContextScope()
qDeleteAll( mFunctions ); 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 ) ) if ( mVariables.contains( name ) )
{ {
StaticVariable existing = mVariables.value( name ); StaticVariable existing = mVariables.value( name );
existing.value = value; existing.value = value;
existing.isStatic = isStatic;
addVariable( existing ); addVariable( existing );
} }
else else
{ {
addVariable( QgsExpressionContextScope::StaticVariable( name, value ) ); addVariable( QgsExpressionContextScope::StaticVariable( name, value, false, isStatic ) );
} }
} }
@ -179,6 +180,11 @@ bool QgsExpressionContextScope::isReadOnly( const QString &name ) const
return hasVariable( name ) ? mVariables.value( name ).readOnly : false; 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 bool QgsExpressionContextScope::hasFunction( const QString &name ) const
{ {
return mFunctions.contains( name ); return mFunctions.contains( name );
@ -545,19 +551,19 @@ QgsExpressionContextScope *QgsExpressionContextUtils::globalScope()
for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it ) 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 //add some extra global variables
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_version" ), Qgis::QGIS_VERSION, 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 ) ); 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 ) ); 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 ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_release_name" ), Qgis::QGIS_RELEASE_NAME, true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_platform" ), QgsApplication::platform(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_os_name" ), QgsApplication::osName(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "qgis_locale" ), QgsApplication::locale(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_account_name" ), QgsApplication::userLoginName(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "user_full_name" ), QgsApplication::userFullName(), true, true ) );
return scope; return scope;
} }
@ -715,17 +721,17 @@ QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsPro
for ( ; it != vars.constEnd(); ++it ) for ( ; it != vars.constEnd(); ++it )
{ {
scope->setVariable( it.key(), it.value() ); scope->setVariable( it.key(), it.value(), true );
} }
//add other known project variables //add other known project variables
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), project->fileInfo().filePath(), 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 ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), project->fileInfo().dir().path(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), project->fileInfo().fileName(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), project->fileInfo().fileName(), true, true ) );
QgsCoordinateReferenceSystem projectCrs = project->crs(); QgsCoordinateReferenceSystem projectCrs = project->crs();
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true ) ); scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true, true ) );
scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) ); scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) );
return scope; return scope;
@ -772,14 +778,14 @@ QgsExpressionContextScope *QgsExpressionContextUtils::layerScope( const QgsMapLa
QVariant varValue = variableValues.at( varIndex ); QVariant varValue = variableValues.at( varIndex );
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_name" ), layer->name(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), 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 ) ); 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 ) if ( vLayer )
{ {
scope->setFields( vLayer->fields() ); scope->setFields( vLayer->fields() );

View File

@ -127,10 +127,11 @@ class CORE_EXPORT QgsExpressionContextScope
* \param value initial variable value * \param value initial variable value
* \param readOnly true if variable should not be editable by users * \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 ) : name( name )
, value( value ) , value( value )
, readOnly( readOnly ) , readOnly( readOnly )
, isStatic( isStatic )
{} {}
//! Variable name //! Variable name
@ -141,6 +142,9 @@ class CORE_EXPORT QgsExpressionContextScope
//! True if variable should not be editable by users //! True if variable should not be editable by users
bool readOnly; bool readOnly;
//! A static variable can be cached for the lifetime of a context
bool isStatic;
}; };
/** Constructor for QgsExpressionContextScope /** Constructor for QgsExpressionContextScope
@ -166,7 +170,7 @@ class CORE_EXPORT QgsExpressionContextScope
* \param value variable value * \param value variable value
* \see addVariable() * \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 /** 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. * value is overwritten, otherwise a new variable is added to the scope.
@ -219,6 +223,14 @@ class CORE_EXPORT QgsExpressionContextScope
*/ */
bool isReadOnly( const QString &name ) const; 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. /** Returns the count of variables contained within the scope.
*/ */
int variableCount() const { return mVariables.count(); } int variableCount() const { return mVariables.count(); }

View File

@ -122,7 +122,7 @@ class TestQgsAtlasComposition(unittest.TestCase):
for i in range(0, self.mAtlas.numFeatures()): for i in range(0, self.mAtlas.numFeatures()):
self.mAtlas.prepareForFeature(i) self.mAtlas.prepareForFeature(i)
expected = "output_%d" % (i + 1) expected = "output_%d" % (i + 1)
assert self.mAtlas.currentFilename() == expected self.assertEqual(self.mAtlas.currentFilename(), expected)
self.mAtlas.endRender() self.mAtlas.endRender()
def autoscale_render_test(self): def autoscale_render_test(self):