mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-12 00:06:43 -04:00
1468 lines
51 KiB
C++
1468 lines
51 KiB
C++
/***************************************************************************
|
|
qgsexpressioncontext.cpp
|
|
------------------------
|
|
Date : April 2015
|
|
Copyright : (C) 2015 by Nyall Dawson
|
|
Email : nyall dot dawson at gmail dot com
|
|
***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgsexpressioncontext.h"
|
|
|
|
#include "qgslogger.h"
|
|
#include "qgsexpression.h"
|
|
#include "qgsexpressionfunction.h"
|
|
#include "qgsfields.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgsproject.h"
|
|
#include "qgssymbollayerutils.h"
|
|
#include "qgsgeometry.h"
|
|
#include "qgscomposition.h"
|
|
#include "qgscomposeritem.h"
|
|
#include "qgsatlascomposition.h"
|
|
#include "qgsapplication.h"
|
|
#include "qgsmapsettings.h"
|
|
#include "qgsmaplayerlistutils.h"
|
|
#include "qgsprocessingcontext.h"
|
|
#include "qgsprocessingalgorithm.h"
|
|
#include "qgslayoutatlas.h"
|
|
#include "qgslayout.h"
|
|
#include "qgslayoutpagecollection.h"
|
|
#include "qgslayoutreportcontext.h"
|
|
|
|
#include <QSettings>
|
|
#include <QDir>
|
|
|
|
|
|
const QString QgsExpressionContext::EXPR_FIELDS( QStringLiteral( "_fields_" ) );
|
|
const QString QgsExpressionContext::EXPR_ORIGINAL_VALUE( QStringLiteral( "value" ) );
|
|
const QString QgsExpressionContext::EXPR_SYMBOL_COLOR( QStringLiteral( "symbol_color" ) );
|
|
const QString QgsExpressionContext::EXPR_SYMBOL_ANGLE( QStringLiteral( "symbol_angle" ) );
|
|
const QString QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT( QStringLiteral( "geometry_part_count" ) );
|
|
const QString QgsExpressionContext::EXPR_GEOMETRY_PART_NUM( QStringLiteral( "geometry_part_num" ) );
|
|
const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT( QStringLiteral( "geometry_point_count" ) );
|
|
const QString QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM( QStringLiteral( "geometry_point_num" ) );
|
|
const QString QgsExpressionContext::EXPR_CLUSTER_SIZE( QStringLiteral( "cluster_size" ) );
|
|
const QString QgsExpressionContext::EXPR_CLUSTER_COLOR( QStringLiteral( "cluster_color" ) );
|
|
|
|
//
|
|
// QgsExpressionContextScope
|
|
//
|
|
|
|
QgsExpressionContextScope::QgsExpressionContextScope( const QString &name )
|
|
: mName( name )
|
|
{
|
|
|
|
}
|
|
|
|
QgsExpressionContextScope::QgsExpressionContextScope( const QgsExpressionContextScope &other )
|
|
: mName( other.mName )
|
|
, mVariables( other.mVariables )
|
|
, mHasFeature( other.mHasFeature )
|
|
, mFeature( other.mFeature )
|
|
{
|
|
QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
|
|
for ( ; it != other.mFunctions.constEnd(); ++it )
|
|
{
|
|
mFunctions.insert( it.key(), it.value()->clone() );
|
|
}
|
|
}
|
|
|
|
QgsExpressionContextScope &QgsExpressionContextScope::operator=( const QgsExpressionContextScope &other )
|
|
{
|
|
mName = other.mName;
|
|
mVariables = other.mVariables;
|
|
mHasFeature = other.mHasFeature;
|
|
mFeature = other.mFeature;
|
|
|
|
qDeleteAll( mFunctions );
|
|
mFunctions.clear();
|
|
QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
|
|
for ( ; it != other.mFunctions.constEnd(); ++it )
|
|
{
|
|
mFunctions.insert( it.key(), it.value()->clone() );
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
QgsExpressionContextScope::~QgsExpressionContextScope()
|
|
{
|
|
qDeleteAll( mFunctions );
|
|
}
|
|
|
|
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, false, isStatic ) );
|
|
}
|
|
}
|
|
|
|
void QgsExpressionContextScope::addVariable( const QgsExpressionContextScope::StaticVariable &variable )
|
|
{
|
|
mVariables.insert( variable.name, variable );
|
|
}
|
|
|
|
bool QgsExpressionContextScope::removeVariable( const QString &name )
|
|
{
|
|
return mVariables.remove( name ) > 0;
|
|
}
|
|
|
|
bool QgsExpressionContextScope::hasVariable( const QString &name ) const
|
|
{
|
|
return mVariables.contains( name );
|
|
}
|
|
|
|
QVariant QgsExpressionContextScope::variable( const QString &name ) const
|
|
{
|
|
return hasVariable( name ) ? mVariables.value( name ).value : QVariant();
|
|
}
|
|
|
|
QStringList QgsExpressionContextScope::variableNames() const
|
|
{
|
|
QStringList names = mVariables.keys();
|
|
return names;
|
|
}
|
|
|
|
bool QgsExpressionContextScope::variableNameSort( const QString &a, const QString &b )
|
|
{
|
|
return QString::localeAwareCompare( a, b ) < 0;
|
|
}
|
|
|
|
/// @cond PRIVATE
|
|
class QgsExpressionContextVariableCompare
|
|
{
|
|
public:
|
|
explicit QgsExpressionContextVariableCompare( const QgsExpressionContextScope &scope )
|
|
: mScope( scope )
|
|
{ }
|
|
|
|
bool operator()( const QString &a, const QString &b ) const
|
|
{
|
|
bool aReadOnly = mScope.isReadOnly( a );
|
|
bool bReadOnly = mScope.isReadOnly( b );
|
|
if ( aReadOnly != bReadOnly )
|
|
return aReadOnly;
|
|
return QString::localeAwareCompare( a, b ) < 0;
|
|
}
|
|
|
|
private:
|
|
const QgsExpressionContextScope &mScope;
|
|
};
|
|
/// @endcond
|
|
|
|
QStringList QgsExpressionContextScope::filteredVariableNames() const
|
|
{
|
|
QStringList allVariables = mVariables.keys();
|
|
QStringList filtered;
|
|
Q_FOREACH ( const QString &variable, allVariables )
|
|
{
|
|
if ( variable.startsWith( '_' ) )
|
|
continue;
|
|
|
|
filtered << variable;
|
|
}
|
|
QgsExpressionContextVariableCompare cmp( *this );
|
|
std::sort( filtered.begin(), filtered.end(), cmp );
|
|
|
|
return filtered;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
QString QgsExpressionContextScope::description( const QString &name ) const
|
|
{
|
|
return hasVariable( name ) ? mVariables.value( name ).description : QString();
|
|
}
|
|
|
|
bool QgsExpressionContextScope::hasFunction( const QString &name ) const
|
|
{
|
|
return mFunctions.contains( name );
|
|
}
|
|
|
|
QgsExpressionFunction *QgsExpressionContextScope::function( const QString &name ) const
|
|
{
|
|
return mFunctions.contains( name ) ? mFunctions.value( name ) : nullptr;
|
|
}
|
|
|
|
QStringList QgsExpressionContextScope::functionNames() const
|
|
{
|
|
return mFunctions.keys();
|
|
}
|
|
|
|
void QgsExpressionContextScope::addFunction( const QString &name, QgsScopedExpressionFunction *function )
|
|
{
|
|
mFunctions.insert( name, function );
|
|
}
|
|
|
|
|
|
void QgsExpressionContextScope::setFields( const QgsFields &fields )
|
|
{
|
|
addVariable( StaticVariable( QgsExpressionContext::EXPR_FIELDS, QVariant::fromValue( fields ), true ) );
|
|
}
|
|
|
|
|
|
//
|
|
// QgsExpressionContext
|
|
//
|
|
|
|
QgsExpressionContext::QgsExpressionContext( const QList<QgsExpressionContextScope *> &scopes )
|
|
: mStack( scopes )
|
|
{
|
|
}
|
|
|
|
QgsExpressionContext::QgsExpressionContext( const QgsExpressionContext &other )
|
|
{
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, other.mStack )
|
|
{
|
|
mStack << new QgsExpressionContextScope( *scope );
|
|
}
|
|
mHighlightedVariables = other.mHighlightedVariables;
|
|
mCachedValues = other.mCachedValues;
|
|
}
|
|
|
|
QgsExpressionContext &QgsExpressionContext::operator=( QgsExpressionContext &&other ) noexcept
|
|
{
|
|
if ( this != &other )
|
|
{
|
|
qDeleteAll( mStack );
|
|
// move the stack over
|
|
mStack = other.mStack;
|
|
other.mStack.clear();
|
|
|
|
mHighlightedVariables = other.mHighlightedVariables;
|
|
mCachedValues = other.mCachedValues;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
QgsExpressionContext &QgsExpressionContext::operator=( const QgsExpressionContext &other )
|
|
{
|
|
qDeleteAll( mStack );
|
|
mStack.clear();
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, other.mStack )
|
|
{
|
|
mStack << new QgsExpressionContextScope( *scope );
|
|
}
|
|
mHighlightedVariables = other.mHighlightedVariables;
|
|
mCachedValues = other.mCachedValues;
|
|
return *this;
|
|
}
|
|
|
|
QgsExpressionContext::~QgsExpressionContext()
|
|
{
|
|
qDeleteAll( mStack );
|
|
mStack.clear();
|
|
}
|
|
|
|
bool QgsExpressionContext::hasVariable( const QString &name ) const
|
|
{
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
if ( scope->hasVariable( name ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QVariant QgsExpressionContext::variable( const QString &name ) const
|
|
{
|
|
const QgsExpressionContextScope *scope = activeScopeForVariable( name );
|
|
return scope ? scope->variable( name ) : QVariant();
|
|
}
|
|
|
|
QVariantMap QgsExpressionContext::variablesToMap() const
|
|
{
|
|
QStringList names = variableNames();
|
|
QVariantMap m;
|
|
Q_FOREACH ( const QString &name, names )
|
|
{
|
|
m.insert( name, variable( name ) );
|
|
}
|
|
return m;
|
|
}
|
|
|
|
bool QgsExpressionContext::isHighlightedVariable( const QString &name ) const
|
|
{
|
|
return mHighlightedVariables.contains( name );
|
|
}
|
|
|
|
void QgsExpressionContext::setHighlightedVariables( const QStringList &variableNames )
|
|
{
|
|
mHighlightedVariables = variableNames;
|
|
}
|
|
|
|
const QgsExpressionContextScope *QgsExpressionContext::activeScopeForVariable( const QString &name ) const
|
|
{
|
|
//iterate through stack backwards, so that higher priority variables take precedence
|
|
QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
|
|
while ( it != mStack.constBegin() )
|
|
{
|
|
--it;
|
|
if ( ( *it )->hasVariable( name ) )
|
|
return ( *it );
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContext::activeScopeForVariable( const QString &name )
|
|
{
|
|
//iterate through stack backwards, so that higher priority variables take precedence
|
|
QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
|
|
while ( it != mStack.constBegin() )
|
|
{
|
|
--it;
|
|
if ( ( *it )->hasVariable( name ) )
|
|
return ( *it );
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContext::scope( int index )
|
|
{
|
|
if ( index < 0 || index >= mStack.count() )
|
|
return nullptr;
|
|
|
|
return mStack.at( index );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContext::lastScope()
|
|
{
|
|
if ( mStack.count() < 1 )
|
|
return nullptr;
|
|
|
|
return mStack.last();
|
|
}
|
|
|
|
int QgsExpressionContext::indexOfScope( QgsExpressionContextScope *scope ) const
|
|
{
|
|
if ( !scope )
|
|
return -1;
|
|
|
|
return mStack.indexOf( scope );
|
|
}
|
|
|
|
int QgsExpressionContext::indexOfScope( const QString &scopeName ) const
|
|
{
|
|
int index = 0;
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
if ( scope->name() == scopeName )
|
|
return index;
|
|
|
|
index++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
QStringList QgsExpressionContext::variableNames() const
|
|
{
|
|
QStringList names;
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
names << scope->variableNames();
|
|
}
|
|
return names.toSet().toList();
|
|
}
|
|
|
|
QStringList QgsExpressionContext::filteredVariableNames() const
|
|
{
|
|
QStringList allVariables = variableNames();
|
|
QStringList filtered;
|
|
Q_FOREACH ( const QString &variable, allVariables )
|
|
{
|
|
if ( variable.startsWith( '_' ) )
|
|
continue;
|
|
|
|
filtered << variable;
|
|
}
|
|
|
|
filtered.sort();
|
|
return filtered;
|
|
}
|
|
|
|
bool QgsExpressionContext::isReadOnly( const QString &name ) const
|
|
{
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
if ( scope->isReadOnly( name ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QString QgsExpressionContext::description( const QString &name ) const
|
|
{
|
|
const QgsExpressionContextScope *scope = activeScopeForVariable( name );
|
|
return ( scope && !scope->description( name ).isEmpty() ) ? scope->description( name ) : QgsExpression::variableHelpText( name );
|
|
}
|
|
|
|
bool QgsExpressionContext::hasFunction( const QString &name ) const
|
|
{
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
if ( scope->hasFunction( name ) )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QStringList QgsExpressionContext::functionNames() const
|
|
{
|
|
QStringList result;
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
result << scope->functionNames();
|
|
}
|
|
result = result.toSet().toList();
|
|
result.sort();
|
|
return result;
|
|
}
|
|
|
|
QgsExpressionFunction *QgsExpressionContext::function( const QString &name ) const
|
|
{
|
|
//iterate through stack backwards, so that higher priority variables take precedence
|
|
QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
|
|
while ( it != mStack.constBegin() )
|
|
{
|
|
--it;
|
|
if ( ( *it )->hasFunction( name ) )
|
|
return ( *it )->function( name );
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int QgsExpressionContext::scopeCount() const
|
|
{
|
|
return mStack.count();
|
|
}
|
|
|
|
void QgsExpressionContext::appendScope( QgsExpressionContextScope *scope )
|
|
{
|
|
mStack.append( scope );
|
|
}
|
|
|
|
void QgsExpressionContext::appendScopes( const QList<QgsExpressionContextScope *> &scopes )
|
|
{
|
|
mStack.append( scopes );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContext::popScope()
|
|
{
|
|
if ( !mStack.isEmpty() )
|
|
return mStack.takeLast();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
QList<QgsExpressionContextScope *> QgsExpressionContext::takeScopes()
|
|
{
|
|
QList<QgsExpressionContextScope *> stack = mStack;
|
|
mStack.clear();
|
|
return stack;
|
|
}
|
|
|
|
QgsExpressionContext &QgsExpressionContext::operator<<( QgsExpressionContextScope *scope )
|
|
{
|
|
mStack.append( scope );
|
|
return *this;
|
|
}
|
|
|
|
void QgsExpressionContext::setFeature( const QgsFeature &feature )
|
|
{
|
|
if ( mStack.isEmpty() )
|
|
mStack.append( new QgsExpressionContextScope() );
|
|
|
|
mStack.last()->setFeature( feature );
|
|
}
|
|
|
|
bool QgsExpressionContext::hasFeature() const
|
|
{
|
|
Q_FOREACH ( const QgsExpressionContextScope *scope, mStack )
|
|
{
|
|
if ( scope->hasFeature() )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QgsFeature QgsExpressionContext::feature() const
|
|
{
|
|
//iterate through stack backwards, so that higher priority variables take precedence
|
|
QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
|
|
while ( it != mStack.constBegin() )
|
|
{
|
|
--it;
|
|
if ( ( *it )->hasFeature() )
|
|
return ( *it )->feature();
|
|
}
|
|
return QgsFeature();
|
|
}
|
|
|
|
void QgsExpressionContext::setFields( const QgsFields &fields )
|
|
{
|
|
if ( mStack.isEmpty() )
|
|
mStack.append( new QgsExpressionContextScope() );
|
|
|
|
mStack.last()->setFields( fields );
|
|
}
|
|
|
|
QgsFields QgsExpressionContext::fields() const
|
|
{
|
|
return qvariant_cast<QgsFields>( variable( QgsExpressionContext::EXPR_FIELDS ) );
|
|
}
|
|
|
|
void QgsExpressionContext::setOriginalValueVariable( const QVariant &value )
|
|
{
|
|
if ( mStack.isEmpty() )
|
|
mStack.append( new QgsExpressionContextScope() );
|
|
|
|
mStack.last()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_ORIGINAL_VALUE,
|
|
value, true ) );
|
|
}
|
|
|
|
void QgsExpressionContext::setCachedValue( const QString &key, const QVariant &value ) const
|
|
{
|
|
mCachedValues.insert( key, value );
|
|
}
|
|
|
|
bool QgsExpressionContext::hasCachedValue( const QString &key ) const
|
|
{
|
|
return mCachedValues.contains( key );
|
|
}
|
|
|
|
QVariant QgsExpressionContext::cachedValue( const QString &key ) const
|
|
{
|
|
return mCachedValues.value( key, QVariant() );
|
|
}
|
|
|
|
void QgsExpressionContext::clearCachedValues() const
|
|
{
|
|
mCachedValues.clear();
|
|
}
|
|
|
|
|
|
//
|
|
// QgsExpressionContextUtils
|
|
//
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::globalScope()
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Global" ) );
|
|
|
|
QVariantMap customVariables = QgsApplication::customVariables();
|
|
|
|
for ( QVariantMap::const_iterator it = customVariables.constBegin(); it != customVariables.constEnd(); ++it )
|
|
{
|
|
scope->setVariable( it.key(), it.value(), true );
|
|
}
|
|
|
|
//add some extra global variables
|
|
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;
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setGlobalVariable( const QString &name, const QVariant &value )
|
|
{
|
|
QgsApplication::setCustomVariable( name, value );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setGlobalVariables( const QVariantMap &variables )
|
|
{
|
|
QgsApplication::setCustomVariables( variables );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::removeGlobalVariable( const QString &name )
|
|
{
|
|
QVariantMap vars = QgsApplication::customVariables();
|
|
if ( vars.remove( name ) )
|
|
QgsApplication::setCustomVariables( vars );
|
|
}
|
|
|
|
|
|
/// @cond PRIVATE
|
|
|
|
class GetNamedProjectColor : public QgsScopedExpressionFunction
|
|
{
|
|
public:
|
|
GetNamedProjectColor( const QgsProject *project )
|
|
: QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
|
|
, mProject( project )
|
|
{
|
|
if ( !project )
|
|
return;
|
|
|
|
//build up color list from project. Do this in advance for speed
|
|
QStringList colorStrings = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ) );
|
|
QStringList colorLabels = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ) );
|
|
|
|
//generate list from custom colors
|
|
int colorIndex = 0;
|
|
for ( QStringList::iterator it = colorStrings.begin();
|
|
it != colorStrings.end(); ++it )
|
|
{
|
|
QColor color = QgsSymbolLayerUtils::decodeColor( *it );
|
|
QString label;
|
|
if ( colorLabels.length() > colorIndex )
|
|
{
|
|
label = colorLabels.at( colorIndex );
|
|
}
|
|
|
|
mColors.insert( label.toLower(), color );
|
|
colorIndex++;
|
|
}
|
|
}
|
|
|
|
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
|
|
{
|
|
QString colorName = values.at( 0 ).toString().toLower();
|
|
if ( mColors.contains( colorName ) )
|
|
{
|
|
return QStringLiteral( "%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
|
|
}
|
|
else
|
|
return QVariant();
|
|
}
|
|
|
|
QgsScopedExpressionFunction *clone() const override
|
|
{
|
|
return new GetNamedProjectColor( mProject );
|
|
}
|
|
|
|
private:
|
|
|
|
const QgsProject *mProject = nullptr;
|
|
QHash< QString, QColor > mColors;
|
|
|
|
};
|
|
|
|
class GetComposerItemVariables : public QgsScopedExpressionFunction
|
|
{
|
|
public:
|
|
GetComposerItemVariables( const QgsComposition *c )
|
|
: QgsScopedExpressionFunction( QStringLiteral( "item_variables" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "Composition" ) )
|
|
, mComposition( c )
|
|
{}
|
|
|
|
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
|
|
{
|
|
if ( !mComposition )
|
|
return QVariant();
|
|
|
|
QString id = values.at( 0 ).toString().toLower();
|
|
|
|
const QgsComposerItem *item = mComposition->getComposerItemById( id );
|
|
if ( !item )
|
|
return QVariant();
|
|
|
|
QgsExpressionContext c = item->createExpressionContext();
|
|
|
|
return c.variablesToMap();
|
|
}
|
|
|
|
QgsScopedExpressionFunction *clone() const override
|
|
{
|
|
return new GetComposerItemVariables( mComposition );
|
|
}
|
|
|
|
private:
|
|
|
|
const QgsComposition *mComposition = nullptr;
|
|
|
|
};
|
|
|
|
class GetLayoutItemVariables : public QgsScopedExpressionFunction
|
|
{
|
|
public:
|
|
GetLayoutItemVariables( const QgsLayout *c )
|
|
: QgsScopedExpressionFunction( QStringLiteral( "item_variables" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "Layout" ) )
|
|
, mLayout( c )
|
|
{}
|
|
|
|
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
|
|
{
|
|
if ( !mLayout )
|
|
return QVariant();
|
|
|
|
QString id = values.at( 0 ).toString().toLower();
|
|
|
|
const QgsLayoutItem *item = mLayout->itemById( id );
|
|
if ( !item )
|
|
return QVariant();
|
|
|
|
QgsExpressionContext c = item->createExpressionContext();
|
|
|
|
return c.variablesToMap();
|
|
}
|
|
|
|
QgsScopedExpressionFunction *clone() const override
|
|
{
|
|
return new GetLayoutItemVariables( mLayout );
|
|
}
|
|
|
|
private:
|
|
|
|
const QgsLayout *mLayout = nullptr;
|
|
|
|
};
|
|
|
|
class GetLayerVisibility : public QgsScopedExpressionFunction
|
|
{
|
|
public:
|
|
GetLayerVisibility( const QList<QgsMapLayer *> &layers )
|
|
: QgsScopedExpressionFunction( QStringLiteral( "is_layer_visible" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ), QStringLiteral( "General" ) )
|
|
, mLayers( layers )
|
|
{}
|
|
|
|
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) 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;
|
|
|
|
};
|
|
|
|
class GetProcessingParameterValue : public QgsScopedExpressionFunction
|
|
{
|
|
public:
|
|
GetProcessingParameterValue( const QVariantMap ¶ms )
|
|
: QgsScopedExpressionFunction( QStringLiteral( "parameter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), QStringLiteral( "Processing" ) )
|
|
, mParams( params )
|
|
{}
|
|
|
|
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * ) override
|
|
{
|
|
return mParams.value( values.at( 0 ).toString() );
|
|
}
|
|
|
|
QgsScopedExpressionFunction *clone() const override
|
|
{
|
|
return new GetProcessingParameterValue( mParams );
|
|
}
|
|
|
|
private:
|
|
|
|
const QVariantMap mParams;
|
|
|
|
};
|
|
|
|
///@endcond
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsProject *project )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Project" ) );
|
|
|
|
if ( !project )
|
|
return scope;
|
|
|
|
const QVariantMap vars = project->customVariables();
|
|
|
|
QVariantMap::const_iterator it = vars.constBegin();
|
|
|
|
for ( ; it != vars.constEnd(); ++it )
|
|
{
|
|
scope->setVariable( it.key(), it.value(), true );
|
|
}
|
|
|
|
//add other known project variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), project->title(), true, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), QDir::toNativeSeparators( project->fileInfo().filePath() ), true, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), QDir::toNativeSeparators( 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, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true, true ) );
|
|
|
|
scope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( project ) );
|
|
return scope;
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setProjectVariable( QgsProject *project, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !project )
|
|
return;
|
|
|
|
QVariantMap vars = project->customVariables();
|
|
|
|
vars.insert( name, value );
|
|
|
|
project->setCustomVariables( vars );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setProjectVariables( QgsProject *project, const QVariantMap &variables )
|
|
{
|
|
if ( !project )
|
|
return;
|
|
|
|
project->setCustomVariables( variables );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::removeProjectVariable( QgsProject *project, const QString &name )
|
|
{
|
|
if ( !project )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QVariantMap vars = project->customVariables();
|
|
if ( vars.remove( name ) )
|
|
project->setCustomVariables( vars );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::layerScope( const QgsMapLayer *layer )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) );
|
|
|
|
if ( !layer )
|
|
return scope;
|
|
|
|
//add variables defined in layer properties
|
|
QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
int varIndex = 0;
|
|
Q_FOREACH ( const QString &variableName, variableNames )
|
|
{
|
|
if ( varIndex >= variableValues.length() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
QVariant varValue = variableValues.at( varIndex );
|
|
varIndex++;
|
|
scope->setVariable( variableName, varValue, 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 = qobject_cast< const QgsVectorLayer * >( layer );
|
|
if ( vLayer )
|
|
{
|
|
scope->setFields( vLayer->fields() );
|
|
}
|
|
|
|
//TODO - add functions. Possibilities include:
|
|
//is_selected
|
|
//field summary stats
|
|
|
|
return scope;
|
|
}
|
|
|
|
QList<QgsExpressionContextScope *> QgsExpressionContextUtils::globalProjectLayerScopes( const QgsMapLayer *layer )
|
|
{
|
|
QList<QgsExpressionContextScope *> scopes;
|
|
scopes << globalScope();
|
|
|
|
QgsProject *project = QgsProject::instance(); // TODO: use project associated with layer
|
|
if ( project )
|
|
scopes << projectScope( project );
|
|
|
|
if ( layer )
|
|
scopes << layerScope( layer );
|
|
return scopes;
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayerVariable( QgsMapLayer *layer, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !layer )
|
|
return;
|
|
|
|
//write variable to layer
|
|
QStringList variableNames = layer->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = layer->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
variableNames << name;
|
|
variableValues << value.toString();
|
|
|
|
layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayerVariables( QgsMapLayer *layer, const QVariantMap &variables )
|
|
{
|
|
if ( !layer )
|
|
return;
|
|
|
|
QStringList variableNames;
|
|
QStringList variableValues;
|
|
|
|
QVariantMap::const_iterator it = variables.constBegin();
|
|
for ( ; it != variables.constEnd(); ++it )
|
|
{
|
|
variableNames << it.key();
|
|
variableValues << it.value().toString();
|
|
}
|
|
|
|
layer->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
layer->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::mapSettingsScope( const QgsMapSettings &mapSettings )
|
|
{
|
|
// IMPORTANT: ANY CHANGES HERE ALSO NEED TO BE MADE TO QgsComposerMap::createExpressionContext()
|
|
// (rationale is described in QgsComposerMap::createExpressionContext() )
|
|
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Settings" ) );
|
|
|
|
//add known map settings context variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), "canvas", true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mapSettings.rotation(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), mapSettings.scale(), true ) );
|
|
QgsGeometry extent = QgsGeometry::fromRect( mapSettings.visibleExtent() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( extent ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), mapSettings.visibleExtent().width(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), mapSettings.visibleExtent().height(), true ) );
|
|
QgsGeometry centerPoint = QgsGeometry::fromPointXY( mapSettings.visibleExtent().center() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
|
|
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapSettings.destinationCrs().authid(), true ) );
|
|
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;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Tool Capture" ) );
|
|
|
|
QVariantList matchList;
|
|
|
|
for ( const QgsPointLocator::Match &match : matches )
|
|
{
|
|
QVariantMap matchMap;
|
|
|
|
matchMap.insert( QStringLiteral( "valid" ), match.isValid() );
|
|
matchMap.insert( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( match.layer() ) ) );
|
|
matchMap.insert( QStringLiteral( "feature_id" ), match.featureId() );
|
|
matchMap.insert( QStringLiteral( "vertex_index" ), match.vertexIndex() );
|
|
matchMap.insert( QStringLiteral( "distance" ), match.distance() );
|
|
|
|
matchList.append( matchMap );
|
|
}
|
|
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "snapping_results" ), matchList ) );
|
|
|
|
return scope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope )
|
|
{
|
|
if ( !symbolScope )
|
|
return nullptr;
|
|
|
|
symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, symbol ? symbol->color() : QColor(), true ) );
|
|
|
|
double angle = 0.0;
|
|
const QgsMarkerSymbol *markerSymbol = dynamic_cast< const QgsMarkerSymbol * >( symbol );
|
|
if ( markerSymbol )
|
|
{
|
|
angle = markerSymbol->angle();
|
|
}
|
|
symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_ANGLE, angle, true ) );
|
|
|
|
return symbolScope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::compositionScope( const QgsComposition *composition )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Composition" ) );
|
|
if ( !composition )
|
|
return scope;
|
|
|
|
//add variables defined in composition properties
|
|
QStringList variableNames = composition->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = composition->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
int varIndex = 0;
|
|
Q_FOREACH ( const QString &variableName, variableNames )
|
|
{
|
|
if ( varIndex >= variableValues.length() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
QVariant varValue = variableValues.at( varIndex );
|
|
varIndex++;
|
|
scope->setVariable( variableName, varValue );
|
|
}
|
|
|
|
//add known composition context variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_name" ), composition->name(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_numpages" ), composition->numPages(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), composition->paperHeight(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), composition->paperWidth(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_dpi" ), composition->printResolution(), true ) );
|
|
|
|
|
|
scope->addFunction( QStringLiteral( "item_variables" ), new GetComposerItemVariables( composition ) );
|
|
|
|
return scope;
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setCompositionVariable( QgsComposition *composition, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !composition )
|
|
return;
|
|
|
|
//write variable to composition
|
|
QStringList variableNames = composition->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = composition->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
variableNames << name;
|
|
variableValues << value.toString();
|
|
|
|
composition->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
composition->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setCompositionVariables( QgsComposition *composition, const QVariantMap &variables )
|
|
{
|
|
if ( !composition )
|
|
return;
|
|
|
|
QStringList variableNames;
|
|
QStringList variableValues;
|
|
|
|
QVariantMap::const_iterator it = variables.constBegin();
|
|
for ( ; it != variables.constEnd(); ++it )
|
|
{
|
|
variableNames << it.key();
|
|
variableValues << it.value().toString();
|
|
}
|
|
|
|
composition->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
composition->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::layoutScope( const QgsLayout *layout )
|
|
{
|
|
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Layout" ) ) );
|
|
if ( !layout )
|
|
return scope.release();
|
|
|
|
//add variables defined in layout properties
|
|
QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
int varIndex = 0;
|
|
Q_FOREACH ( const QString &variableName, variableNames )
|
|
{
|
|
if ( varIndex >= variableValues.length() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
QVariant varValue = variableValues.at( varIndex );
|
|
varIndex++;
|
|
scope->setVariable( variableName, varValue );
|
|
}
|
|
|
|
//add known layout context variables
|
|
if ( const QgsMasterLayoutInterface *l = dynamic_cast< const QgsMasterLayoutInterface * >( layout ) )
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_name" ), l->name(), true ) );
|
|
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_numpages" ), layout->pageCollection()->pageCount(), true ) );
|
|
if ( layout->pageCollection()->pageCount() > 0 )
|
|
{
|
|
// just take first page size
|
|
QSizeF s = layout->pageCollection()->page( 0 )->sizeWithUnits().toQSizeF();
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
|
|
}
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_dpi" ), layout->renderContext().dpi(), true ) );
|
|
|
|
scope->addFunction( QStringLiteral( "item_variables" ), new GetLayoutItemVariables( layout ) );
|
|
|
|
if ( layout->reportContext().layer() )
|
|
{
|
|
scope->setFields( layout->reportContext().layer()->fields() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), layout->reportContext().layer()->id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), layout->reportContext().layer()->name(), true ) );
|
|
}
|
|
|
|
if ( layout->reportContext().feature().isValid() )
|
|
{
|
|
QgsFeature atlasFeature = layout->reportContext().feature();
|
|
scope->setFeature( atlasFeature );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
|
|
}
|
|
|
|
return scope.release();
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayoutVariable( QgsLayout *layout, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !layout )
|
|
return;
|
|
|
|
//write variable to composition
|
|
QStringList variableNames = layout->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = layout->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
variableNames << name;
|
|
variableValues << value.toString();
|
|
|
|
layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayoutVariables( QgsLayout *layout, const QVariantMap &variables )
|
|
{
|
|
if ( !layout )
|
|
return;
|
|
|
|
QStringList variableNames;
|
|
QStringList variableValues;
|
|
|
|
QVariantMap::const_iterator it = variables.constBegin();
|
|
for ( ; it != variables.constEnd(); ++it )
|
|
{
|
|
variableNames << it.key();
|
|
variableValues << it.value().toString();
|
|
}
|
|
|
|
layout->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
layout->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::compositionAtlasScope( const QgsAtlasComposition *atlas )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
|
|
if ( !atlas )
|
|
{
|
|
//add some dummy atlas variables. This is done so that as in certain contexts we want to show
|
|
//users that these variables are available even if they have no current value
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), QString(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( QgsFeature() ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), 0, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( QgsGeometry() ), true ) );
|
|
return scope;
|
|
}
|
|
|
|
//add known atlas variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->numFeatures(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->currentPageName(), true ) );
|
|
|
|
if ( atlas->enabled() && atlas->coverageLayer() )
|
|
{
|
|
scope->setFields( atlas->coverageLayer()->fields() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), atlas->coverageLayer()->id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), atlas->coverageLayer()->name(), true ) );
|
|
}
|
|
|
|
if ( atlas->enabled() )
|
|
{
|
|
QgsFeature atlasFeature = atlas->feature();
|
|
scope->setFeature( atlasFeature );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::atlasScope( QgsLayoutAtlas *atlas )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Atlas" ) );
|
|
if ( !atlas )
|
|
{
|
|
//add some dummy atlas variables. This is done so that as in certain contexts we want to show
|
|
//users that these variables are available even if they have no current value
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), QString(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( QgsFeature() ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), 0, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( QgsGeometry() ), true ) );
|
|
return scope;
|
|
}
|
|
|
|
//add known atlas variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->count(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->nameForPage( atlas->currentFeatureNumber() ), true ) );
|
|
|
|
if ( atlas->enabled() && atlas->coverageLayer() )
|
|
{
|
|
scope->setFields( atlas->coverageLayer()->fields() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layerid" ), atlas->coverageLayer()->id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_layername" ), atlas->coverageLayer()->name(), true ) );
|
|
}
|
|
|
|
if ( atlas->enabled() )
|
|
{
|
|
QgsFeature atlasFeature = atlas->layout()->reportContext().feature();
|
|
scope->setFeature( atlasFeature );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_feature" ), QVariant::fromValue( atlasFeature ), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featureid" ), atlasFeature.id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_geometry" ), QVariant::fromValue( atlasFeature.geometry() ), true ) );
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::composerItemScope( const QgsComposerItem *composerItem )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Composer Item" ) );
|
|
if ( !composerItem )
|
|
return scope;
|
|
|
|
//add variables defined in composer item properties
|
|
QStringList variableNames = composerItem->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = composerItem->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
int varIndex = 0;
|
|
Q_FOREACH ( const QString &variableName, variableNames )
|
|
{
|
|
if ( varIndex >= variableValues.length() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
QVariant varValue = variableValues.at( varIndex );
|
|
varIndex++;
|
|
scope->setVariable( variableName, varValue );
|
|
}
|
|
|
|
//add known composer item context variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_id" ), composerItem->id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_uuid" ), composerItem->uuid(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_page" ), composerItem->page(), true ) );
|
|
return scope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::layoutItemScope( const QgsLayoutItem *item )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layout Item" ) );
|
|
if ( !item )
|
|
return scope;
|
|
|
|
//add variables defined in composer item properties
|
|
const QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
const QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
int varIndex = 0;
|
|
for ( const QString &variableName : variableNames )
|
|
{
|
|
if ( varIndex >= variableValues.length() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
QVariant varValue = variableValues.at( varIndex );
|
|
varIndex++;
|
|
scope->setVariable( variableName, varValue );
|
|
}
|
|
|
|
//add known composer item context variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_id" ), item->id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "item_uuid" ), item->uuid(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_page" ), item->page() + 1, true ) );
|
|
|
|
if ( item->layout() )
|
|
{
|
|
const QgsLayoutItemPage *page = item->layout()->pageCollection()->page( item->page() );
|
|
if ( page )
|
|
{
|
|
const QSizeF s = page->sizeWithUnits().toQSizeF();
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), s.height(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), s.width(), true ) );
|
|
}
|
|
else
|
|
{
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pageheight" ), QVariant(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layout_pagewidth" ), QVariant(), true ) );
|
|
}
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayoutItemVariable( QgsLayoutItem *item, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !item )
|
|
return;
|
|
|
|
//write variable to composer item
|
|
QStringList variableNames = item->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = item->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
variableNames << name;
|
|
variableValues << value.toString();
|
|
|
|
item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setLayoutItemVariables( QgsLayoutItem *item, const QVariantMap &variables )
|
|
{
|
|
if ( !item )
|
|
return;
|
|
|
|
QStringList variableNames;
|
|
QStringList variableValues;
|
|
|
|
QVariantMap::const_iterator it = variables.constBegin();
|
|
for ( ; it != variables.constEnd(); ++it )
|
|
{
|
|
variableNames << it.key();
|
|
variableValues << it.value().toString();
|
|
}
|
|
|
|
item->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
item->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setComposerItemVariable( QgsComposerItem *composerItem, const QString &name, const QVariant &value )
|
|
{
|
|
if ( !composerItem )
|
|
return;
|
|
|
|
//write variable to composer item
|
|
QStringList variableNames = composerItem->customProperty( QStringLiteral( "variableNames" ) ).toStringList();
|
|
QStringList variableValues = composerItem->customProperty( QStringLiteral( "variableValues" ) ).toStringList();
|
|
|
|
variableNames << name;
|
|
variableValues << value.toString();
|
|
|
|
composerItem->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
composerItem->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
void QgsExpressionContextUtils::setComposerItemVariables( QgsComposerItem *composerItem, const QVariantMap &variables )
|
|
{
|
|
if ( !composerItem )
|
|
return;
|
|
|
|
QStringList variableNames;
|
|
QStringList variableValues;
|
|
|
|
QVariantMap::const_iterator it = variables.constBegin();
|
|
for ( ; it != variables.constEnd(); ++it )
|
|
{
|
|
variableNames << it.key();
|
|
variableValues << it.value().toString();
|
|
}
|
|
|
|
composerItem->setCustomProperty( QStringLiteral( "variableNames" ), variableNames );
|
|
composerItem->setCustomProperty( QStringLiteral( "variableValues" ), variableValues );
|
|
}
|
|
|
|
QgsExpressionContext QgsExpressionContextUtils::createFeatureBasedContext( const QgsFeature &feature, const QgsFields &fields )
|
|
{
|
|
QgsExpressionContextScope *scope = new QgsExpressionContextScope();
|
|
scope->setFeature( feature );
|
|
scope->setFields( fields );
|
|
return QgsExpressionContext() << scope;
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap ¶meters, QgsProcessingContext &context )
|
|
{
|
|
// set aside for future use
|
|
Q_UNUSED( context );
|
|
|
|
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Algorithm" ) ) );
|
|
if ( !algorithm )
|
|
return scope.release();
|
|
|
|
//add standard algorithm variables
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "algorithm_id" ), algorithm->id(), true ) );
|
|
|
|
scope->addFunction( QStringLiteral( "parameter" ), new GetProcessingParameterValue( parameters ) );
|
|
|
|
return scope.release();
|
|
}
|
|
|
|
QgsExpressionContextScope *QgsExpressionContextUtils::notificationScope( const QString &message )
|
|
{
|
|
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "notification_message" ), message, true ) );
|
|
return scope.release();
|
|
}
|
|
|
|
void QgsExpressionContextUtils::registerContextFunctions()
|
|
{
|
|
QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
|
|
QgsExpression::registerFunction( new GetComposerItemVariables( nullptr ) );
|
|
QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer *>() ) );
|
|
QgsExpression::registerFunction( new GetProcessingParameterValue( QVariantMap() ) );
|
|
}
|
|
|
|
bool QgsScopedExpressionFunction::usesGeometry( const QgsExpressionNodeFunction *node ) const
|
|
{
|
|
Q_UNUSED( node )
|
|
return mUsesGeometry;
|
|
}
|
|
|
|
QSet<QString> QgsScopedExpressionFunction::referencedColumns( const QgsExpressionNodeFunction *node ) const
|
|
{
|
|
Q_UNUSED( node )
|
|
return mReferencedColumns;
|
|
}
|
|
|
|
bool QgsScopedExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
|
|
{
|
|
return allParamsStatic( node, parent, context );
|
|
}
|