Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsexpressioncontext.cpp 3 : : ------------------------ 4 : : Date : April 2015 5 : : Copyright : (C) 2015 by Nyall Dawson 6 : : Email : nyall dot dawson at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgsexpressioncontext.h" 17 : : #include "qgslogger.h" 18 : : #include "qgsxmlutils.h" 19 : : #include "qgsexpression.h" 20 : : 21 : 10 : const QString QgsExpressionContext::EXPR_FIELDS( QStringLiteral( "_fields_" ) ); 22 : 10 : const QString QgsExpressionContext::EXPR_ORIGINAL_VALUE( QStringLiteral( "value" ) ); 23 : 10 : const QString QgsExpressionContext::EXPR_SYMBOL_COLOR( QStringLiteral( "symbol_color" ) ); 24 : 10 : const QString QgsExpressionContext::EXPR_SYMBOL_ANGLE( QStringLiteral( "symbol_angle" ) ); 25 : 10 : const QString QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT( QStringLiteral( "geometry_part_count" ) ); 26 : 10 : const QString QgsExpressionContext::EXPR_GEOMETRY_PART_NUM( QStringLiteral( "geometry_part_num" ) ); 27 : 10 : const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT( QStringLiteral( "geometry_point_count" ) ); 28 : 10 : const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM( QStringLiteral( "geometry_point_num" ) ); 29 : 10 : const QString QgsExpressionContext::EXPR_CLUSTER_SIZE( QStringLiteral( "cluster_size" ) ); 30 : 10 : const QString QgsExpressionContext::EXPR_CLUSTER_COLOR( QStringLiteral( "cluster_color" ) ); 31 : : 32 : : // 33 : : // QgsExpressionContextScope 34 : : // 35 : : 36 : 421 : QgsExpressionContextScope::QgsExpressionContextScope( const QString &name ) 37 : 421 : : mName( name ) 38 : : { 39 : : 40 : 421 : } 41 : : 42 : 122 : QgsExpressionContextScope::QgsExpressionContextScope( const QgsExpressionContextScope &other ) 43 : 61 : : mName( other.mName ) 44 : 61 : , mVariables( other.mVariables ) 45 : 61 : , mHasFeature( other.mHasFeature ) 46 : 61 : , mFeature( other.mFeature ) 47 : : { 48 : 61 : QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin(); 49 : 62 : for ( ; it != other.mFunctions.constEnd(); ++it ) 50 : : { 51 : 1 : mFunctions.insert( it.key(), it.value()->clone() ); 52 : 1 : } 53 : 61 : } 54 : : 55 : 199 : QgsExpressionContextScope &QgsExpressionContextScope::operator=( const QgsExpressionContextScope &other ) 56 : : { 57 : 199 : mName = other.mName; 58 : 199 : mVariables = other.mVariables; 59 : 199 : mHasFeature = other.mHasFeature; 60 : 199 : mFeature = other.mFeature; 61 : : 62 : 199 : qDeleteAll( mFunctions ); 63 : 199 : mFunctions.clear(); 64 : 199 : QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin(); 65 : 199 : for ( ; it != other.mFunctions.constEnd(); ++it ) 66 : : { 67 : 0 : mFunctions.insert( it.key(), it.value()->clone() ); 68 : 0 : } 69 : : 70 : 199 : return *this; 71 : : } 72 : : 73 : 479 : QgsExpressionContextScope::~QgsExpressionContextScope() 74 : : { 75 : 479 : qDeleteAll( mFunctions ); 76 : 479 : } 77 : : 78 : 0 : void QgsExpressionContextScope::setVariable( const QString &name, const QVariant &value, bool isStatic ) 79 : : { 80 : 0 : if ( mVariables.contains( name ) ) 81 : : { 82 : 0 : StaticVariable existing = mVariables.value( name ); 83 : 0 : existing.value = value; 84 : 0 : existing.isStatic = isStatic; 85 : 0 : addVariable( existing ); 86 : 0 : } 87 : : else 88 : : { 89 : 0 : addVariable( QgsExpressionContextScope::StaticVariable( name, value, false, isStatic ) ); 90 : : } 91 : 0 : } 92 : : 93 : 1260 : void QgsExpressionContextScope::addVariable( const QgsExpressionContextScope::StaticVariable &variable ) 94 : : { 95 : 1260 : mVariables.insert( variable.name, variable ); 96 : 1260 : } 97 : : 98 : 0 : bool QgsExpressionContextScope::removeVariable( const QString &name ) 99 : : { 100 : 0 : return mVariables.remove( name ) > 0; 101 : : } 102 : : 103 : 0 : bool QgsExpressionContextScope::hasVariable( const QString &name ) const 104 : : { 105 : 0 : return mVariables.contains( name ); 106 : : } 107 : : 108 : 0 : QVariant QgsExpressionContextScope::variable( const QString &name ) const 109 : : { 110 : 0 : return hasVariable( name ) ? mVariables.value( name ).value : QVariant(); 111 : 0 : } 112 : : 113 : 20 : QStringList QgsExpressionContextScope::variableNames() const 114 : : { 115 : 20 : QStringList names = mVariables.keys(); 116 : 20 : return names; 117 : 20 : } 118 : : 119 : : /// @cond PRIVATE 120 : : class QgsExpressionContextVariableCompare 121 : : { 122 : : public: 123 : 0 : explicit QgsExpressionContextVariableCompare( const QgsExpressionContextScope &scope ) 124 : 0 : : mScope( scope ) 125 : 0 : { } 126 : : 127 : 0 : bool operator()( const QString &a, const QString &b ) const 128 : : { 129 : 0 : bool aReadOnly = mScope.isReadOnly( a ); 130 : 0 : bool bReadOnly = mScope.isReadOnly( b ); 131 : 0 : if ( aReadOnly != bReadOnly ) 132 : 0 : return aReadOnly; 133 : 0 : return QString::localeAwareCompare( a, b ) < 0; 134 : 0 : } 135 : : 136 : : private: 137 : : const QgsExpressionContextScope &mScope; 138 : : }; 139 : : /// @endcond 140 : : 141 : 0 : QStringList QgsExpressionContextScope::filteredVariableNames() const 142 : : { 143 : 0 : QStringList allVariables = mVariables.keys(); 144 : 0 : QStringList filtered; 145 : 0 : const auto constAllVariables = allVariables; 146 : 0 : for ( const QString &variable : constAllVariables ) 147 : : { 148 : 0 : if ( variable.startsWith( '_' ) ) 149 : 0 : continue; 150 : : 151 : 0 : filtered << variable; 152 : : } 153 : 0 : QgsExpressionContextVariableCompare cmp( *this ); 154 : 0 : std::sort( filtered.begin(), filtered.end(), cmp ); 155 : : 156 : 0 : return filtered; 157 : 0 : } 158 : : 159 : 0 : bool QgsExpressionContextScope::isReadOnly( const QString &name ) const 160 : : { 161 : 0 : return hasVariable( name ) ? mVariables.value( name ).readOnly : false; 162 : : } 163 : : 164 : 0 : bool QgsExpressionContextScope::isStatic( const QString &name ) const 165 : : { 166 : 0 : return hasVariable( name ) ? mVariables.value( name ).isStatic : false; 167 : : } 168 : : 169 : 0 : QString QgsExpressionContextScope::description( const QString &name ) const 170 : : { 171 : 0 : return hasVariable( name ) ? mVariables.value( name ).description : QString(); 172 : : } 173 : : 174 : 0 : bool QgsExpressionContextScope::hasFunction( const QString &name ) const 175 : : { 176 : 0 : return mFunctions.contains( name ); 177 : : } 178 : : 179 : 0 : QgsExpressionFunction *QgsExpressionContextScope::function( const QString &name ) const 180 : : { 181 : 0 : return mFunctions.contains( name ) ? mFunctions.value( name ) : nullptr; 182 : : } 183 : : 184 : 0 : QStringList QgsExpressionContextScope::functionNames() const 185 : : { 186 : 0 : return mFunctions.keys(); 187 : : } 188 : : 189 : 1 : void QgsExpressionContextScope::addFunction( const QString &name, QgsScopedExpressionFunction *function ) 190 : : { 191 : 1 : mFunctions.insert( name, function ); 192 : 1 : } 193 : : 194 : : 195 : 200 : void QgsExpressionContextScope::setFields( const QgsFields &fields ) 196 : : { 197 : 200 : addVariable( StaticVariable( QgsExpressionContext::EXPR_FIELDS, QVariant::fromValue( fields ), true ) ); 198 : 200 : } 199 : : 200 : 0 : void QgsExpressionContextScope::readXml( const QDomElement &element, const QgsReadWriteContext & ) 201 : : { 202 : 0 : const QDomNodeList variablesNodeList = element.childNodes(); 203 : 0 : for ( int i = 0; i < variablesNodeList.size(); ++i ) 204 : : { 205 : 0 : const QDomElement variableElement = variablesNodeList.at( i ).toElement(); 206 : 0 : const QString key = variableElement.attribute( QStringLiteral( "name" ) ); 207 : 0 : const QVariant value = QgsXmlUtils::readVariant( variableElement.firstChildElement( QStringLiteral( "Option" ) ) ); 208 : 0 : setVariable( key, value ); 209 : 0 : } 210 : 0 : } 211 : : 212 : 0 : bool QgsExpressionContextScope::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const 213 : : { 214 : 0 : for ( auto it = mVariables.constBegin(); it != mVariables.constEnd(); ++it ) 215 : : { 216 : 0 : QDomElement varElem = document.createElement( QStringLiteral( "Variable" ) ); 217 : 0 : varElem.setAttribute( QStringLiteral( "name" ), it.key() ); 218 : 0 : QDomElement valueElem = QgsXmlUtils::writeVariant( it.value().value, document ); 219 : 0 : varElem.appendChild( valueElem ); 220 : 0 : element.appendChild( varElem ); 221 : 0 : } 222 : 0 : return true; 223 : 0 : } 224 : : 225 : : 226 : : // 227 : : // QgsExpressionContext 228 : : // 229 : : 230 : 1 : QgsExpressionContext::QgsExpressionContext( const QList<QgsExpressionContextScope *> &scopes ) 231 : 1 : : mStack( scopes ) 232 : : { 233 : 1 : } 234 : : 235 : 0 : QgsExpressionContext::QgsExpressionContext( const QgsExpressionContext &other ) : mStack{} 236 : : { 237 : 0 : for ( const QgsExpressionContextScope *scope : std::as_const( other.mStack ) ) 238 : : { 239 : 0 : mStack << new QgsExpressionContextScope( *scope ); 240 : : } 241 : 0 : mHighlightedVariables = other.mHighlightedVariables; 242 : 0 : mHighlightedFunctions = other.mHighlightedFunctions; 243 : 0 : mCachedValues = other.mCachedValues; 244 : 0 : } 245 : : 246 : 0 : QgsExpressionContext &QgsExpressionContext::operator=( QgsExpressionContext &&other ) noexcept 247 : : { 248 : 0 : if ( this != &other ) 249 : : { 250 : 0 : qDeleteAll( mStack ); 251 : : // move the stack over 252 : 0 : mStack = other.mStack; 253 : 0 : other.mStack.clear(); 254 : : 255 : 0 : mHighlightedVariables = other.mHighlightedVariables; 256 : 0 : mHighlightedFunctions = other.mHighlightedFunctions; 257 : 0 : mCachedValues = other.mCachedValues; 258 : 0 : } 259 : 0 : return *this; 260 : : } 261 : : 262 : 533 : QgsExpressionContext &QgsExpressionContext::operator=( const QgsExpressionContext &other ) 263 : : { 264 : 533 : if ( &other == this ) 265 : 0 : return *this; 266 : : 267 : 533 : qDeleteAll( mStack ); 268 : 533 : mStack.clear(); 269 : 533 : for ( const QgsExpressionContextScope *scope : std::as_const( other.mStack ) ) 270 : : { 271 : 0 : mStack << new QgsExpressionContextScope( *scope ); 272 : : } 273 : 533 : mHighlightedVariables = other.mHighlightedVariables; 274 : 533 : mHighlightedFunctions = other.mHighlightedFunctions; 275 : 533 : mCachedValues = other.mCachedValues; 276 : 533 : return *this; 277 : 533 : } 278 : : 279 : 853 : QgsExpressionContext::~QgsExpressionContext() 280 : : { 281 : 853 : qDeleteAll( mStack ); 282 : 853 : mStack.clear(); 283 : 853 : } 284 : : 285 : 0 : bool QgsExpressionContext::hasVariable( const QString &name ) const 286 : : { 287 : 0 : const auto constMStack = mStack; 288 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 289 : : { 290 : 0 : if ( scope->hasVariable( name ) ) 291 : 0 : return true; 292 : : } 293 : 0 : return false; 294 : 0 : } 295 : : 296 : 0 : QVariant QgsExpressionContext::variable( const QString &name ) const 297 : : { 298 : 0 : const QgsExpressionContextScope *scope = activeScopeForVariable( name ); 299 : 0 : return scope ? scope->variable( name ) : QVariant(); 300 : : } 301 : : 302 : 0 : QVariantMap QgsExpressionContext::variablesToMap() const 303 : : { 304 : 0 : QStringList names = variableNames(); 305 : 0 : QVariantMap m; 306 : 0 : const auto constNames = names; 307 : 0 : for ( const QString &name : constNames ) 308 : : { 309 : 0 : m.insert( name, variable( name ) ); 310 : : } 311 : 0 : return m; 312 : 0 : } 313 : : 314 : 0 : bool QgsExpressionContext::isHighlightedVariable( const QString &name ) const 315 : : { 316 : 0 : return mHighlightedVariables.contains( name ); 317 : : } 318 : : 319 : 0 : QStringList QgsExpressionContext::highlightedVariables() const 320 : : { 321 : 0 : return mHighlightedVariables; 322 : : } 323 : : 324 : 0 : void QgsExpressionContext::setHighlightedVariables( const QStringList &variableNames ) 325 : : { 326 : 0 : mHighlightedVariables = variableNames; 327 : 0 : } 328 : : 329 : 0 : bool QgsExpressionContext::isHighlightedFunction( const QString &name ) const 330 : : { 331 : 0 : return mHighlightedFunctions.contains( name ); 332 : : } 333 : : 334 : 0 : void QgsExpressionContext::setHighlightedFunctions( const QStringList &names ) 335 : : { 336 : 0 : mHighlightedFunctions = names; 337 : 0 : } 338 : : 339 : 0 : const QgsExpressionContextScope *QgsExpressionContext::activeScopeForVariable( const QString &name ) const 340 : : { 341 : : //iterate through stack backwards, so that higher priority variables take precedence 342 : 0 : QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd(); 343 : 0 : while ( it != mStack.constBegin() ) 344 : : { 345 : 0 : --it; 346 : 0 : if ( ( *it )->hasVariable( name ) ) 347 : 0 : return ( *it ); 348 : : } 349 : 0 : return nullptr; 350 : 0 : } 351 : : 352 : 421 : QgsExpressionContextScope *QgsExpressionContext::activeScopeForVariable( const QString &name ) 353 : : { 354 : : //iterate through stack backwards, so that higher priority variables take precedence 355 : 0 : QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd(); 356 : 0 : while ( it != mStack.constBegin() ) 357 : : { 358 : 0 : --it; 359 : 0 : if ( ( *it )->hasVariable( name ) ) 360 : 0 : return ( *it ); 361 : : } 362 : 0 : return nullptr; 363 : 0 : } 364 : : 365 : 0 : QgsExpressionContextScope *QgsExpressionContext::scope( int index ) 366 : : { 367 : 0 : if ( index < 0 || index >= mStack.count() ) 368 : 0 : return nullptr; 369 : : 370 : 0 : return mStack.at( index ); 371 : 0 : } 372 : : 373 : 0 : QgsExpressionContextScope *QgsExpressionContext::lastScope() 374 : : { 375 : 0 : if ( mStack.count() < 1 ) 376 : 0 : return nullptr; 377 : : 378 : 0 : return mStack.last(); 379 : 0 : } 380 : : 381 : 0 : int QgsExpressionContext::indexOfScope( QgsExpressionContextScope *scope ) const 382 : : { 383 : 0 : if ( !scope ) 384 : 0 : return -1; 385 : : 386 : 0 : return mStack.indexOf( scope ); 387 : 0 : } 388 : : 389 : 0 : int QgsExpressionContext::indexOfScope( const QString &scopeName ) const 390 : : { 391 : 0 : int index = 0; 392 : 0 : const auto constMStack = mStack; 393 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 394 : : { 395 : 0 : if ( scope->name() == scopeName ) 396 : 0 : return index; 397 : : 398 : 0 : index++; 399 : : } 400 : 0 : return -1; 401 : 0 : } 402 : : 403 : 0 : QStringList QgsExpressionContext::variableNames() const 404 : : { 405 : 0 : QStringList names; 406 : 0 : const auto constMStack = mStack; 407 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 408 : : { 409 : 0 : names << scope->variableNames(); 410 : : } 411 : 0 : return qgis::setToList( qgis::listToSet( names ) ); 412 : 0 : } 413 : : 414 : 0 : QStringList QgsExpressionContext::filteredVariableNames() const 415 : : { 416 : 0 : QStringList allVariables = variableNames(); 417 : 0 : QStringList filtered; 418 : 0 : const auto constAllVariables = allVariables; 419 : 0 : for ( const QString &variable : constAllVariables ) 420 : : { 421 : 0 : if ( variable.startsWith( '_' ) ) 422 : 0 : continue; 423 : : 424 : 0 : filtered << variable; 425 : : } 426 : : 427 : 0 : filtered.sort(); 428 : 0 : return filtered; 429 : 0 : } 430 : : 431 : 0 : bool QgsExpressionContext::isReadOnly( const QString &name ) const 432 : : { 433 : 0 : const auto constMStack = mStack; 434 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 435 : : { 436 : 0 : if ( scope->isReadOnly( name ) ) 437 : 0 : return true; 438 : : } 439 : 0 : return false; 440 : 0 : } 441 : : 442 : 0 : QString QgsExpressionContext::description( const QString &name ) const 443 : : { 444 : 0 : const QgsExpressionContextScope *scope = activeScopeForVariable( name ); 445 : 0 : return ( scope && !scope->description( name ).isEmpty() ) ? scope->description( name ) : QgsExpression::variableHelpText( name ); 446 : 0 : } 447 : : 448 : 0 : bool QgsExpressionContext::hasFunction( const QString &name ) const 449 : : { 450 : 0 : const auto constMStack = mStack; 451 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 452 : : { 453 : 0 : if ( scope->hasFunction( name ) ) 454 : 0 : return true; 455 : : } 456 : 0 : return false; 457 : 0 : } 458 : : 459 : 0 : QStringList QgsExpressionContext::functionNames() const 460 : : { 461 : 0 : QStringList result; 462 : 0 : const auto constMStack = mStack; 463 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 464 : : { 465 : 0 : result << scope->functionNames(); 466 : : } 467 : 0 : result = qgis::setToList( qgis::listToSet( result ) ); 468 : 0 : result.sort(); 469 : 0 : return result; 470 : 0 : } 471 : : 472 : 0 : QgsExpressionFunction *QgsExpressionContext::function( const QString &name ) const 473 : : { 474 : : //iterate through stack backwards, so that higher priority variables take precedence 475 : 0 : QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd(); 476 : 0 : while ( it != mStack.constBegin() ) 477 : : { 478 : 0 : --it; 479 : 0 : if ( ( *it )->hasFunction( name ) ) 480 : 0 : return ( *it )->function( name ); 481 : : } 482 : 0 : return nullptr; 483 : 0 : } 484 : : 485 : 0 : int QgsExpressionContext::scopeCount() const 486 : : { 487 : 0 : return mStack.count(); 488 : : } 489 : : 490 : 0 : void QgsExpressionContext::appendScope( QgsExpressionContextScope *scope ) 491 : : { 492 : 0 : mStack.append( scope ); 493 : 0 : } 494 : : 495 : 0 : void QgsExpressionContext::appendScopes( const QList<QgsExpressionContextScope *> &scopes ) 496 : : { 497 : 0 : mStack.append( scopes ); 498 : 0 : } 499 : : 500 : 0 : QgsExpressionContextScope *QgsExpressionContext::popScope() 501 : : { 502 : 0 : if ( !mStack.isEmpty() ) 503 : 0 : return mStack.takeLast(); 504 : : 505 : 0 : return nullptr; 506 : 0 : } 507 : : 508 : 0 : QList<QgsExpressionContextScope *> QgsExpressionContext::takeScopes() 509 : : { 510 : 0 : QList<QgsExpressionContextScope *> stack = mStack; 511 : 0 : mStack.clear(); 512 : 0 : return stack; 513 : 0 : } 514 : : 515 : 0 : QgsExpressionContext &QgsExpressionContext::operator<<( QgsExpressionContextScope *scope ) 516 : : { 517 : 0 : mStack.append( scope ); 518 : 0 : return *this; 519 : : } 520 : : 521 : 0 : void QgsExpressionContext::setFeature( const QgsFeature &feature ) 522 : : { 523 : 0 : if ( mStack.isEmpty() ) 524 : 0 : mStack.append( new QgsExpressionContextScope() ); 525 : : 526 : 0 : mStack.last()->setFeature( feature ); 527 : 0 : } 528 : : 529 : 0 : bool QgsExpressionContext::hasFeature() const 530 : : { 531 : 0 : const auto constMStack = mStack; 532 : 0 : for ( const QgsExpressionContextScope *scope : constMStack ) 533 : : { 534 : 0 : if ( scope->hasFeature() ) 535 : 0 : return true; 536 : : } 537 : 0 : return false; 538 : 0 : } 539 : : 540 : 0 : QgsFeature QgsExpressionContext::feature() const 541 : : { 542 : : //iterate through stack backwards, so that higher priority variables take precedence 543 : 0 : QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd(); 544 : 0 : while ( it != mStack.constBegin() ) 545 : : { 546 : 0 : --it; 547 : 0 : if ( ( *it )->hasFeature() ) 548 : 0 : return ( *it )->feature(); 549 : : } 550 : 0 : return QgsFeature(); 551 : 0 : } 552 : : 553 : 0 : void QgsExpressionContext::setFields( const QgsFields &fields ) 554 : : { 555 : 0 : if ( mStack.isEmpty() ) 556 : 0 : mStack.append( new QgsExpressionContextScope() ); 557 : : 558 : 0 : mStack.last()->setFields( fields ); 559 : 0 : } 560 : : 561 : 0 : QgsFields QgsExpressionContext::fields() const 562 : : { 563 : 0 : return qvariant_cast<QgsFields>( variable( QgsExpressionContext::EXPR_FIELDS ) ); 564 : 0 : } 565 : : 566 : 0 : void QgsExpressionContext::setOriginalValueVariable( const QVariant &value ) 567 : : { 568 : 0 : if ( mStack.isEmpty() ) 569 : 0 : mStack.append( new QgsExpressionContextScope() ); 570 : : 571 : 0 : mStack.last()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_ORIGINAL_VALUE, 572 : 0 : value, true ) ); 573 : 0 : } 574 : : 575 : 0 : void QgsExpressionContext::setCachedValue( const QString &key, const QVariant &value ) const 576 : : { 577 : 0 : mCachedValues.insert( key, value ); 578 : 0 : } 579 : : 580 : 0 : bool QgsExpressionContext::hasCachedValue( const QString &key ) const 581 : : { 582 : 0 : return mCachedValues.contains( key ); 583 : : } 584 : : 585 : 0 : QVariant QgsExpressionContext::cachedValue( const QString &key ) const 586 : : { 587 : 0 : return mCachedValues.value( key, QVariant() ); 588 : 0 : } 589 : : 590 : 0 : void QgsExpressionContext::clearCachedValues() const 591 : : { 592 : 0 : mCachedValues.clear(); 593 : 0 : }