QGIS API Documentation 4.3.0-Master (16eddb2670e)
Loading...
Searching...
No Matches
qgsvaluerelationfieldformatter.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvaluerelationfieldformatter.cpp - QgsValueRelationFieldFormatter
3
4 ---------------------
5 begin : 3.12.2016
6 copyright : (C) 2016 by Matthias Kuhn
7 email : matthias@opengis.ch
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
17
18#include <nlohmann/json.hpp>
19
20#include "qgis.h"
21#include "qgsapplication.h"
24#include "qgsmessagelog.h"
26#include "qgsproject.h"
27#include "qgsvariantutils.h"
28#include "qgsvectorlayer.h"
29#include "qgsvectorlayerref.h"
30
31#include <QString>
32
33using namespace Qt::StringLiterals;
34
35using namespace nlohmann;
36
37#include <QSettings>
38
40{
41 setFlags( flags() | QgsFieldFormatter::CanProvideAvailableValues );
42}
43
45{
46 return u"ValueRelation"_s;
47}
48
49QString QgsValueRelationFieldFormatter::representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const
50{
51 ValueRelationCache vrCache;
52
53 if ( cache.isValid() )
54 {
56 }
57 else
58 {
59 QgsProject *project = layer->project(); // skip-keyword-check
60 // TODO QGIS 5.0 -- remove the fallback to QgsProject.instance() return empty QString instead
61 if ( !project )
62 {
63 project = QgsProject::instance(); // skip-keyword-check
64 }
65 vrCache = QgsValueRelationFieldFormatter::createCache( config, project );
66 }
67
68 if ( config.value( u"AllowMulti"_s ).toBool() )
69 {
70 QStringList keyList;
71
72 if ( layer->fields().at( fieldIndex ).type() == QMetaType::Type::QVariantMap )
73 {
74 //because of json it's stored as QVariantList
75 keyList = value.toStringList();
76 }
77 else
78 {
79 keyList = valueToStringList( value );
80 }
81
82 QStringList valueList;
83
84 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &item : std::as_const( vrCache ) )
85 {
86 if ( keyList.contains( item.key.toString() ) )
87 {
88 valueList << item.value;
89 }
90 }
91
92 return valueList.join( ", "_L1 ).prepend( '{' ).append( '}' );
93 }
94 else
95 {
96 if ( QgsVariantUtils::isNull( value ) )
97 {
99 }
100
101 for ( const QgsValueRelationFieldFormatter::ValueRelationItem &item : std::as_const( vrCache ) )
102 {
103 if ( item.key == value )
104 {
105 return item.value;
106 }
107 }
108 }
109
110 return u"(%1)"_s.arg( value.toString() );
111}
112
113QVariant QgsValueRelationFieldFormatter::sortValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const
114{
115 return QgsVariantUtils::isNull( value ) ? QString() : representValue( layer, fieldIndex, config, cache, value );
116}
117
118QVariant QgsValueRelationFieldFormatter::createCache( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config ) const
119{
120 Q_UNUSED( layer )
121 Q_UNUSED( fieldIndex )
122 QgsProject *project = layer->project();
123
124 // TODO QGIS 5.0 -- remove the fallback to QgsProject.instance() when no project is associated, return empty QVariant instead
125 if ( !project )
126 {
127 project = QgsProject::instance(); // skip-keyword-check
128 }
129
130 return QVariant::fromValue<ValueRelationCache>( createCache( config, project ) );
131}
132
133QgsValueRelationFieldFormatter::ValueRelationCache QgsValueRelationFieldFormatter::createCache( const QVariantMap &config, const QgsFeature &formFeature, const QgsFeature &parentFormFeature )
134{
135 return createCache( config, QgsProject::instance(), formFeature, parentFormFeature ); // skip-keyword-check
136}
137
139 const QVariantMap &config, const QgsProject *project, const QgsFeature &formFeature, const QgsFeature &parentFormFeature
140)
141{
142 ValueRelationCache cache;
143
144 const QgsVectorLayer *layer = resolveLayer( config, project );
145
146 if ( !layer )
147 return cache;
148
149 QgsFields fields = layer->fields();
150 const int keyIdx = fields.indexOf( config.value( u"Key"_s ).toString() );
151 const int valueIdx = fields.indexOf( config.value( u"Value"_s ).toString() );
152
153 QgsFeatureRequest request;
154
156 QgsAttributeIds subsetOfAttributes { keyIdx, valueIdx };
157
158 const int groupIdx = fields.lookupField( config.value( u"Group"_s ).toString() );
159 if ( groupIdx > -1 )
160 {
161 subsetOfAttributes << groupIdx;
162 }
163
164 const bool orderByField { config.value( u"OrderByField"_s ).toBool() };
165 const int fieldIdx { orderByField ? layer->fields().lookupField( config.value( u"OrderByFieldName"_s ).toString() ) : -1 };
166 const bool reverseSort { config.value( u"OrderByDescending"_s ).toBool() };
167 if ( fieldIdx != -1 )
168 {
169 subsetOfAttributes << fieldIdx;
170 }
171
172 const QString descriptionExpressionString = config.value( "Description" ).toString();
173 QgsExpression descriptionExpression( descriptionExpressionString );
175 descriptionExpression.prepare( &context );
176 subsetOfAttributes += descriptionExpression.referencedAttributeIndexes( layer->fields() );
177 request.setSubsetOfAttributes( qgis::setToList( subsetOfAttributes ) );
178
179 const QString filterExpression = config.value( u"FilterExpression"_s ).toString();
180
181 // Skip the filter and build a full cache if the form scope is required and the feature
182 // is not valid or the attributes required for the filter have no valid value
183 // Note: parent form scope is not checked for usability because it's supposed to
184 // be used into a coalesce that retrieve the current value of the parent
185 // from the parent layer when used outside of an embedded form
186 if ( !filterExpression.isEmpty() && ( !( expressionRequiresFormScope( filterExpression ) ) || expressionIsUsable( filterExpression, formFeature ) ) )
187 {
188 QgsExpressionContext filterContext = context;
189 if ( formFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresFormScope( filterExpression ) )
190 filterContext.appendScope( QgsExpressionContextUtils::formScope( formFeature ) );
191 if ( parentFormFeature.isValid() && QgsValueRelationFieldFormatter::expressionRequiresParentFormScope( filterExpression ) )
192 filterContext.appendScope( QgsExpressionContextUtils::parentFormScope( parentFormFeature ) );
193 request.setExpressionContext( filterContext );
194 request.setFilterExpression( filterExpression );
195 }
196
197 QgsFeatureIterator fit = layer->getFeatures( request );
198 QMap<QVariant, QVariant> orderByFieldValues;
199
200 QgsFeature f;
201 while ( fit.nextFeature( f ) )
202 {
203 QString description;
204 if ( descriptionExpression.isValid() )
205 {
206 context.setFeature( f );
207 description = descriptionExpression.evaluate( &context ).toString();
208 }
209 const QVariant group = groupIdx > -1 ? f.attribute( groupIdx ) : QVariant();
210 const QVariant keyValue = f.attribute( keyIdx );
211 if ( fieldIdx != -1 )
212 {
213 orderByFieldValues.insert( keyValue, f.attribute( fieldIdx ) );
214 }
215 cache.append( ValueRelationItem( keyValue, f.attribute( valueIdx ).toString(), description, group ) );
216 }
217
218
219 if ( config.value( u"OrderByValue"_s ).toBool() )
220 {
221 std::sort( cache.begin(), cache.end(), [&reverseSort]( const QgsValueRelationFieldFormatter::ValueRelationItem &p1, const QgsValueRelationFieldFormatter::ValueRelationItem &p2 ) -> bool {
222 if ( reverseSort )
223 return p1.group == p2.group ? qgsVariantGreaterThan( p1.value, p2.value ) : qgsVariantGreaterThan( p1.group, p2.group );
224 else
225 return p1.group == p2.group ? qgsVariantLessThan( p1.value, p2.value ) : qgsVariantLessThan( p1.group, p2.group );
226 } );
227 }
228 // Order by field
229 else if ( fieldIdx != -1 )
230 {
231 std::sort( cache.begin(), cache.end(), [&reverseSort, &orderByFieldValues]( const QgsValueRelationFieldFormatter::ValueRelationItem &p1, const QgsValueRelationFieldFormatter::ValueRelationItem &p2 ) -> bool {
232 if ( reverseSort )
233 return p1.group == p2.group ? qgsVariantGreaterThan( orderByFieldValues.value( p1.key ), orderByFieldValues.value( p2.key ) ) : qgsVariantGreaterThan( p1.group, p2.group );
234 else
235 return p1.group == p2.group ? qgsVariantLessThan( orderByFieldValues.value( p1.key ), orderByFieldValues.value( p2.key ) ) : qgsVariantLessThan( p1.group, p2.group );
236 } );
237 }
238 // OrderByKey is the default
239 else
240 {
241 std::sort( cache.begin(), cache.end(), [&reverseSort]( const QgsValueRelationFieldFormatter::ValueRelationItem &p1, const QgsValueRelationFieldFormatter::ValueRelationItem &p2 ) -> bool {
242 if ( reverseSort )
243 return p1.group == p2.group ? qgsVariantGreaterThan( p1.key, p2.key ) : qgsVariantGreaterThan( p1.group, p2.group );
244 else
245 return p1.group == p2.group ? qgsVariantLessThan( p1.key, p2.key ) : qgsVariantLessThan( p1.group, p2.group );
246 } );
247 }
248
249 return cache;
250}
251
252
253QList<QgsVectorLayerRef> QgsValueRelationFieldFormatter::layerDependencies( const QVariantMap &config ) const
254{
255 QList<QgsVectorLayerRef> result;
256 const QString layerId { config.value( u"Layer"_s ).toString() };
257 const QString layerName { config.value( u"LayerName"_s ).toString() };
258 const QString providerName { config.value( u"LayerProviderName"_s ).toString() };
259 const QString layerSource { config.value( u"LayerSource"_s ).toString() };
260 if ( !layerId.isEmpty() && !layerName.isEmpty() && !providerName.isEmpty() && !layerSource.isEmpty() )
261 {
262 result.append( QgsVectorLayerRef( layerId, layerName, layerSource, providerName ) );
263 }
264 return result;
265}
266
267QVariantList QgsValueRelationFieldFormatter::availableValues( const QVariantMap &config, int countLimit, const QgsFieldFormatterContext &context ) const
268{
269 QVariantList values;
270
271 if ( auto *lProject = context.project() )
272 {
273 const QgsVectorLayer *referencedLayer = qobject_cast<QgsVectorLayer *>( lProject->mapLayer( config[u"Layer"_s].toString() ) );
274 if ( referencedLayer )
275 {
276 int fieldIndex = referencedLayer->fields().indexOf( config.value( u"Key"_s ).toString() );
277 values = qgis::setToList( referencedLayer->uniqueValues( fieldIndex, countLimit ) );
278 }
279 }
280 return values;
281}
282
283QStringList QgsValueRelationFieldFormatter::valueToStringList( const QVariant &value )
284{
285 QStringList checkList;
286 if ( value.userType() == QMetaType::Type::QStringList )
287 {
288 checkList = value.toStringList();
289 }
290 else
291 {
292 QVariantList valuesList;
293 if ( value.userType() == QMetaType::Type::QString )
294 {
295 // This must be an array representation
296 auto newVal { value };
297 if ( newVal.toString().trimmed().startsWith( '{' ) )
298 {
299 //normal case
300 valuesList = QgsPostgresStringUtils::parseArray( newVal.toString() );
301 }
302 else if ( newVal.toString().trimmed().startsWith( '[' ) )
303 {
304 //fallback, in case it's a json array
305 try
306 {
307 for ( auto &element : json::parse( newVal.toString().toStdString() ) )
308 {
309 if ( element.is_number_integer() )
310 {
311 valuesList.push_back( element.get<int>() );
312 }
313 else if ( element.is_number_unsigned() )
314 {
315 valuesList.push_back( element.get<unsigned>() );
316 }
317 else if ( element.is_string() )
318 {
319 valuesList.push_back( QString::fromStdString( element.get<std::string>() ) );
320 }
321 }
322 }
323 catch ( json::parse_error &ex )
324 {
325 QgsMessageLog::logMessage( QObject::tr( "Cannot parse JSON like string '%1' Error: %2" ).arg( newVal.toString(), ex.what() ) );
326 }
327 }
328 }
329 else if ( value.userType() == QMetaType::Type::QVariantList )
330 {
331 valuesList = value.toList();
332 }
333
334 checkList.reserve( valuesList.size() );
335 for ( const QVariant &listItem : std::as_const( valuesList ) )
336 {
337 QString v( listItem.toString() );
338 if ( !v.isEmpty() )
339 checkList.append( v );
340 }
341 }
342 return checkList;
343}
344
345
346QSet<QString> QgsValueRelationFieldFormatter::expressionFormVariables( const QString &expression )
347{
348 std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::formScope() );
349 QSet< QString > formVariables = qgis::listToSet( scope->variableNames() );
350 const QSet< QString > usedVariables = QgsExpression( expression ).referencedVariables();
351 formVariables.intersect( usedVariables );
352 return formVariables;
353}
354
356{
357 std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::parentFormScope() );
358 QSet< QString > formVariables = qgis::listToSet( scope->variableNames() );
359 const QSet< QString > usedVariables = QgsExpression( expression ).referencedVariables();
360 formVariables.intersect( usedVariables );
361 return formVariables;
362}
363
365{
366 return !( expressionFormAttributes( expression ).isEmpty() && expressionFormVariables( expression ).isEmpty() );
367}
368
370{
371 return !( expressionParentFormAttributes( expression ).isEmpty() && expressionParentFormVariables( expression ).isEmpty() );
372}
373
375{
376 QSet<QString> attributes;
377 QgsExpression exp( expression );
378 std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::parentFormScope() );
379 // List of form function names used in the expression
380 const QSet<QString> formFunctions( qgis::listToSet( scope->functionNames() ).intersect( exp.referencedFunctions() ) );
381 const QList<const QgsExpressionNodeFunction *> expFunctions( exp.findNodes<QgsExpressionNodeFunction>() );
382 QgsExpressionContext context;
383
384 for ( const auto &f : expFunctions )
385 {
386 const QgsExpression::SharedFunctionPtr fd = f->function();
387 if ( formFunctions.contains( fd->name() ) )
388 {
389 const QList<QgsExpressionNode *> cExpressionNodes { f->args()->list() };
390 for ( const auto &param : std::as_const( cExpressionNodes ) )
391 {
392 attributes.insert( param->eval( &exp, &context ).toString() );
393 }
394 }
395 }
396 return attributes;
397}
398
399QSet<QString> QgsValueRelationFieldFormatter::expressionFormAttributes( const QString &expression )
400{
401 QSet<QString> attributes;
402 QgsExpression exp( expression );
403 std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::formScope() );
404 // List of form function names used in the expression
405 const QSet<QString> formFunctions( qgis::listToSet( scope->functionNames() ).intersect( exp.referencedFunctions() ) );
406 const QList<const QgsExpressionNodeFunction *> expFunctions( exp.findNodes<QgsExpressionNodeFunction>() );
407 QgsExpressionContext context;
408
409 for ( const auto &f : expFunctions )
410 {
411 const QgsExpression::SharedFunctionPtr fd = f->function();
412 if ( formFunctions.contains( fd->name() ) )
413 {
414 const QList<QgsExpressionNode *> cExpressionNodes { f->args()->list() };
415 for ( const auto &param : std::as_const( cExpressionNodes ) )
416 {
417 attributes.insert( param->eval( &exp, &context ).toString() );
418 }
419 }
420 }
421 return attributes;
422}
423
424bool QgsValueRelationFieldFormatter::expressionIsUsable( const QString &expression, const QgsFeature &feature, const QgsFeature &parentFeature )
425{
426 const QSet<QString> attrs = expressionFormAttributes( expression );
427 for ( auto it = attrs.constBegin(); it != attrs.constEnd(); it++ )
428 {
429 if ( feature.fieldNameIndex( *it ) < 0 )
430 return false;
431 }
432
433 if ( !expressionFormVariables( expression ).isEmpty() && feature.geometry().isEmpty() )
434 return false;
435
436 if ( parentFeature.isValid() )
437 {
438 const QSet<QString> parentAttrs = expressionParentFormAttributes( expression );
439 for ( auto it = parentAttrs.constBegin(); it != parentAttrs.constEnd(); it++ )
440 {
441 if ( !parentFeature.attribute( *it ).isValid() )
442 return false;
443 }
444 if ( !expressionParentFormVariables( expression ).isEmpty() && parentFeature.geometry().isEmpty() )
445 return false;
446 }
447 return true;
448}
449
450QgsVectorLayer *QgsValueRelationFieldFormatter::resolveLayer( const QVariantMap &config, const QgsProject *project )
451{
452 QgsVectorLayerRef ref { config.value( u"Layer"_s ).toString(), config.value( u"LayerName"_s ).toString(), config.value( u"LayerSource"_s ).toString(), config.value( u"LayerProviderName"_s ).toString() };
453 return ref.resolveByIdOrNameOnly( project );
454}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2380
static QString nullRepresentation()
Returns the string 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.
An expression node for expression functions.
Handles 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.
std::shared_ptr< QgsExpressionFunction > SharedFunctionPtr
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)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags 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.
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...
Definition qgsfeature.h:60
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
QgsGeometry geometry
Definition qgsfeature.h:66
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE 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.
Flags flags() const
Returns the flags.
void setFlags(const Flags &flags)
Sets the flags.
QMetaType::Type type
Definition qgsfield.h:63
Container of fields for a vector layer.
Definition qgsfields.h:45
Q_INVOKABLE 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).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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,...
Definition qgsproject.h:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
static QgsVectorLayer * resolveLayer(const QVariantMap &config, const QgsProject *project)
Returns the (possibly nullptr) layer from the widget's config and project.
static QSet< QString > expressionFormVariables(const QString &expression)
Returns a list of variables required by the form context expression.
static bool expressionRequiresFormScope(const QString &expression)
Check if the expression requires a form scope (i.e.
QString id() const override
Returns a unique id for this field formatter.
static bool expressionRequiresParentFormScope(const QString &expression)
Check if the expression requires a parent form scope (i.e.
QString representValue(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value) const override
Create a pretty String representation of the value.
QVariant sortValue(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value) const override
If the default sort order should be overwritten for this widget, you can transform the value in here.
QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const override
Create a cache for a given field.
QList< QgsVectorLayerRef > layerDependencies(const QVariantMap &config) const override
Returns a list of weak layer references to other layers required by this formatter for the given conf...
static QSet< QString > expressionParentFormVariables(const QString &expression)
Returns a list of variables required by the parent form's form context expression.
static QSet< QString > expressionParentFormAttributes(const QString &expression)
Returns a list of attributes required by the parent form's form context expression.
static QStringList valueToStringList(const QVariant &value)
Utility to convert a list or a string representation of an (hstore style: {1,2...}...
static QSet< QString > expressionFormAttributes(const QString &expression)
Returns a list of attributes required by the form context expression.
static bool expressionIsUsable(const QString &expression, const QgsFeature &feature, const QgsFeature &parentFeature=QgsFeature())
Check whether the feature has all values required by the expression, optionally checks for parentFeat...
QVariantList availableValues(const QVariantMap &config, int countLimit, const QgsFieldFormatterContext &context) const override
Returns a list of the values that would be possible to select with this widget type On a RelationRefe...
QVector< QgsValueRelationFieldFormatter::ValueRelationItem > ValueRelationCache
QgsValueRelationFieldFormatter()
Constructor for QgsValueRelationFieldFormatter.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
Q_INVOKABLE QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const final
Calculates a list of unique values contained within an attribute in the layer.
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.