QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsvectorlayerutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayerutils.cpp
3 -----------------------
4 Date : October 2016
5 Copyright : (C) 2016 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 "qgsvectorlayerutils.h"
17
18#include <memory>
19
20#include "qgsauxiliarystorage.h"
23#include "qgsfeatureiterator.h"
24#include "qgsfeaturerequest.h"
25#include "qgsfeedback.h"
26#include "qgspainteffect.h"
27#include "qgspallabeling.h"
28#include "qgsproject.h"
29#include "qgsrelationmanager.h"
30#include "qgsrenderer.h"
31#include "qgsstyle.h"
33#include "qgssymbollayer.h"
35#include "qgsthreadingutils.h"
38#include "qgsvectorlayer.h"
41
42#include <QRegularExpression>
43#include <QString>
44
45using namespace Qt::StringLiterals;
46
47QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
48{
49 std::unique_ptr<QgsExpression> expression;
51
52 int attrNum = layer->fields().lookupField( fieldOrExpression );
53 if ( attrNum == -1 )
54 {
55 // try to use expression
56 expression = std::make_unique<QgsExpression>( fieldOrExpression );
58
59 if ( expression->hasParserError() || !expression->prepare( &context ) )
60 {
61 ok = false;
62 return QgsFeatureIterator();
63 }
64 }
65
66 QSet<QString> lst;
67 if ( !expression )
68 lst.insert( fieldOrExpression );
69 else
70 lst = expression->referencedColumns();
71
72 QgsFeatureRequest request
73 = QgsFeatureRequest().setFlags( ( expression && expression->needsGeometry() ) ? Qgis::FeatureRequestFlag::NoFlags : Qgis::FeatureRequestFlag::NoGeometry ).setSubsetOfAttributes( lst, layer->fields() );
74
75 ok = true;
76 if ( !selectedOnly )
77 {
78 return layer->getFeatures( std::move( request ) );
79 }
80 else
81 {
82 return layer->getSelectedFeatures( std::move( request ) );
83 }
84}
85
86QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
87{
88 QList<QVariant> values;
89 QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
90 if ( ok )
91 {
92 std::unique_ptr<QgsExpression> expression;
94
95 int attrNum = layer->fields().lookupField( fieldOrExpression );
96 if ( attrNum == -1 )
97 {
98 // use expression, already validated in the getValuesIterator() function
99 expression = std::make_unique<QgsExpression>( fieldOrExpression );
101 }
102
103 QgsFeature f;
104 while ( fit.nextFeature( f ) )
105 {
106 if ( expression )
107 {
108 context.setFeature( f );
109 QVariant v = expression->evaluate( &context );
110 values << v;
111 }
112 else
113 {
114 values << f.attribute( attrNum );
115 }
116 if ( feedback && feedback->isCanceled() )
117 {
118 ok = false;
119 return values;
120 }
121 }
122 }
123 return values;
124}
125
126QList<QVariant> QgsVectorLayerUtils::uniqueValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int limit, QgsFeedback *feedback )
127{
128 QSet<QVariant> uniqueValues;
129 ok = false;
130
131 const int attrNum = layer->fields().lookupField( fieldOrExpression );
132 if ( attrNum != -1 && !selectedOnly )
133 {
134 // attribute case, not selected only
135 // optimized case: directly call QgsVectorLayer::uniqueValues
136 uniqueValues = layer->uniqueValues( attrNum, limit );
137 // remove null value if necessary
138 uniqueValues.remove( QVariant() );
139 ok = true;
140 }
141 else
142 {
143 // expression or attribute - use an iterator
144 QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
145 if ( ok )
146 {
147 std::unique_ptr<QgsExpression> expression;
148 QgsExpressionContext context;
149 if ( attrNum == -1 )
150 {
151 // use expression, already validated in the getValuesIterator() function
152 expression = std::make_unique<QgsExpression>( fieldOrExpression );
154 }
155 QgsFeature feature;
156 while ( fit.nextFeature( feature ) && ( limit < 0 || uniqueValues.size() < limit ) )
157 {
158 QVariant newValue;
159 if ( expression )
160 {
161 context.setFeature( feature );
162 newValue = expression->evaluate( &context );
163 }
164 else
165 {
166 newValue = feature.attribute( attrNum );
167 }
168
169 if ( !newValue.isNull() )
170 {
171 uniqueValues.insert( newValue );
172 }
173
174 if ( feedback && feedback->isCanceled() )
175 {
176 ok = false;
177 break;
178 }
179 }
180 }
181 }
182
183 return qgis::setToList( uniqueValues );
184}
185
186QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
187{
188 QList<double> values;
189
190 if ( nullCount )
191 *nullCount = 0;
192
193 const QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
194 if ( !ok )
195 return values;
196
197 bool convertOk;
198 for ( const QVariant &value : variantValues )
199 {
200 double val = value.toDouble( &convertOk );
201 if ( convertOk )
202 values << val;
203 else if ( QgsVariantUtils::isNull( value ) )
204 {
205 if ( nullCount )
206 *nullCount += 1;
207 }
208 if ( feedback && feedback->isCanceled() )
209 {
210 ok = false;
211 return values;
212 }
213 }
214 return values;
215}
216
217bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
218{
219 if ( !layer )
220 return false;
221
222 QgsFields fields = layer->fields();
223
224 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
225 return false;
226
227
228 // If it's an unset value assume value doesn't exist
230 {
231 return false;
232 }
233
234 // If it's a joined field search the value in the source layer
235 if ( fields.fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
236 {
237 int srcFieldIndex = -1;
238 const QgsVectorLayerJoinInfo *joinInfo { layer->joinBuffer()->joinForFieldIndex( fieldIndex, fields, srcFieldIndex ) };
239 if ( !joinInfo )
240 {
241 return false;
242 }
243 fieldIndex = srcFieldIndex;
244 layer = joinInfo->joinLayer();
245 if ( !layer )
246 {
247 return false;
248 }
249 fields = layer->fields();
250 }
251
252 QString fieldName = fields.at( fieldIndex ).name();
253
254 // build up an optimised feature request
255 QgsFeatureRequest request;
256 request.setNoAttributes();
258
259 // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
260 int limit = ignoreIds.size() + 1;
261 request.setLimit( limit );
262
263 request.setFilterExpression( u"%1=%2"_s.arg( QgsExpression::quotedColumnRef( fieldName ), QgsExpression::quotedValue( value ) ) );
264
265 QgsFeature feat;
266 QgsFeatureIterator it = layer->getFeatures( request );
267 while ( it.nextFeature( feat ) )
268 {
269 if ( ignoreIds.contains( feat.id() ) )
270 continue;
271
272 return true;
273 }
274
275 return false;
276}
277
278QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
279{
280 if ( !layer )
281 return QVariant();
282
283 QgsFields fields = layer->fields();
284
285 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
286 return QVariant();
287
288 QgsField field = fields.at( fieldIndex );
289
290 if ( field.isNumeric() )
291 {
292 QVariant maxVal = layer->maximumValue( fieldIndex );
293 QVariant newVar( maxVal.toLongLong() + 1 );
294 if ( field.convertCompatible( newVar ) )
295 return newVar;
296 else
297 return QVariant();
298 }
299 else
300 {
301 switch ( field.type() )
302 {
303 case QMetaType::Type::QString:
304 {
305 QString base;
306 if ( seed.isValid() )
307 base = seed.toString();
308
309 if ( !base.isEmpty() )
310 {
311 // strip any existing _1, _2 from the seed
312 const thread_local QRegularExpression rx( u"(.*)_\\d+"_s );
313 QRegularExpressionMatch match = rx.match( base );
314 if ( match.hasMatch() )
315 {
316 base = match.captured( 1 );
317 }
318 }
319 else
320 {
321 // no base seed - fetch first value from layer
323 req.setLimit( 1 );
324 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
326 QgsFeature f;
327 layer->getFeatures( req ).nextFeature( f );
328 base = f.attribute( fieldIndex ).toString();
329 }
330
331 // try variants like base_1, base_2, etc until a new value found
332 QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
333
334 // might already be unique
335 if ( !base.isEmpty() && !vals.contains( base ) )
336 return base;
337
338 for ( int i = 1; i < 10000; ++i )
339 {
340 QString testVal = base + '_' + QString::number( i );
341 if ( !vals.contains( testVal ) )
342 return testVal;
343 }
344
345 // failed
346 return QVariant();
347 }
348
349 default:
350 // todo other types - dates? times?
351 break;
352 }
353 }
354
355 return QVariant();
356}
357
358QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
359{
360 if ( !layer )
361 return QVariant();
362
363 QgsFields fields = layer->fields();
364
365 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
366 return QVariant();
367
368 QgsField field = fields.at( fieldIndex );
369
370 if ( field.isNumeric() )
371 {
372 QVariant maxVal = existingValues.isEmpty()
373 ? 0
374 : *std::max_element( existingValues.begin(), existingValues.end(), []( const QVariant &a, const QVariant &b ) { return a.toLongLong() < b.toLongLong(); } );
375 QVariant newVar( maxVal.toLongLong() + 1 );
376 if ( field.convertCompatible( newVar ) )
377 return newVar;
378 else
379 return QVariant();
380 }
381 else
382 {
383 switch ( field.type() )
384 {
385 case QMetaType::Type::QString:
386 {
387 QString base;
388 if ( seed.isValid() )
389 base = seed.toString();
390
391 if ( !base.isEmpty() )
392 {
393 // strip any existing _1, _2 from the seed
394 const thread_local QRegularExpression rx( u"(.*)_\\d+"_s );
395 QRegularExpressionMatch match = rx.match( base );
396 if ( match.hasMatch() )
397 {
398 base = match.captured( 1 );
399 }
400 }
401 else
402 {
403 // no base seed - fetch first value from layer
405 base = existingValues.isEmpty() ? QString() : existingValues.constBegin()->toString();
406 }
407
408 // try variants like base_1, base_2, etc until a new value found
409 QStringList vals;
410 for ( const auto &v : std::as_const( existingValues ) )
411 {
412 if ( v.toString().startsWith( base ) )
413 vals.push_back( v.toString() );
414 }
415
416 // might already be unique
417 if ( !base.isEmpty() && !vals.contains( base ) )
418 return base;
419
420 for ( int i = 1; i < 10000; ++i )
421 {
422 QString testVal = base + '_' + QString::number( i );
423 if ( !vals.contains( testVal ) )
424 return testVal;
425 }
426
427 // failed
428 return QVariant();
429 }
430
431 default:
432 // todo other types - dates? times?
433 break;
434 }
435 }
436
437 return QVariant();
438}
439
440bool QgsVectorLayerUtils::attributeHasConstraints( const QgsVectorLayer *layer, int attributeIndex )
441{
442 if ( !layer )
443 return false;
444
445 if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
446 return false;
447
448 const QgsFieldConstraints constraints = layer->fields().at( attributeIndex ).constraints();
449 return (
453 );
454}
455
457 const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors, QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin
458)
459{
460 if ( !layer )
461 return false;
462
463 if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
464 return false;
465
466 QgsFields fields = layer->fields();
467 QgsField field = fields.at( attributeIndex );
468 const QVariant value = feature.attribute( attributeIndex );
469 bool valid = true;
470 errors.clear();
471
472 QgsFieldConstraints constraints = field.constraints();
473
475 && !constraints.constraintExpression().isEmpty()
478 {
480 context.setFeature( feature );
481
482 QgsExpression expr( constraints.constraintExpression() );
483
484 valid = expr.evaluate( &context ).toBool();
485
486 if ( expr.hasParserError() )
487 {
488 errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
489 }
490 else if ( expr.hasEvalError() )
491 {
492 errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
493 }
494 else if ( !valid )
495 {
496 errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
497 }
498 }
499
500 bool notNullConstraintViolated { false };
501
505 {
506 bool exempt = false;
508 {
509 int providerIdx = fields.fieldOriginIndex( attributeIndex );
510 exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
511 }
512
513 if ( !exempt )
514 {
515 const bool isNullOrUnset { QgsVariantUtils::isNull( value ) || QgsVariantUtils::isUnsetAttributeValue( value ) };
516 valid = valid && !isNullOrUnset;
517
518 if ( isNullOrUnset )
519 {
520 errors << QObject::tr( "value is NULL" );
521 notNullConstraintViolated = true;
522 }
523 }
524 }
525
526 // if a NOT NULL constraint is violated we don't need to check for UNIQUE
527 if ( !notNullConstraintViolated )
528 {
532 {
533 bool exempt = false;
535 {
536 int providerIdx = fields.fieldOriginIndex( attributeIndex );
537 exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
538 }
539
540 if ( !exempt )
541 {
542 bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
543 valid = valid && !alreadyExists;
544
545 if ( alreadyExists )
546 {
547 errors << QObject::tr( "value is not unique" );
548 }
549 }
550 }
551 }
552
553 return valid;
554}
555
557{
558 QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
559 return features.isEmpty() ? QgsFeature() : features.first();
560}
561
563{
564 if ( !layer )
565 return QgsFeatureList();
566
567 QgsFeatureList result;
568 result.reserve( featuresData.length() );
569
570 QgsExpressionContext *evalContext = context;
571 std::unique_ptr< QgsExpressionContext > tempContext;
572 if ( !evalContext )
573 {
574 // no context passed, so we create a default one
575 tempContext = std::make_unique<QgsExpressionContext>( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
576 evalContext = tempContext.get();
577 }
578
579 QgsFields fields = layer->fields();
580
581 // Cache unique values
582 QMap<int, QSet<QVariant>> uniqueValueCache;
583
584 auto checkUniqueValue = [&]( const int fieldIdx, const QVariant &value ) {
585 if ( !uniqueValueCache.contains( fieldIdx ) )
586 {
587 // If the layer is filtered, get unique values from an unfiltered clone
588 if ( !layer->subsetString().isEmpty() )
589 {
590 std::unique_ptr<QgsVectorLayer> unfilteredClone { layer->clone() };
591 unfilteredClone->setSubsetString( QString() );
592 uniqueValueCache[fieldIdx] = unfilteredClone->uniqueValues( fieldIdx );
593 }
594 else
595 {
596 uniqueValueCache[fieldIdx] = layer->uniqueValues( fieldIdx );
597 }
598 }
599 return uniqueValueCache[fieldIdx].contains( value );
600 };
601
602 for ( const auto &fd : std::as_const( featuresData ) )
603 {
604 QgsFeature newFeature( fields );
605 newFeature.setValid( true );
606 newFeature.setGeometry( fd.geometry() );
607
608 // initialize attributes
609 newFeature.initAttributes( fields.count() );
610 for ( int idx = 0; idx < fields.count(); ++idx )
611 {
612 QVariant v;
613 bool checkUnique = true;
614 const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
615
616 // in order of priority:
617 // 1. passed attribute value and if field does not have a unique constraint like primary key
618 if ( fd.attributes().contains( idx ) )
619 {
620 v = fd.attributes().value( idx );
621 }
622
623 // 2. client side default expression
624 // note - deliberately not using else if!
625 QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
626 if ( ( QgsVariantUtils::isNull( v ) || ( hasUniqueConstraint && checkUniqueValue( idx, v ) ) || defaultValueDefinition.applyOnUpdate() ) && defaultValueDefinition.isValid() )
627 {
628 // client side default expression set - takes precedence over all. Why? Well, this is the only default
629 // which QGIS users have control over, so we assume that they're deliberately overriding any
630 // provider defaults for some good reason and we should respect that
631 v = layer->defaultValue( idx, newFeature, evalContext );
632 }
633
634 // 3. provider side default value clause
635 // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
636 if ( ( QgsVariantUtils::isNull( v ) || ( hasUniqueConstraint && checkUniqueValue( idx, v ) ) ) && fields.fieldOrigin( idx ) == Qgis::FieldOrigin::Provider )
637 {
638 int providerIndex = fields.fieldOriginIndex( idx );
639 QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
640 if ( !providerDefault.isEmpty() )
641 {
642 v = QgsUnsetAttributeValue( providerDefault );
643 checkUnique = false;
644 }
645 }
646
647 // 4. provider side default literal
648 // note - deliberately not using else if!
649 if ( ( QgsVariantUtils::isNull( v ) || ( checkUnique && hasUniqueConstraint && checkUniqueValue( idx, v ) ) ) && fields.fieldOrigin( idx ) == Qgis::FieldOrigin::Provider )
650 {
651 int providerIndex = fields.fieldOriginIndex( idx );
652 v = layer->dataProvider()->defaultValue( providerIndex );
653 if ( v.isValid() )
654 {
655 //trust that the provider default has been sensibly set not to violate any constraints
656 checkUnique = false;
657 }
658 }
659
660 // 5. passed attribute value
661 // note - deliberately not using else if!
662 if ( QgsVariantUtils::isNull( v ) && fd.attributes().contains( idx ) )
663 {
664 v = fd.attributes().value( idx );
665 }
666
667 // last of all... check that unique constraints are respected if the value is valid
668 if ( v.isValid() )
669 {
670 // we can't handle not null or expression constraints here, since there's no way to pick a sensible
671 // value if the constraint is violated
672 if ( checkUnique && hasUniqueConstraint )
673 {
674 if ( checkUniqueValue( idx, v ) )
675 {
676 // unique constraint violated
677 QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCache[idx], v );
678 if ( uniqueValue.isValid() )
679 v = uniqueValue;
680 }
681 }
682 if ( hasUniqueConstraint )
683 {
684 uniqueValueCache[idx].insert( v );
685 }
686 }
687 newFeature.setAttribute( idx, v );
688 }
689 result.append( newFeature );
690 }
691 return result;
692}
693
695 QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth, int depth, QList<QgsVectorLayer *> referencedLayersBranch
696)
697{
698 if ( !layer )
699 return QgsFeature();
700
701 if ( !layer->isEditable() )
702 return QgsFeature();
703
704 //get context from layer
706 context.setFeature( feature );
707
708 //respect field duplicate policy
709 QgsAttributeMap attributeMap;
710 const int fieldCount = layer->fields().count();
711 for ( int fieldIdx = 0; fieldIdx < fieldCount; ++fieldIdx )
712 {
713 const QgsField field = layer->fields().at( fieldIdx );
714 switch ( field.duplicatePolicy() )
715 {
717 //do nothing - default values ​​are determined
718 break;
719
721 attributeMap.insert( fieldIdx, feature.attribute( fieldIdx ) );
722 break;
723
725 attributeMap.insert( fieldIdx, QgsUnsetAttributeValue() );
726 break;
727 }
728 }
729
730 QgsFeature newFeature = createFeature( layer, feature.geometry(), attributeMap, &context );
731 layer->addFeature( newFeature );
732
733 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
734 referencedLayersBranch << layer;
735
736 const int effectiveMaxDepth = maxDepth > 0 ? maxDepth : 100;
737
738 for ( const QgsRelation &relation : relations )
739 {
740 //check if composition (and not association)
741 if ( relation.strength() == Qgis::RelationshipStrength::Composition && !referencedLayersBranch.contains( relation.referencingLayer() ) && depth < effectiveMaxDepth )
742 {
743 //get features connected over this relation
744 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
745 QgsFeatureIds childFeatureIds;
746 QgsFeature childFeature;
747 while ( relatedFeaturesIt.nextFeature( childFeature ) )
748 {
749 //set childlayer editable
750 relation.referencingLayer()->startEditing();
751 //change the fk of the child to the id of the new parent
752 const auto pairs = relation.fieldPairs();
753 for ( const QgsRelation::FieldPair &fieldPair : pairs )
754 {
755 childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
756 }
757 //call the function for the child
758 childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, duplicateFeatureContext, maxDepth, depth + 1, referencedLayersBranch ).id() );
759 }
760
761 //store for feedback
762 duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
763 }
764 }
765
766
767 return newFeature;
768}
769
770std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
771{
772 std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
773
774 auto getFeatureSource = [layer = std::move( layer ), &featureSource, feedback] {
775 Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
776 QgsVectorLayer *lyr = layer.data();
777
778 if ( lyr )
779 {
780 featureSource = std::make_unique<QgsVectorLayerFeatureSource>( lyr );
781 }
782 };
783
785
786 return featureSource;
787}
788
790{
791 if ( !feature.fields().isEmpty() )
792 {
793 QgsAttributes attributes;
794 attributes.reserve( fields.size() );
795 // feature has a field mapping, so we can match attributes to field names
796 for ( const QgsField &field : fields )
797 {
798 int index = feature.fields().lookupField( field.name() );
799 attributes.append( index >= 0 ? feature.attribute( index ) : QgsVariantUtils::createNullVariant( field.type() ) );
800 }
801 feature.setAttributes( attributes );
802 }
803 else
804 {
805 // no field name mapping in feature, just use order
806 const int lengthDiff = feature.attributeCount() - fields.count();
807 if ( lengthDiff > 0 )
808 {
809 // truncate extra attributes
810 QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
811 feature.setAttributes( attributes );
812 }
813 else if ( lengthDiff < 0 )
814 {
815 // add missing null attributes
816 QgsAttributes attributes = feature.attributes();
817 attributes.reserve( fields.count() );
818 const int attributeCount = feature.attributeCount();
819 for ( int i = attributeCount; i < fields.count(); ++i )
820 {
821 attributes.append( QgsVariantUtils::createNullVariant( fields.at( i ).type() ) );
822 }
823 feature.setAttributes( attributes );
824 }
825 }
826 feature.setFields( fields );
827}
828
830{
831 Qgis::WkbType inputWkbType( layer->wkbType() );
832 QgsFeatureList resultFeatures;
833 QgsFeature newF( feature );
834 // Fix attributes
836
837 if ( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey )
838 {
839 // drop incoming primary key values, let them be regenerated
840 const QgsAttributeList pkIndexes = layer->dataProvider()->pkAttributeIndexes();
841 for ( int index : pkIndexes )
842 {
843 if ( index >= 0 )
844 newF.setAttribute( index, QVariant() );
845 }
846 }
847
848 // Does geometry need transformations?
850 bool newFHasGeom = newFGeomType != Qgis::GeometryType::Unknown && newFGeomType != Qgis::GeometryType::Null;
851 bool layerHasGeom = inputWkbType != Qgis::WkbType::NoGeometry && inputWkbType != Qgis::WkbType::Unknown;
852 // Drop geometry if layer is geometry-less
853 if ( ( newFHasGeom && !layerHasGeom ) || !newFHasGeom )
854 {
855 QgsFeature _f = QgsFeature( layer->fields() );
856 _f.setAttributes( newF.attributes() );
857 resultFeatures.append( _f );
858 }
859 else
860 {
861 // Geometry need fixing?
862 const QVector< QgsGeometry > geometries = newF.geometry().coerceToType( inputWkbType );
863
864 if ( geometries.count() != 1 )
865 {
866 QgsAttributeMap attrMap;
867 for ( int j = 0; j < newF.fields().count(); j++ )
868 {
869 attrMap[j] = newF.attribute( j );
870 }
871 resultFeatures.reserve( geometries.size() );
872 for ( const QgsGeometry &geometry : geometries )
873 {
874 QgsFeature _f( createFeature( layer, geometry, attrMap ) );
875 resultFeatures.append( _f );
876 }
877 }
878 else
879 {
880 newF.setGeometry( geometries.at( 0 ) );
881 resultFeatures.append( newF );
882 }
883 }
884 return resultFeatures;
885}
886
888{
889 QgsFeatureList resultFeatures;
890 for ( const QgsFeature &f : features )
891 {
892 const QgsFeatureList features( makeFeatureCompatible( f, layer, sinkFlags ) );
893 for ( const auto &_f : features )
894 {
895 resultFeatures.append( _f );
896 }
897 }
898 return resultFeatures;
899}
900
902{
903 QList<QgsVectorLayer *> layers;
904 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
905 for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
906 layers.append( i.key() );
907 return layers;
908}
909
911{
912 return mDuplicatedFeatures[layer];
913}
914
915void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
916{
917 if ( mDuplicatedFeatures.contains( layer ) )
918 mDuplicatedFeatures[layer] += ids;
919 else
920 mDuplicatedFeatures.insert( layer, ids );
921}
922/*
923QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
924{
925 return mDuplicatedFeatures;
926}
927*/
928
933
935{
936 return mGeometry;
937}
938
940{
941 return mAttributes;
942}
943
945{
947 !layer->editFormConfig().readOnly( fieldIndex ) &&
948 // Provider permissions
949 layer->dataProvider() &&
951 ( layer->dataProvider()->capabilities() & Qgis::VectorProviderCapability::AddFeatures && ( FID_IS_NULL( feature.id() ) || FID_IS_NEW( feature.id() ) ) ) ) &&
952 // Field must not be read only
953 !layer->fields().at( fieldIndex ).isReadOnly();
954}
955
956bool QgsVectorLayerUtils::fieldIsReadOnly( const QgsVectorLayer *layer, int fieldIndex )
957{
958 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
959 {
960 int srcFieldIndex;
961 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
962
963 if ( !info || !info->isEditable() || !info->joinLayer() )
964 return true;
965
966 return fieldIsReadOnly( info->joinLayer(), srcFieldIndex );
967 }
968 else
969 {
970 // any of these properties makes the field read only
971 if ( !layer->isEditable()
972 || layer->editFormConfig().readOnly( fieldIndex )
973 || !layer->dataProvider()
975 || layer->fields().at( fieldIndex ).isReadOnly() )
976 return true;
977
978 return false;
979 }
980}
981
983{
984 // editability will vary feature-by-feature only for joined fields
985 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
986 {
987 int srcFieldIndex;
988 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
989
990 if ( !info || !info->isEditable() || info->hasUpsertOnEdit() )
991 return false;
992
993 // join does not have upsert capabilities, so the ability to edit the joined field will
994 // vary feature-by-feature, depending on whether the join target feature already exists
995 return true;
996 }
997 else
998 {
999 return false;
1000 }
1001}
1002
1004{
1005 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
1006 {
1007 int srcFieldIndex;
1008 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
1009
1010 if ( !info || !info->isEditable() )
1011 return false;
1012
1013 // check that joined feature exist, else it is not editable
1014 if ( !info->hasUpsertOnEdit() )
1015 {
1016 const QgsFeature joinedFeature = layer->joinBuffer()->joinedFeatureOf( info, feature );
1017 if ( !joinedFeature.isValid() )
1018 return false;
1019 }
1020
1021 return fieldIsEditablePrivate( info->joinLayer(), srcFieldIndex, feature );
1022 }
1023
1024 return fieldIsEditablePrivate( layer, fieldIndex, feature, flags );
1025}
1026
1027
1029 const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector<QgsVectorLayer *> &allRenderedVectorLayers
1030)
1031{
1032 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
1033 {
1034 public:
1035 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
1036 {
1038 {
1039 currentLabelRuleId = node.identifier;
1040 return true;
1041 }
1042 return false;
1043 }
1044 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1045 {
1046 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
1047 {
1048 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
1049 const QgsTextMaskSettings &maskSettings = labelSettingsEntity->settings().format().mask();
1050 if ( maskSettings.enabled() )
1051 {
1052 // transparency is considered has effects because it implies rasterization when masking
1053 // is involved
1054 const bool hasEffects = maskSettings.opacity() < 1 || ( maskSettings.paintEffect() && maskSettings.paintEffect()->enabled() );
1055 for ( const QgsSymbolLayerReference &r : maskSettings.maskedSymbolLayers() )
1056 {
1057 QgsMaskedLayer &maskedLayer = maskedLayers[currentLabelRuleId][r.layerId()];
1058 maskedLayer.symbolLayerIdsToMask.insert( r.symbolLayerIdV2() );
1059 maskedLayer.hasEffects = hasEffects;
1060 }
1061 }
1062 }
1063 return true;
1064 }
1065
1066 QHash<QString, QgsMaskedLayers> maskedLayers;
1067 // Current label rule, empty string for a simple labeling
1068 QString currentLabelRuleId;
1069 };
1070
1071 LabelMasksVisitor visitor;
1072
1073 if ( layer->labeling() )
1074 {
1075 layer->labeling()->accept( &visitor );
1076 }
1077
1078 class LabelSelectiveMaskingSetVisitor : public QgsStyleEntityVisitorInterface
1079 {
1080 public:
1081 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1082
1083 bool visitSymbol( const QgsSymbol *symbol )
1084 {
1085 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1086 {
1087 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1088 if ( !sl->selectiveMaskingSourceSetId().isEmpty() )
1089 {
1090 auto it = selectiveMaskingSourceSets.constFind( sl->selectiveMaskingSourceSetId() );
1091 if ( it != selectiveMaskingSourceSets.constEnd() )
1092 {
1093 const QVector<QgsSelectiveMaskSource> maskingSources = it.value().sources();
1094 for ( const QgsSelectiveMaskSource &maskSource : maskingSources )
1095 {
1096 if ( maskSource.sourceType() == Qgis::SelectiveMaskSourceType::Label && maskSource.layerId() == maskingLayerId )
1097 {
1098 QgsMaskedLayer &maskedLayer = maskedLayers[maskSource.sourceId()][maskedLayerId];
1099 maskedLayer.symbolLayerIdsToMask.insert( sl->id() );
1100 }
1101 }
1102 }
1103 }
1104
1105 // recurse over sub symbols
1106 if ( const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol() )
1107 {
1108 visitSymbol( subSymbol );
1109 }
1110 }
1111
1112 return true;
1113 }
1114
1115 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1116 {
1117 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1118 {
1119 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1120 if ( symbolEntity->symbol() )
1121 visitSymbol( symbolEntity->symbol() );
1122 }
1123 return true;
1124 }
1125
1126 QHash<QString, QgsMaskedLayers> maskedLayers;
1127 QString maskingLayerId;
1128 QString maskedLayerId;
1129 QHash< QString, QgsSelectiveMaskingSourceSet > selectiveMaskingSourceSets;
1130 };
1131
1132 LabelSelectiveMaskingSetVisitor selectiveMaskingSetVisitor;
1133 selectiveMaskingSetVisitor.maskingLayerId = layer->id();
1134 selectiveMaskingSetVisitor.maskedLayers = std::move( visitor.maskedLayers );
1135 selectiveMaskingSetVisitor.selectiveMaskingSourceSets = selectiveMaskingSourceSets;
1136 for ( QgsVectorLayer *layer : allRenderedVectorLayers )
1137 {
1138 if ( layer->renderer() )
1139 {
1140 selectiveMaskingSetVisitor.maskedLayerId = layer->id();
1141 layer->renderer()->accept( &selectiveMaskingSetVisitor );
1142 }
1143 }
1144
1145 return std::move( selectiveMaskingSetVisitor.maskedLayers );
1146}
1147
1149 const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector<QgsVectorLayer *> &allRenderedVectorLayers
1150)
1151{
1152 if ( !layer->renderer() )
1153 return {};
1154
1155 class SymbolLayerVisitor : public QgsStyleEntityVisitorInterface
1156 {
1157 public:
1158 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1159
1160 // Returns true if the visited symbol has effects
1161 bool visitSymbol( const QgsSymbol *symbol )
1162 {
1163 // transparency is considered has effects because it implies rasterization when masking
1164 // is involved
1165 bool symbolHasEffect = symbol->opacity() < 1;
1166 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1167 {
1168 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1169 bool slHasEffects = sl->paintEffect() && sl->paintEffect()->enabled();
1170 symbolHasEffect |= slHasEffects;
1171
1172 // recurse over sub symbols
1173 const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
1174 if ( subSymbol )
1175 {
1176 slHasEffects = visitSymbol( subSymbol ) || slHasEffects;
1177 }
1178
1179 for ( const QgsSymbolLayerReference &thingToMask : sl->masks() )
1180 {
1181 QgsMaskedLayer &maskedLayer = maskedLayers[thingToMask.layerId()];
1182 maskedLayer.hasEffects |= slHasEffects;
1183 maskedLayer.symbolLayerIdsToMask.insert( thingToMask.symbolLayerIdV2() );
1184 }
1185 }
1186
1187 return symbolHasEffect;
1188 }
1189
1190 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1191 {
1192 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1193 {
1194 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1195 if ( symbolEntity->symbol() )
1196 visitSymbol( symbolEntity->symbol() );
1197 }
1198 return true;
1199 }
1200 QgsMaskedLayers maskedLayers;
1201 };
1202
1203 SymbolLayerVisitor visitor;
1204 layer->renderer()->accept( &visitor );
1205
1206
1207 class SymbolLayerSelectiveMaskingSetVisitor : public QgsStyleEntityVisitorInterface
1208 {
1209 public:
1210 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1211
1212 // Returns true if the visited symbol has effects
1213 bool visitSymbol( const QgsSymbol *symbol )
1214 {
1215 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1216 {
1217 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1218 if ( !sl->selectiveMaskingSourceSetId().isEmpty() )
1219 {
1220 auto it = selectiveMaskingSourceSets.constFind( sl->selectiveMaskingSourceSetId() );
1221 if ( it != selectiveMaskingSourceSets.constEnd() )
1222 {
1223 const QVector<QgsSelectiveMaskSource> maskingSources = it.value().sources();
1224 for ( const QgsSelectiveMaskSource &maskSource : maskingSources )
1225 {
1226 if ( maskSource.sourceType() == Qgis::SelectiveMaskSourceType::SymbolLayer && maskSource.layerId() == maskingLayerId )
1227 {
1228 QgsMaskedLayer &maskedLayer = maskedLayers[maskedLayerId];
1229 maskedLayer.symbolLayerIdsToMask.insert( sl->id() );
1230 }
1231 }
1232 }
1233 }
1234
1235 // recurse over sub symbols
1236 if ( const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol() )
1237 {
1238 visitSymbol( subSymbol );
1239 }
1240 }
1241
1242 return true;
1243 }
1244
1245 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1246 {
1247 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1248 {
1249 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1250 if ( symbolEntity->symbol() )
1251 visitSymbol( symbolEntity->symbol() );
1252 }
1253 return true;
1254 }
1255 QgsMaskedLayers maskedLayers;
1256 QString maskingLayerId;
1257 QString maskedLayerId;
1258 QHash< QString, QgsSelectiveMaskingSourceSet > selectiveMaskingSourceSets;
1259 };
1260
1261 SymbolLayerSelectiveMaskingSetVisitor selectiveMaskingSetVisitor;
1262 selectiveMaskingSetVisitor.maskingLayerId = layer->id();
1263 selectiveMaskingSetVisitor.maskedLayers = visitor.maskedLayers;
1264 selectiveMaskingSetVisitor.selectiveMaskingSourceSets = selectiveMaskingSourceSets;
1265 for ( QgsVectorLayer *layer : allRenderedVectorLayers )
1266 {
1267 if ( layer->renderer() )
1268 {
1269 selectiveMaskingSetVisitor.maskedLayerId = layer->id();
1270 layer->renderer()->accept( &selectiveMaskingSetVisitor );
1271 }
1272 }
1273
1274 return selectiveMaskingSetVisitor.maskedLayers;
1275}
1276
1278{
1280
1281 QgsExpression exp( layer->displayExpression() );
1282 context.setFeature( feature );
1283 exp.prepare( &context );
1284 QString displayString = exp.evaluate( &context ).toString();
1285
1286 return displayString;
1287}
1288
1290{
1291 if ( !layer )
1292 return false;
1293
1294 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
1295 for ( const QgsRelation &relation : relations )
1296 {
1297 switch ( relation.strength() )
1298 {
1300 {
1301 QgsFeatureIds childFeatureIds;
1302
1303 const auto constFids = fids;
1304 for ( const QgsFeatureId fid : constFids )
1305 {
1306 //get features connected over this relation
1307 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( layer->getFeature( fid ) );
1308 QgsFeature childFeature;
1309 while ( relatedFeaturesIt.nextFeature( childFeature ) )
1310 {
1311 childFeatureIds.insert( childFeature.id() );
1312 }
1313 }
1314
1315 if ( childFeatureIds.count() > 0 )
1316 {
1317 if ( context.layers().contains( relation.referencingLayer() ) )
1318 {
1319 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( relation.referencingLayer() );
1320 // add feature ids
1321 handledFeatureIds.unite( childFeatureIds );
1322 context.setDuplicatedFeatures( relation.referencingLayer(), handledFeatureIds );
1323 }
1324 else
1325 {
1326 // add layer and feature id
1327 context.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
1328 }
1329 }
1330 break;
1331 }
1332
1334 break;
1335 }
1336 }
1337
1338 if ( layer->joinBuffer()->containsJoins() )
1339 {
1340 const QgsVectorJoinList joins = layer->joinBuffer()->vectorJoins();
1341 for ( const QgsVectorLayerJoinInfo &info : joins )
1342 {
1343 if ( qobject_cast< QgsAuxiliaryLayer * >( info.joinLayer() ) && flags & IgnoreAuxiliaryLayers )
1344 continue;
1345
1346 if ( info.isEditable() && info.hasCascadedDelete() )
1347 {
1348 QgsFeatureIds joinFeatureIds;
1349 const auto constFids = fids;
1350 for ( const QgsFeatureId &fid : constFids )
1351 {
1352 const QgsFeature joinFeature = layer->joinBuffer()->joinedFeatureOf( &info, layer->getFeature( fid ) );
1353 if ( joinFeature.isValid() )
1354 joinFeatureIds.insert( joinFeature.id() );
1355 }
1356
1357 if ( joinFeatureIds.count() > 0 )
1358 {
1359 if ( context.layers().contains( info.joinLayer() ) )
1360 {
1361 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( info.joinLayer() );
1362 // add feature ids
1363 handledFeatureIds.unite( joinFeatureIds );
1364 context.setDuplicatedFeatures( info.joinLayer(), handledFeatureIds );
1365 }
1366 else
1367 {
1368 // add layer and feature id
1369 context.setDuplicatedFeatures( info.joinLayer(), joinFeatureIds );
1370 }
1371 }
1372 }
1373 }
1374 }
1375
1376 return !context.layers().isEmpty();
1377}
1378
1379QString QgsVectorLayerUtils::guessFriendlyIdentifierField( const QgsFields &fields, bool *foundFriendly )
1380{
1381 if ( foundFriendly )
1382 *foundFriendly = false;
1383
1384 if ( fields.isEmpty() )
1385 return QString();
1386
1387 // Check the fields and keep the first one that matches.
1388 // We assume that the user has organized the data with the
1389 // more "interesting" field names first. As such, name should
1390 // be selected before oldname, othername, etc.
1391 // This candidates list is a prioritized list of candidates ranked by "interestingness"!
1392 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
1393 // but adding hardcoded localized variants of the strings is encouraged.
1394 static QStringList sCandidates {
1395 u"name"_s,
1396 u"title"_s,
1397 u"heibt"_s,
1398 u"desc"_s,
1399 u"nom"_s,
1400 u"street"_s,
1401 u"road"_s,
1402 u"label"_s,
1403 // German candidates
1404 u"titel"_s, //#spellok
1405 u"beschreibung"_s,
1406 u"strasse"_s,
1407 u"beschriftung"_s
1408 };
1409
1410 // anti-names
1411 // this list of strings indicates parts of field names which make the name "less interesting".
1412 // For instance, we'd normally like to default to a field called "name" or "title", but if instead we
1413 // find one called "typename" or "typeid", then that's most likely a classification of the feature and not the
1414 // best choice to default to
1415 static QStringList sAntiCandidates {
1416 u"type"_s,
1417 u"class"_s,
1418 u"cat"_s,
1419 // German anti-candidates
1420 u"typ"_s,
1421 u"klasse"_s,
1422 u"kategorie"_s
1423 };
1424
1425 QString bestCandidateName;
1426 QString bestCandidateContainsName;
1427 QString bestCandidateContainsNameWithAntiCandidate;
1428
1429 for ( const QString &candidate : sCandidates )
1430 {
1431 for ( const QgsField &field : fields )
1432 {
1433 const QString fldName = field.name();
1434
1435 if ( fldName.compare( candidate, Qt::CaseInsensitive ) == 0 )
1436 {
1437 bestCandidateName = fldName;
1438 }
1439 else if ( fldName.contains( candidate, Qt::CaseInsensitive ) )
1440 {
1441 bool isAntiCandidate = false;
1442 for ( const QString &antiCandidate : sAntiCandidates )
1443 {
1444 if ( fldName.contains( antiCandidate, Qt::CaseInsensitive ) )
1445 {
1446 isAntiCandidate = true;
1447 break;
1448 }
1449 }
1450
1451 if ( isAntiCandidate )
1452 {
1453 if ( bestCandidateContainsNameWithAntiCandidate.isEmpty() )
1454 {
1455 bestCandidateContainsNameWithAntiCandidate = fldName;
1456 }
1457 }
1458 else
1459 {
1460 if ( bestCandidateContainsName.isEmpty() )
1461 {
1462 bestCandidateContainsName = fldName;
1463 }
1464 }
1465 }
1466 }
1467
1468 if ( !bestCandidateName.isEmpty() )
1469 break;
1470 }
1471
1472 QString candidateName = bestCandidateName;
1473 if ( candidateName.isEmpty() )
1474 {
1475 candidateName = bestCandidateContainsName.isEmpty() ? bestCandidateContainsNameWithAntiCandidate : bestCandidateContainsName;
1476 }
1477
1478 if ( !candidateName.isEmpty() )
1479 {
1480 // Special case for layers got from WFS using the OGR GMLAS field parsing logic.
1481 // Such layers contain a "id" field (the gml:id attribute of the object),
1482 // as well as a gml_name (a <gml:name>) element. However this gml:name is often
1483 // absent, partly because it is a property of the base class in GML schemas, and
1484 // that a lot of readers are not able to deduce its potential presence.
1485 // So try to look at another field whose name would end with _name
1486 // And fallback to using the "id" field that should always be filled.
1487 if ( candidateName == "gml_name"_L1 && fields.indexOf( "id"_L1 ) >= 0 )
1488 {
1489 candidateName.clear();
1490 // Try to find a field ending with "_name", which is not "gml_name"
1491 for ( const QgsField &field : std::as_const( fields ) )
1492 {
1493 const QString fldName = field.name();
1494 if ( fldName != "gml_name"_L1 && fldName.endsWith( "_name"_L1 ) )
1495 {
1496 candidateName = fldName;
1497 break;
1498 }
1499 }
1500 if ( candidateName.isEmpty() )
1501 {
1502 // Fallback to "id"
1503 candidateName = u"id"_s;
1504 }
1505 }
1506
1507 if ( foundFriendly )
1508 *foundFriendly = true;
1509 return candidateName;
1510 }
1511 else
1512 {
1513 // no good matches found by name, so scan through and look for the first string field
1514 for ( const QgsField &field : fields )
1515 {
1516 if ( field.type() == QMetaType::Type::QString )
1517 return field.name();
1518 }
1519
1520 // no string fields found - just return first field
1521 return fields.at( 0 ).name();
1522 }
1523}
1524
1525template<typename T, typename ConverterFunc> void populateFieldDataArray( const QVector<QVariant> &values, const QVariant &nullValue, QByteArray &res, ConverterFunc converter )
1526{
1527 res.resize( values.size() * sizeof( T ) );
1528 T *data = reinterpret_cast<T *>( res.data() );
1529 for ( const QVariant &val : values )
1530 {
1531 if ( QgsVariantUtils::isNull( val ) )
1532 {
1533 *data++ = converter( nullValue );
1534 }
1535 else
1536 {
1537 *data++ = converter( val );
1538 }
1539 }
1540}
1541
1542QByteArray QgsVectorLayerUtils::fieldToDataArray( const QgsFields &fields, const QString &fieldName, QgsFeatureIterator &it, const QVariant &nullValue )
1543{
1544 const int fieldIndex = fields.lookupField( fieldName );
1545 if ( fieldIndex < 0 )
1546 return QByteArray();
1547
1548 QVector< QVariant > values;
1549 QgsFeature f;
1550 while ( it.nextFeature( f ) )
1551 {
1552 values.append( f.attribute( fieldIndex ) );
1553 }
1554
1555 const QgsField field = fields.at( fieldIndex );
1556 QByteArray res;
1557 switch ( field.type() )
1558 {
1559 case QMetaType::Int:
1560 {
1561 populateFieldDataArray<int>( values, nullValue, res, []( const QVariant &v ) { return v.toInt(); } );
1562 break;
1563 }
1564
1565 case QMetaType::UInt:
1566 {
1567 populateFieldDataArray<unsigned int>( values, nullValue, res, []( const QVariant &v ) { return v.toUInt(); } );
1568 break;
1569 }
1570
1571 case QMetaType::LongLong:
1572 {
1573 populateFieldDataArray<long long>( values, nullValue, res, []( const QVariant &v ) { return v.toLongLong(); } );
1574 break;
1575 }
1576
1577 case QMetaType::ULongLong:
1578 {
1579 populateFieldDataArray<unsigned long long>( values, nullValue, res, []( const QVariant &v ) { return v.toULongLong(); } );
1580 break;
1581 }
1582
1583 case QMetaType::Double:
1584 {
1585 populateFieldDataArray<double>( values, nullValue, res, []( const QVariant &v ) { return v.toDouble(); } );
1586 break;
1587 }
1588
1589 case QMetaType::Long:
1590 {
1591 populateFieldDataArray<long>( values, nullValue, res, []( const QVariant &v ) { return v.toLongLong(); } );
1592 break;
1593 }
1594
1595 case QMetaType::Short:
1596 {
1597 populateFieldDataArray<short>( values, nullValue, res, []( const QVariant &v ) { return v.toInt(); } );
1598 break;
1599 }
1600
1601 case QMetaType::ULong:
1602 {
1603 populateFieldDataArray<unsigned long>( values, nullValue, res, []( const QVariant &v ) { return v.toULongLong(); } );
1604 break;
1605 }
1606
1607 case QMetaType::UShort:
1608 {
1609 populateFieldDataArray<unsigned short>( values, nullValue, res, []( const QVariant &v ) { return v.toUInt(); } );
1610 break;
1611 }
1612
1613 case QMetaType::Float:
1614 {
1615 populateFieldDataArray<float>( values, nullValue, res, []( const QVariant &v ) { return v.toFloat(); } );
1616 break;
1617 }
1618
1619 default:
1620 break;
1621 }
1622
1623 return res;
1624}
1625
1627{
1628 if ( !layer )
1629 return QgsFeatureIds();
1630
1631 if ( featureIds.isEmpty() )
1632 return QgsFeatureIds();
1633
1634 // build up an optimised feature request
1635 QgsFeatureRequest request;
1636 request.setFilterFids( featureIds );
1637 request.setNoAttributes();
1639
1640 QgsFeatureIds validIds;
1641 validIds.reserve( featureIds.size() );
1642
1643 QgsFeature feat;
1644 QgsFeatureIterator it = layer->getFeatures( request );
1645 while ( it.nextFeature( feat ) )
1646 {
1647 validIds.insert( feat.id() );
1648 }
1649
1650 return validIds;
1651}
@ AddFeatures
Allows adding features.
Definition qgis.h:527
@ ChangeAttributeValues
Allows modification of attribute values.
Definition qgis.h:529
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
Definition qgis.h:4551
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
Definition qgis.h:4550
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2276
@ NoFlags
No flags are set.
Definition qgis.h:2275
@ Label
A mask generated from a labeling provider.
Definition qgis.h:3170
@ SymbolLayer
A mask generated from a symbol layer.
Definition qgis.h:3169
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:379
@ Unknown
Unknown types.
Definition qgis.h:383
@ Null
No geometry.
Definition qgis.h:384
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
Definition qgis.h:4063
@ DefaultValue
Use default field value.
Definition qgis.h:4061
@ Duplicate
Duplicate original value.
Definition qgis.h:4062
@ Provider
Field originates from the underlying data provider of the vector layer.
Definition qgis.h:1785
@ Join
Field originates from a joined layer.
Definition qgis.h:1786
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ NoGeometry
No geometry.
Definition qgis.h:312
@ Unknown
Unknown.
Definition qgis.h:295
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
A vector of attributes.
Provides a container for managing client side default values for fields.
bool isValid() const
Returns if this default value should be applied.
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
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 setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
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.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString evalErrorString() const
Returns evaluation error.
QString parserErrorString() const
Returns parser error.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
QVariant evaluate()
Evaluate the feature and return the result.
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.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
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 & setLimit(long long limit)
Set the maximum number of features to request.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should 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 & setNoAttributes()
Set that no attributes will be fetched.
QFlags< SinkFlag > SinkFlags
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsAttributes attributes
Definition qgsfeature.h:69
QgsFields fields
Definition qgsfeature.h:70
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
QgsFeatureId id
Definition qgsfeature.h:68
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
int attributeCount() const
Returns the number of attributes attached to the feature.
QgsGeometry geometry
Definition qgsfeature.h:71
void setValid(bool validity)
Sets the validity of the feature.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
Stores information about constraints which may be present on a field.
ConstraintStrength
Strength of constraints.
@ ConstraintStrengthNotSet
Constraint is not set.
ConstraintOrigin
Origin of constraints.
@ ConstraintOriginNotSet
Constraint is not set.
@ ConstraintOriginProvider
Constraint was set at data provider.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QMetaType::Type type
Definition qgsfield.h:63
QString name
Definition qgsfield.h:65
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition qgsfield.cpp:470
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:764
bool isNumeric
Definition qgsfield.h:59
QgsFieldConstraints constraints
Definition qgsfield.h:68
bool isReadOnly
Definition qgsfield.h:70
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
bool isEmpty
Definition qgsfields.h:49
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
QVector< QgsGeometry > coerceToType(Qgis::WkbType type, double defaultZ=0, double defaultM=0, bool avoidDuplicates=true) const
Attempts to coerce this geometry into the specified destination type.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
QString id
Definition qgsmaplayer.h:86
bool enabled() const
Returns whether the effect is enabled.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
QgsRelationManager * relationManager
Definition qgsproject.h:124
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Defines a relation between matching fields of the two involved tables of a relation.
Definition qgsrelation.h:71
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
Encapsulates a single source for selective masking (e.g.
virtual QgsStyle::StyleEntity type() const =0
Returns the type of style entity.
An interface for classes which can visit style entity (e.g.
@ SymbolRule
Rule based symbology or label child rule.
A label settings entity for QgsStyle databases.
Definition qgsstyle.h:1478
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1393
@ LabelSettingsEntity
Label settings.
Definition qgsstyle.h:210
@ SymbolEntity
Symbols.
Definition qgsstyle.h:205
Type used to refer to a specific symbol layer in a symbol of a layer.
Abstract base class for symbol layers.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
QString selectiveMaskingSourceSetId() const
Returns the selective masking source set ID for this symbol layer.
QString id() const
Returns symbol layer identifier This id is unique in the whole project.
virtual QList< QgsSymbolLayerReference > masks() const
Returns masks defined by this symbol layer.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:227
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
qreal opacity() const
Returns the opacity for the symbol.
Definition qgssymbol.h:677
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition qgssymbol.h:357
Container for settings relating to a selective masking around a text.
QList< QgsSymbolLayerReference > maskedSymbolLayers() const
Returns a list of references to symbol layers that are masked by this buffer.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the mask.
double opacity() const
Returns the mask's opacity.
bool enabled() const
Returns whether the mask is enabled.
static bool runOnMainThread(const Func &func, QgsFeedback *feedback=nullptr)
Guarantees that func is executed on the main thread.
Represents a default, "not-specified" value for a feature attribute.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
static bool isUnsetAttributeValue(const QVariant &variant)
Check if the variant is a QgsUnsetAttributeValue.
virtual Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
virtual QString defaultValueClause(int fieldIndex) const
Returns any default value clauses which are present at the provider for a specified field index.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index.
virtual bool skipConstraintCheck(int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value=QVariant()) const
Returns true if a constraint check should be skipped for a specified field (e.g., if the value return...
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool containsJoins() const
Quick way to test if there is any join at all.
QgsFeature joinedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const
Returns the joined feature corresponding to the feature.
const QgsVectorJoinList & vectorJoins() const
Defines left outer join from our vector layer to some other vector layer.
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet).
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds which list all the duplicated features...
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
QgsGeometry geometry() const
Returns geometry.
QgsAttributeMap attributes() const
Returns attributes.
QgsFeatureData(const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap())
Constructs a new QgsFeatureData with given geometry and attributes.
static QByteArray fieldToDataArray(const QgsFields &fields, const QString &fieldName, QgsFeatureIterator &it, const QVariant &nullValue)
Converts field values from an iterator to an array of data.
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth=0, int depth=0, QList< QgsVectorLayer * > referencedLayersBranch=QList< QgsVectorLayer * >())
Duplicates a feature and it's children (one level deep).
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
static QgsMaskedLayers collectObjectsMaskedBySymbolLayersFromLayer(const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector< QgsVectorLayer * > &allRenderedVectorLayers)
Returns all objects that will be masked by the symbol layers for a given vector layer.
static bool valueExists(const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds=QgsFeatureIds())
Returns true if the specified value already exists within a field.
static QgsFeatureList makeFeatureCompatible(const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags())
Converts input feature to be compatible with the given layer.
static QString guessFriendlyIdentifierField(const QgsFields &fields, bool *foundFriendly=nullptr)
Given a set of fields, attempts to pick the "most useful" field for user-friendly identification of f...
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature, QgsVectorLayerUtils::FieldIsEditableFlags flags=QgsVectorLayerUtils::FieldIsEditableFlags())
Tests whether a field is editable for a particular feature.
static QList< QVariant > uniqueValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, int limit=-1, QgsFeedback *feedback=nullptr)
Fetches all unique values from a specified field name or expression.
static QgsFeatureIterator getValuesIterator(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly)
Create a feature iterator for a specified field name or expression.
static bool fieldEditabilityDependsOnFeature(const QgsVectorLayer *layer, int fieldIndex)
Returns true if the editability of the field at index fieldIndex from layer may vary feature by featu...
static QgsFeatureList makeFeaturesCompatible(const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags())
Converts input features to be compatible with the given layer.
static QHash< QString, QgsMaskedLayers > collectObjectsMaskedByLabelsFromLayer(const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector< QgsVectorLayer * > &allRenderedVectorLayers)
Returns all objects that will be masked by the labels for a given vector layer.
static std::unique_ptr< QgsVectorLayerFeatureSource > getFeatureSource(QPointer< QgsVectorLayer > layer, QgsFeedback *feedback=nullptr)
Gets the feature source from a QgsVectorLayer pointer.
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
Returns a descriptive string for a feature, suitable for displaying to the user.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
QFlags< FieldIsEditableFlag > FieldIsEditableFlags
static bool attributeHasConstraints(const QgsVectorLayer *layer, int attributeIndex)
Returns true if a feature attribute has active constraints.
static QList< double > getDoubleValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, int *nullCount=nullptr, QgsFeedback *feedback=nullptr)
Fetches all double values from a specified field name or expression.
@ IgnoreLayerEditability
Ignores the vector layer's editable state.
QFlags< CascadedFeatureFlag > CascadedFeatureFlags
static bool fieldIsReadOnly(const QgsVectorLayer *layer, int fieldIndex)
Returns true if the field at index fieldIndex from layer is editable, false if the field is read only...
static QgsFeatureIds filterValidFeatureIds(const QgsVectorLayer *layer, const QgsFeatureIds &featureIds)
Filters a set of feature IDs to only include those that exist in the layer.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
static QVariant createUniqueValue(const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed=QVariant())
Returns a new attribute value for the specified field index which is guaranteed to be unique.
static bool impactsCascadeFeatures(const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context, QgsVectorLayerUtils::CascadedFeatureFlags flags=QgsVectorLayerUtils::CascadedFeatureFlags())
Returns true if at least one feature of the fids on layer is connected as parent in at least one comp...
static QList< QVariant > getValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, QgsFeedback *feedback=nullptr)
Fetches all values from a specified field name or expression.
static QVariant createUniqueValueFromCache(const QgsVectorLayer *layer, int fieldIndex, const QSet< QVariant > &existingValues, const QVariant &seed=QVariant())
Returns a new attribute value for the specified field index which is guaranteed to be unique within r...
static bool validateAttribute(const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthNotSet, QgsFieldConstraints::ConstraintOrigin origin=QgsFieldConstraints::ConstraintOriginNotSet)
Tests a feature attribute value to check whether it passes all constraints which are present on the c...
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
@ IgnoreAuxiliaryLayers
Ignore auxiliary layers.
Represents a vector layer which manages a vector based dataset.
bool isEditable() const final
Returns true if the provider is in editing mode.
QVariant maximumValue(int index) const final
Returns the maximum value for an attribute column or an invalid variant in case of error.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
QString displayExpression
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
QgsEditFormConfig editFormConfig
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const final
Calculates a list of unique values contained within an attribute in the layer.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) final
Adds a single feature to the sink.
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
#define FID_IS_NULL(fid)
QSet< QgsFeatureId > QgsFeatureIds
#define FID_IS_NEW(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:30
QList< QgsVectorLayerJoinInfo > QgsVectorJoinList
bool fieldIsEditablePrivate(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature, QgsVectorLayerUtils::FieldIsEditableFlags flags=QgsVectorLayerUtils::FieldIsEditableFlags())
void populateFieldDataArray(const QVector< QVariant > &values, const QVariant &nullValue, QByteArray &res, ConverterFunc converter)
QHash< QString, QgsMaskedLayer > QgsMaskedLayers
masked layers where key is the layer id of the layer that WILL be masked
QSet< QString > symbolLayerIdsToMask
Contains information relating to a node (i.e.
QString identifier
A string identifying the node.
QgsStyleEntityVisitorInterface::NodeType type
Node type.
Contains information relating to the style entity currently being visited.
const QgsStyleEntityInterface * entity
Reference to style entity being visited.