29#include <nlohmann/json.hpp>
30using namespace nlohmann;
51 return QStringLiteral(
"ValueRelation" );
58 if ( cache.isValid() )
67 if ( config.value( QStringLiteral(
"AllowMulti" ) ).toBool() )
71 if ( layer->
fields().
at( fieldIndex ).
type() == QVariant::Map )
74 keyList = value.toStringList();
81 QStringList valueList;
85 if ( keyList.contains( item.key.toString() ) )
87 valueList << item.value;
91 return valueList.join( QLatin1String(
", " ) ).prepend(
'{' ).append(
'}' );
102 if ( item.key == value )
109 return QStringLiteral(
"(%1)" ).arg( value.toString() );
120 Q_UNUSED( fieldIndex )
121 return QVariant::fromValue<ValueRelationCache>(
createCache( config ) );
126 const QVariantMap &config,
138 int ki = fields.
indexOf( config.value( QStringLiteral(
"Key" ) ).toString() );
139 int vi = fields.
indexOf( config.value( QStringLiteral(
"Value" ) ).toString() );
146 const QString descriptionExpressionString = config.value(
"Description" ).toString();
147 QgsExpression descriptionExpression( descriptionExpressionString );
149 descriptionExpression.
prepare( &context );
153 const QString filterExpression = config.value( QStringLiteral(
"FilterExpression" ) ).toString();
178 if ( descriptionExpression.
isValid() )
181 description = descriptionExpression.
evaluate( &context ).toString();
186 if ( config.value( QStringLiteral(
"OrderByValue" ) ).toBool() )
201 QList<QgsVectorLayerRef> result;
202 const QString layerId { config.value( QStringLiteral(
"Layer" ) ).toString() };
203 const QString layerName { config.value( QStringLiteral(
"LayerName" ) ).toString() };
204 const QString providerName { config.value( QStringLiteral(
"LayerProviderName" ) ).toString() };
205 const QString layerSource { config.value( QStringLiteral(
"LayerSource" ) ).toString() };
206 if ( ! layerId.isEmpty() && ! layerName.isEmpty() && ! providerName.isEmpty() && ! layerSource.isEmpty() )
208 result.append(
QgsVectorLayerRef( layerId, layerName, layerSource, providerName ) );
217 if (
auto *lProject = context.
project() )
219 const QgsVectorLayer *referencedLayer = qobject_cast<QgsVectorLayer *>( lProject->mapLayer( config[QStringLiteral(
"Layer" )].toString() ) );
220 if ( referencedLayer )
222 int fieldIndex = referencedLayer->
fields().
indexOf( config.value( QStringLiteral(
"Key" ) ).toString() );
223 values = qgis::setToList( referencedLayer->
uniqueValues( fieldIndex, countLimit ) );
231 QStringList checkList;
232 if ( value.type() == QVariant::StringList )
234 checkList = value.toStringList();
238 QVariantList valuesList;
239 if ( value.type() == QVariant::String )
242 auto newVal { value };
243 if ( newVal.toString().trimmed().startsWith(
'{' ) )
248 else if ( newVal.toString().trimmed().startsWith(
'[' ) )
253 for (
auto &element :
json::parse( newVal.toString().toStdString() ) )
255 if ( element.is_number_integer() )
257 valuesList.push_back( element.get<
int>() );
259 else if ( element.is_number_unsigned() )
261 valuesList.push_back( element.get<
unsigned>() );
263 else if ( element.is_string() )
265 valuesList.push_back( QString::fromStdString( element.get<std::string>() ) );
269 catch ( json::parse_error &ex )
271 QgsMessageLog::logMessage( QObject::tr(
"Cannot parse JSON like string '%1' Error: %2" ).arg( newVal.toString(), ex.what() ) );
275 else if ( value.type() == QVariant::List )
277 valuesList = value.toList( );
280 checkList.reserve( valuesList.size() );
281 for (
const QVariant &listItem : std::as_const( valuesList ) )
283 QString v( listItem.toString( ) );
285 checkList.append( v );
295 QSet< QString > formVariables = qgis::listToSet( scope->variableNames() );
297 formVariables.intersect( usedVariables );
298 return formVariables;
304 QSet< QString > formVariables = qgis::listToSet( scope->variableNames() );
306 formVariables.intersect( usedVariables );
307 return formVariables;
322 QSet<QString> attributes;
326 const QSet<QString> formFunctions( qgis::listToSet( scope->functionNames() )
330 for (
const auto &f : expFunctions )
333 if ( formFunctions.contains( fd->
name( ) ) )
335 const QList<QgsExpressionNode *> cExpressionNodes { f->args( )->list() };
336 for (
const auto ¶m : std::as_const( cExpressionNodes ) )
338 attributes.insert( param->eval( &exp, &context ).toString() );
347 QSet<QString> attributes;
351 const QSet<QString> formFunctions( qgis::listToSet( scope->functionNames() )
355 for (
const auto &f : expFunctions )
358 if ( formFunctions.contains( fd->
name( ) ) )
360 const QList<QgsExpressionNode *> cExpressionNodes { f->args( )->list() };
361 for (
const auto ¶m : std::as_const( cExpressionNodes ) )
363 attributes.insert( param->eval( &exp, &context ).toString() );
375 for (
auto it = attrs.constBegin() ; it != attrs.constEnd(); it++ )
387 for (
auto it = parentAttrs.constBegin() ; it != parentAttrs.constEnd(); it++ )
389 if ( ! parentFeature.
attribute( *it ).isValid() )
401 config.value( QStringLiteral(
"LayerName" ) ).toString(),
402 config.value( QStringLiteral(
"LayerSource" ) ).toString(),
403 config.value( QStringLiteral(
"LayerProviderName" ) ).toString() };
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
A abstract base class for defining QgsExpression functions.
QString name() const
The name of the function.
An expression node for expression functions.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QList< const T * > findNodes() const
Returns a list of all nodes of the given class which are used in this expression.
QSet< QString > referencedVariables() const
Returns a list of all variables which are used in this expression.
QSet< QString > referencedFunctions() const
Returns a list of the names of all functions which are used in this expression.
QVariant evaluate()
Evaluate the feature and return the result.
bool isValid() const
Checks if this expression is valid.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
bool isValid() const
Returns the validity of this feature.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
A context for field formatter containing information like the project.
QgsProject * project() const
Returns the project used in field formatter.
Container of fields for a vector layer.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QVariantList parseArray(const QString &string)
Returns a QVariantList created out of a string containing an array in postgres array format {1,...
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static QgsProject * instance()
Returns the QgsProject singleton instance.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)
QSet< int > QgsAttributeIds
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
TYPE * resolveByIdOrNameOnly(const QgsProject *project)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.