QGIS API Documentation 4.3.0-Master (bf28115e945)
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
611 // Avoid endless looping for recursive expression dependencies by keeping track of fields already deferred
612 QList<int> deferredFieldIndexes;
613 QList<int> fieldIndexes( fields.count() );
614 std::iota( fieldIndexes.begin(), fieldIndexes.end(), 0 );
615 while ( !fieldIndexes.isEmpty() )
616 {
617 const int idx = fieldIndexes.takeFirst();
618
619 QVariant v;
620 bool checkUnique = true;
621 const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
622
623 // in order of priority:
624 // 1. passed attribute value and if field does not have a unique constraint like primary key
625 if ( fd.attributes().contains( idx ) )
626 {
627 v = fd.attributes().value( idx );
628 }
629
630 // 2. client side default expression
631 // note - deliberately not using else if!
632 QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
633 if ( ( QgsVariantUtils::isNull( v ) || ( hasUniqueConstraint && checkUniqueValue( idx, v ) ) || defaultValueDefinition.applyOnUpdate() ) && defaultValueDefinition.isValid() )
634 {
635 QgsExpression defaultValueExpression( defaultValueDefinition.expression() );
636 if ( defaultValueExpression.referencedColumns().isEmpty() || deferredFieldIndexes.contains( idx ) )
637 {
638 // client side default expression set - takes precedence over all. Why? Well, this is the only default
639 // which QGIS users have control over, so we assume that they're deliberately overriding any
640 // provider defaults for some good reason and we should respect that
641 v = layer->defaultValue( idx, newFeature, evalContext );
642 }
643 else
644 {
645 // the default value relies on order field(s) value, defer until the end
646 deferredFieldIndexes << idx;
647 fieldIndexes << idx;
648 continue;
649 }
650 }
651
652 // 3. provider side default value clause
653 // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
654 if ( ( QgsVariantUtils::isNull( v ) || ( hasUniqueConstraint && checkUniqueValue( idx, v ) ) ) && fields.fieldOrigin( idx ) == Qgis::FieldOrigin::Provider )
655 {
656 int providerIndex = fields.fieldOriginIndex( idx );
657 QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
658 if ( !providerDefault.isEmpty() )
659 {
660 v = QgsUnsetAttributeValue( providerDefault );
661 checkUnique = false;
662 }
663 }
664
665 // 4. provider side default literal
666 // note - deliberately not using else if!
667 if ( ( QgsVariantUtils::isNull( v ) || ( checkUnique && hasUniqueConstraint && checkUniqueValue( idx, v ) ) ) && fields.fieldOrigin( idx ) == Qgis::FieldOrigin::Provider )
668 {
669 int providerIndex = fields.fieldOriginIndex( idx );
670 v = layer->dataProvider()->defaultValue( providerIndex );
671 if ( v.isValid() )
672 {
673 //trust that the provider default has been sensibly set not to violate any constraints
674 checkUnique = false;
675 }
676 }
677
678 // 5. passed attribute value
679 // note - deliberately not using else if!
680 if ( QgsVariantUtils::isNull( v ) && fd.attributes().contains( idx ) )
681 {
682 v = fd.attributes().value( idx );
683 }
684
685 // last of all... check that unique constraints are respected if the value is valid
686 if ( v.isValid() )
687 {
688 // we can't handle not null or expression constraints here, since there's no way to pick a sensible
689 // value if the constraint is violated
690 if ( checkUnique && hasUniqueConstraint )
691 {
692 if ( checkUniqueValue( idx, v ) )
693 {
694 // unique constraint violated
695 QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCache[idx], v );
696 if ( uniqueValue.isValid() )
697 v = uniqueValue;
698 }
699 }
700 if ( hasUniqueConstraint )
701 {
702 uniqueValueCache[idx].insert( v );
703 }
704 }
705 newFeature.setAttribute( idx, v );
706 }
707 result.append( newFeature );
708 }
709 return result;
710}
711
713 QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth, int depth, QList<QgsVectorLayer *> referencedLayersBranch
714)
715{
716 if ( !layer )
717 return QgsFeature();
718
719 if ( !layer->isEditable() )
720 return QgsFeature();
721
722 //get context from layer
724 context.setFeature( feature );
725
726 //respect field duplicate policy
727 QgsAttributeMap attributeMap;
728 const int fieldCount = layer->fields().count();
729 for ( int fieldIdx = 0; fieldIdx < fieldCount; ++fieldIdx )
730 {
731 const QgsField field = layer->fields().at( fieldIdx );
732 switch ( field.duplicatePolicy() )
733 {
735 //do nothing - default values ​​are determined
736 break;
737
739 attributeMap.insert( fieldIdx, feature.attribute( fieldIdx ) );
740 break;
741
743 attributeMap.insert( fieldIdx, QgsUnsetAttributeValue() );
744 break;
745 }
746 }
747
748 QgsFeature newFeature = createFeature( layer, feature.geometry(), attributeMap, &context );
749 layer->addFeature( newFeature );
750
751 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
752 referencedLayersBranch << layer;
753
754 const int effectiveMaxDepth = maxDepth > 0 ? maxDepth : 100;
755
756 for ( const QgsRelation &relation : relations )
757 {
758 //check if composition (and not association)
759 if ( relation.strength() == Qgis::RelationshipStrength::Composition && !referencedLayersBranch.contains( relation.referencingLayer() ) && depth < effectiveMaxDepth )
760 {
761 //get features connected over this relation
762 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
763 QgsFeatureIds childFeatureIds;
764 QgsFeature childFeature;
765 while ( relatedFeaturesIt.nextFeature( childFeature ) )
766 {
767 //set childlayer editable
768 relation.referencingLayer()->startEditing();
769 //change the fk of the child to the id of the new parent
770 const auto pairs = relation.fieldPairs();
771 for ( const QgsRelation::FieldPair &fieldPair : pairs )
772 {
773 childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
774 }
775 //call the function for the child
776 childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, duplicateFeatureContext, maxDepth, depth + 1, referencedLayersBranch ).id() );
777 }
778
779 //store for feedback
780 duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
781 }
782 }
783
784
785 return newFeature;
786}
787
788std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
789{
790 std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
791
792 auto getFeatureSource = [layer = std::move( layer ), &featureSource, feedback] {
793 Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
794 QgsVectorLayer *lyr = layer.data();
795
796 if ( lyr )
797 {
798 featureSource = std::make_unique<QgsVectorLayerFeatureSource>( lyr );
799 }
800 };
801
803
804 return featureSource;
805}
806
808{
809 if ( !feature.fields().isEmpty() )
810 {
811 QgsAttributes attributes;
812 attributes.reserve( fields.size() );
813 // feature has a field mapping, so we can match attributes to field names
814 for ( const QgsField &field : fields )
815 {
816 int index = feature.fields().lookupField( field.name() );
817 attributes.append( index >= 0 ? feature.attribute( index ) : QgsVariantUtils::createNullVariant( field.type() ) );
818 }
819 feature.setAttributes( attributes );
820 }
821 else
822 {
823 // no field name mapping in feature, just use order
824 const int lengthDiff = feature.attributeCount() - fields.count();
825 if ( lengthDiff > 0 )
826 {
827 // truncate extra attributes
828 QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
829 feature.setAttributes( attributes );
830 }
831 else if ( lengthDiff < 0 )
832 {
833 // add missing null attributes
834 QgsAttributes attributes = feature.attributes();
835 attributes.reserve( fields.count() );
836 const int attributeCount = feature.attributeCount();
837 for ( int i = attributeCount; i < fields.count(); ++i )
838 {
839 attributes.append( QgsVariantUtils::createNullVariant( fields.at( i ).type() ) );
840 }
841 feature.setAttributes( attributes );
842 }
843 }
844 feature.setFields( fields );
845}
846
848{
849 Qgis::WkbType inputWkbType( layer->wkbType() );
850 QgsFeatureList resultFeatures;
851 QgsFeature newF( feature );
852 // Fix attributes
854
855 if ( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey )
856 {
857 // drop incoming primary key values, let them be regenerated
858 const QgsAttributeList pkIndexes = layer->dataProvider()->pkAttributeIndexes();
859 for ( int index : pkIndexes )
860 {
861 if ( index >= 0 )
862 newF.setAttribute( index, QVariant() );
863 }
864 }
865
866 // Does geometry need transformations?
868 bool newFHasGeom = newFGeomType != Qgis::GeometryType::Unknown && newFGeomType != Qgis::GeometryType::Null;
869 bool layerHasGeom = inputWkbType != Qgis::WkbType::NoGeometry && inputWkbType != Qgis::WkbType::Unknown;
870 // Drop geometry if layer is geometry-less
871 if ( ( newFHasGeom && !layerHasGeom ) || !newFHasGeom )
872 {
873 QgsFeature _f = QgsFeature( layer->fields() );
874 _f.setAttributes( newF.attributes() );
875 resultFeatures.append( _f );
876 }
877 else
878 {
879 // Geometry need fixing?
880 const QVector< QgsGeometry > geometries = newF.geometry().coerceToType( inputWkbType );
881
882 if ( geometries.count() != 1 )
883 {
884 QgsAttributeMap attrMap;
885 for ( int j = 0; j < newF.fields().count(); j++ )
886 {
887 attrMap[j] = newF.attribute( j );
888 }
889 resultFeatures.reserve( geometries.size() );
890 for ( const QgsGeometry &geometry : geometries )
891 {
892 QgsFeature _f( createFeature( layer, geometry, attrMap ) );
893 resultFeatures.append( _f );
894 }
895 }
896 else
897 {
898 newF.setGeometry( geometries.at( 0 ) );
899 resultFeatures.append( newF );
900 }
901 }
902 return resultFeatures;
903}
904
906{
907 QgsFeatureList resultFeatures;
908 for ( const QgsFeature &f : features )
909 {
910 const QgsFeatureList features( makeFeatureCompatible( f, layer, sinkFlags ) );
911 for ( const auto &_f : features )
912 {
913 resultFeatures.append( _f );
914 }
915 }
916 return resultFeatures;
917}
918
920{
921 QList<QgsVectorLayer *> layers;
922 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
923 for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
924 layers.append( i.key() );
925 return layers;
926}
927
929{
930 return mDuplicatedFeatures[layer];
931}
932
933void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
934{
935 if ( mDuplicatedFeatures.contains( layer ) )
936 mDuplicatedFeatures[layer] += ids;
937 else
938 mDuplicatedFeatures.insert( layer, ids );
939}
940/*
941QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
942{
943 return mDuplicatedFeatures;
944}
945*/
946
951
953{
954 return mGeometry;
955}
956
958{
959 return mAttributes;
960}
961
963{
965 !layer->editFormConfig().readOnly( fieldIndex ) &&
966 // Provider permissions
967 layer->dataProvider() &&
969 ( layer->dataProvider()->capabilities() & Qgis::VectorProviderCapability::AddFeatures && ( FID_IS_NULL( feature.id() ) || FID_IS_NEW( feature.id() ) ) ) ) &&
970 // Field must not be read only
971 !layer->fields().at( fieldIndex ).isReadOnly();
972}
973
974bool QgsVectorLayerUtils::fieldIsReadOnly( const QgsVectorLayer *layer, int fieldIndex )
975{
976 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
977 {
978 int srcFieldIndex;
979 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
980
981 if ( !info || !info->isEditable() || !info->joinLayer() )
982 return true;
983
984 return fieldIsReadOnly( info->joinLayer(), srcFieldIndex );
985 }
986 else
987 {
988 // any of these properties makes the field read only
989 if ( !layer->isEditable()
990 || layer->editFormConfig().readOnly( fieldIndex )
991 || !layer->dataProvider()
993 || layer->fields().at( fieldIndex ).isReadOnly() )
994 return true;
995
996 return false;
997 }
998}
999
1001{
1002 // editability will vary feature-by-feature only for joined fields
1003 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
1004 {
1005 int srcFieldIndex;
1006 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
1007
1008 if ( !info || !info->isEditable() || info->hasUpsertOnEdit() )
1009 return false;
1010
1011 // join does not have upsert capabilities, so the ability to edit the joined field will
1012 // vary feature-by-feature, depending on whether the join target feature already exists
1013 return true;
1014 }
1015 else
1016 {
1017 return false;
1018 }
1019}
1020
1022{
1023 if ( layer->fields().fieldOrigin( fieldIndex ) == Qgis::FieldOrigin::Join )
1024 {
1025 int srcFieldIndex;
1026 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
1027
1028 if ( !info || !info->isEditable() )
1029 return false;
1030
1031 // check that joined feature exist, else it is not editable
1032 if ( !info->hasUpsertOnEdit() )
1033 {
1034 const QgsFeature joinedFeature = layer->joinBuffer()->joinedFeatureOf( info, feature );
1035 if ( !joinedFeature.isValid() )
1036 return false;
1037 }
1038
1039 return fieldIsEditablePrivate( info->joinLayer(), srcFieldIndex, feature );
1040 }
1041
1042 return fieldIsEditablePrivate( layer, fieldIndex, feature, flags );
1043}
1044
1045
1047 const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector<QgsVectorLayer *> &allRenderedVectorLayers
1048)
1049{
1050 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
1051 {
1052 public:
1053 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
1054 {
1056 {
1057 currentLabelRuleId = node.identifier;
1058 return true;
1059 }
1060 return false;
1061 }
1062 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1063 {
1064 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
1065 {
1066 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
1067 const QgsTextMaskSettings &maskSettings = labelSettingsEntity->settings().format().mask();
1068 if ( maskSettings.enabled() )
1069 {
1070 // transparency is considered has effects because it implies rasterization when masking
1071 // is involved
1072 const bool hasEffects = maskSettings.opacity() < 1 || ( maskSettings.paintEffect() && maskSettings.paintEffect()->enabled() );
1073 for ( const QgsSymbolLayerReference &r : maskSettings.maskedSymbolLayers() )
1074 {
1075 QgsMaskedLayer &maskedLayer = maskedLayers[currentLabelRuleId][r.layerId()];
1076 maskedLayer.symbolLayerIdsToMask.insert( r.symbolLayerIdV2() );
1077 maskedLayer.hasEffects = hasEffects;
1078 }
1079 }
1080 }
1081 return true;
1082 }
1083
1084 QHash<QString, QgsMaskedLayers> maskedLayers;
1085 // Current label rule, empty string for a simple labeling
1086 QString currentLabelRuleId;
1087 };
1088
1089 LabelMasksVisitor visitor;
1090
1091 if ( layer->labeling() )
1092 {
1093 layer->labeling()->accept( &visitor );
1094 }
1095
1096 class LabelSelectiveMaskingSetVisitor : public QgsStyleEntityVisitorInterface
1097 {
1098 public:
1099 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1100
1101 bool visitSymbol( const QgsSymbol *symbol )
1102 {
1103 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1104 {
1105 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1106 if ( !sl->selectiveMaskingSourceSetId().isEmpty() )
1107 {
1108 auto it = selectiveMaskingSourceSets.constFind( sl->selectiveMaskingSourceSetId() );
1109 if ( it != selectiveMaskingSourceSets.constEnd() )
1110 {
1111 const QVector<QgsSelectiveMaskSource> maskingSources = it.value().sources();
1112 for ( const QgsSelectiveMaskSource &maskSource : maskingSources )
1113 {
1114 if ( maskSource.sourceType() == Qgis::SelectiveMaskSourceType::Label && maskSource.layerId() == maskingLayerId )
1115 {
1116 QgsMaskedLayer &maskedLayer = maskedLayers[maskSource.sourceId()][maskedLayerId];
1117 maskedLayer.symbolLayerIdsToMask.insert( sl->id() );
1118 }
1119 }
1120 }
1121 }
1122
1123 // recurse over sub symbols
1124 if ( const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol() )
1125 {
1126 visitSymbol( subSymbol );
1127 }
1128 }
1129
1130 return true;
1131 }
1132
1133 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1134 {
1135 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1136 {
1137 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1138 if ( symbolEntity->symbol() )
1139 visitSymbol( symbolEntity->symbol() );
1140 }
1141 return true;
1142 }
1143
1144 QHash<QString, QgsMaskedLayers> maskedLayers;
1145 QString maskingLayerId;
1146 QString maskedLayerId;
1147 QHash< QString, QgsSelectiveMaskingSourceSet > selectiveMaskingSourceSets;
1148 };
1149
1150 LabelSelectiveMaskingSetVisitor selectiveMaskingSetVisitor;
1151 selectiveMaskingSetVisitor.maskingLayerId = layer->id();
1152 selectiveMaskingSetVisitor.maskedLayers = std::move( visitor.maskedLayers );
1153 selectiveMaskingSetVisitor.selectiveMaskingSourceSets = selectiveMaskingSourceSets;
1154 for ( QgsVectorLayer *layer : allRenderedVectorLayers )
1155 {
1156 if ( layer->renderer() )
1157 {
1158 selectiveMaskingSetVisitor.maskedLayerId = layer->id();
1159 layer->renderer()->accept( &selectiveMaskingSetVisitor );
1160 }
1161 }
1162
1163 return std::move( selectiveMaskingSetVisitor.maskedLayers );
1164}
1165
1167 const QgsVectorLayer *layer, const QHash< QString, QgsSelectiveMaskingSourceSet > &selectiveMaskingSourceSets, const QVector<QgsVectorLayer *> &allRenderedVectorLayers
1168)
1169{
1170 if ( !layer->renderer() )
1171 return {};
1172
1173 class SymbolLayerVisitor : public QgsStyleEntityVisitorInterface
1174 {
1175 public:
1176 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1177
1178 // Returns true if the visited symbol has effects
1179 bool visitSymbol( const QgsSymbol *symbol )
1180 {
1181 // transparency is considered has effects because it implies rasterization when masking
1182 // is involved
1183 bool symbolHasEffect = symbol->opacity() < 1;
1184 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1185 {
1186 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1187 bool slHasEffects = sl->paintEffect() && sl->paintEffect()->enabled();
1188 symbolHasEffect |= slHasEffects;
1189
1190 // recurse over sub symbols
1191 const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
1192 if ( subSymbol )
1193 {
1194 slHasEffects = visitSymbol( subSymbol ) || slHasEffects;
1195 }
1196
1197 for ( const QgsSymbolLayerReference &thingToMask : sl->masks() )
1198 {
1199 QgsMaskedLayer &maskedLayer = maskedLayers[thingToMask.layerId()];
1200 maskedLayer.hasEffects |= slHasEffects;
1201 maskedLayer.symbolLayerIdsToMask.insert( thingToMask.symbolLayerIdV2() );
1202 }
1203 }
1204
1205 return symbolHasEffect;
1206 }
1207
1208 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1209 {
1210 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1211 {
1212 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1213 if ( symbolEntity->symbol() )
1214 visitSymbol( symbolEntity->symbol() );
1215 }
1216 return true;
1217 }
1218 QgsMaskedLayers maskedLayers;
1219 };
1220
1221 SymbolLayerVisitor visitor;
1222 layer->renderer()->accept( &visitor );
1223
1224
1225 class SymbolLayerSelectiveMaskingSetVisitor : public QgsStyleEntityVisitorInterface
1226 {
1227 public:
1228 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override { return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule ); }
1229
1230 // Returns true if the visited symbol has effects
1231 bool visitSymbol( const QgsSymbol *symbol )
1232 {
1233 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1234 {
1235 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1236 if ( !sl->selectiveMaskingSourceSetId().isEmpty() )
1237 {
1238 auto it = selectiveMaskingSourceSets.constFind( sl->selectiveMaskingSourceSetId() );
1239 if ( it != selectiveMaskingSourceSets.constEnd() )
1240 {
1241 const QVector<QgsSelectiveMaskSource> maskingSources = it.value().sources();
1242 for ( const QgsSelectiveMaskSource &maskSource : maskingSources )
1243 {
1244 if ( maskSource.sourceType() == Qgis::SelectiveMaskSourceType::SymbolLayer && maskSource.layerId() == maskingLayerId )
1245 {
1246 QgsMaskedLayer &maskedLayer = maskedLayers[maskedLayerId];
1247 maskedLayer.symbolLayerIdsToMask.insert( sl->id() );
1248 }
1249 }
1250 }
1251 }
1252
1253 // recurse over sub symbols
1254 if ( const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol() )
1255 {
1256 visitSymbol( subSymbol );
1257 }
1258 }
1259
1260 return true;
1261 }
1262
1263 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1264 {
1265 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1266 {
1267 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1268 if ( symbolEntity->symbol() )
1269 visitSymbol( symbolEntity->symbol() );
1270 }
1271 return true;
1272 }
1273 QgsMaskedLayers maskedLayers;
1274 QString maskingLayerId;
1275 QString maskedLayerId;
1276 QHash< QString, QgsSelectiveMaskingSourceSet > selectiveMaskingSourceSets;
1277 };
1278
1279 SymbolLayerSelectiveMaskingSetVisitor selectiveMaskingSetVisitor;
1280 selectiveMaskingSetVisitor.maskingLayerId = layer->id();
1281 selectiveMaskingSetVisitor.maskedLayers = visitor.maskedLayers;
1282 selectiveMaskingSetVisitor.selectiveMaskingSourceSets = selectiveMaskingSourceSets;
1283 for ( QgsVectorLayer *layer : allRenderedVectorLayers )
1284 {
1285 if ( layer->renderer() )
1286 {
1287 selectiveMaskingSetVisitor.maskedLayerId = layer->id();
1288 layer->renderer()->accept( &selectiveMaskingSetVisitor );
1289 }
1290 }
1291
1292 return selectiveMaskingSetVisitor.maskedLayers;
1293}
1294
1296{
1298
1299 QgsExpression exp( layer->displayExpression() );
1300 context.setFeature( feature );
1301 exp.prepare( &context );
1302 QString displayString = exp.evaluate( &context ).toString();
1303
1304 return displayString;
1305}
1306
1308{
1309 if ( !layer )
1310 return false;
1311
1312 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
1313 for ( const QgsRelation &relation : relations )
1314 {
1315 switch ( relation.strength() )
1316 {
1318 {
1319 QgsFeatureIds childFeatureIds;
1320
1321 const auto constFids = fids;
1322 for ( const QgsFeatureId fid : constFids )
1323 {
1324 //get features connected over this relation
1325 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( layer->getFeature( fid ) );
1326 QgsFeature childFeature;
1327 while ( relatedFeaturesIt.nextFeature( childFeature ) )
1328 {
1329 childFeatureIds.insert( childFeature.id() );
1330 }
1331 }
1332
1333 if ( childFeatureIds.count() > 0 )
1334 {
1335 if ( context.layers().contains( relation.referencingLayer() ) )
1336 {
1337 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( relation.referencingLayer() );
1338 // add feature ids
1339 handledFeatureIds.unite( childFeatureIds );
1340 context.setDuplicatedFeatures( relation.referencingLayer(), handledFeatureIds );
1341 }
1342 else
1343 {
1344 // add layer and feature id
1345 context.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
1346 }
1347 }
1348 break;
1349 }
1350
1352 break;
1353 }
1354 }
1355
1356 if ( layer->joinBuffer()->containsJoins() )
1357 {
1358 const QgsVectorJoinList joins = layer->joinBuffer()->vectorJoins();
1359 for ( const QgsVectorLayerJoinInfo &info : joins )
1360 {
1361 if ( qobject_cast< QgsAuxiliaryLayer * >( info.joinLayer() ) && flags & IgnoreAuxiliaryLayers )
1362 continue;
1363
1364 if ( info.isEditable() && info.hasCascadedDelete() )
1365 {
1366 QgsFeatureIds joinFeatureIds;
1367 const auto constFids = fids;
1368 for ( const QgsFeatureId &fid : constFids )
1369 {
1370 const QgsFeature joinFeature = layer->joinBuffer()->joinedFeatureOf( &info, layer->getFeature( fid ) );
1371 if ( joinFeature.isValid() )
1372 joinFeatureIds.insert( joinFeature.id() );
1373 }
1374
1375 if ( joinFeatureIds.count() > 0 )
1376 {
1377 if ( context.layers().contains( info.joinLayer() ) )
1378 {
1379 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( info.joinLayer() );
1380 // add feature ids
1381 handledFeatureIds.unite( joinFeatureIds );
1382 context.setDuplicatedFeatures( info.joinLayer(), handledFeatureIds );
1383 }
1384 else
1385 {
1386 // add layer and feature id
1387 context.setDuplicatedFeatures( info.joinLayer(), joinFeatureIds );
1388 }
1389 }
1390 }
1391 }
1392 }
1393
1394 return !context.layers().isEmpty();
1395}
1396
1397QString QgsVectorLayerUtils::guessFriendlyIdentifierField( const QgsFields &fields, bool *foundFriendly )
1398{
1399 if ( foundFriendly )
1400 *foundFriendly = false;
1401
1402 if ( fields.isEmpty() )
1403 return QString();
1404
1405 // Check the fields and keep the first one that matches.
1406 // We assume that the user has organized the data with the
1407 // more "interesting" field names first. As such, name should
1408 // be selected before oldname, othername, etc.
1409 // This candidates list is a prioritized list of candidates ranked by "interestingness"!
1410 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
1411 // but adding hardcoded localized variants of the strings is encouraged.
1412 static QStringList sCandidates {
1413 u"name"_s,
1414 u"title"_s,
1415 u"heibt"_s,
1416 u"desc"_s,
1417 u"nom"_s,
1418 u"street"_s,
1419 u"road"_s,
1420 u"label"_s,
1421 // German candidates
1422 u"titel"_s, //#spellok
1423 u"beschreibung"_s,
1424 u"strasse"_s,
1425 u"beschriftung"_s
1426 };
1427
1428 // anti-names
1429 // this list of strings indicates parts of field names which make the name "less interesting".
1430 // For instance, we'd normally like to default to a field called "name" or "title", but if instead we
1431 // find one called "typename" or "typeid", then that's most likely a classification of the feature and not the
1432 // best choice to default to
1433 static QStringList sAntiCandidates {
1434 u"type"_s,
1435 u"class"_s,
1436 u"cat"_s,
1437 // German anti-candidates
1438 u"typ"_s,
1439 u"klasse"_s,
1440 u"kategorie"_s
1441 };
1442
1443 QString bestCandidateName;
1444 QString bestCandidateContainsName;
1445 QString bestCandidateContainsNameWithAntiCandidate;
1446
1447 for ( const QString &candidate : sCandidates )
1448 {
1449 for ( const QgsField &field : fields )
1450 {
1451 const QString fldName = field.name();
1452
1453 if ( fldName.compare( candidate, Qt::CaseInsensitive ) == 0 )
1454 {
1455 bestCandidateName = fldName;
1456 }
1457 else if ( fldName.contains( candidate, Qt::CaseInsensitive ) )
1458 {
1459 bool isAntiCandidate = false;
1460 for ( const QString &antiCandidate : sAntiCandidates )
1461 {
1462 if ( fldName.contains( antiCandidate, Qt::CaseInsensitive ) )
1463 {
1464 isAntiCandidate = true;
1465 break;
1466 }
1467 }
1468
1469 if ( isAntiCandidate )
1470 {
1471 if ( bestCandidateContainsNameWithAntiCandidate.isEmpty() )
1472 {
1473 bestCandidateContainsNameWithAntiCandidate = fldName;
1474 }
1475 }
1476 else
1477 {
1478 if ( bestCandidateContainsName.isEmpty() )
1479 {
1480 bestCandidateContainsName = fldName;
1481 }
1482 }
1483 }
1484 }
1485
1486 if ( !bestCandidateName.isEmpty() )
1487 break;
1488 }
1489
1490 QString candidateName = bestCandidateName;
1491 if ( candidateName.isEmpty() )
1492 {
1493 candidateName = bestCandidateContainsName.isEmpty() ? bestCandidateContainsNameWithAntiCandidate : bestCandidateContainsName;
1494 }
1495
1496 if ( !candidateName.isEmpty() )
1497 {
1498 // Special case for layers got from WFS using the OGR GMLAS field parsing logic.
1499 // Such layers contain a "id" field (the gml:id attribute of the object),
1500 // as well as a gml_name (a <gml:name>) element. However this gml:name is often
1501 // absent, partly because it is a property of the base class in GML schemas, and
1502 // that a lot of readers are not able to deduce its potential presence.
1503 // So try to look at another field whose name would end with _name
1504 // And fallback to using the "id" field that should always be filled.
1505 if ( candidateName == "gml_name"_L1 && fields.indexOf( "id"_L1 ) >= 0 )
1506 {
1507 candidateName.clear();
1508 // Try to find a field ending with "_name", which is not "gml_name"
1509 for ( const QgsField &field : std::as_const( fields ) )
1510 {
1511 const QString fldName = field.name();
1512 if ( fldName != "gml_name"_L1 && fldName.endsWith( "_name"_L1 ) )
1513 {
1514 candidateName = fldName;
1515 break;
1516 }
1517 }
1518 if ( candidateName.isEmpty() )
1519 {
1520 // Fallback to "id"
1521 candidateName = u"id"_s;
1522 }
1523 }
1524
1525 if ( foundFriendly )
1526 *foundFriendly = true;
1527 return candidateName;
1528 }
1529 else
1530 {
1531 // no good matches found by name, so scan through and look for the first string field
1532 for ( const QgsField &field : fields )
1533 {
1534 if ( field.type() == QMetaType::Type::QString )
1535 return field.name();
1536 }
1537
1538 // no string fields found - just return first field
1539 return fields.at( 0 ).name();
1540 }
1541}
1542
1543template<typename T, typename ConverterFunc> void populateFieldDataArray( const QVector<QVariant> &values, const QVariant &nullValue, QByteArray &res, ConverterFunc converter )
1544{
1545 res.resize( values.size() * sizeof( T ) );
1546 T *data = reinterpret_cast<T *>( res.data() );
1547 for ( const QVariant &val : values )
1548 {
1549 if ( QgsVariantUtils::isNull( val ) )
1550 {
1551 *data++ = converter( nullValue );
1552 }
1553 else
1554 {
1555 *data++ = converter( val );
1556 }
1557 }
1558}
1559
1560QByteArray QgsVectorLayerUtils::fieldToDataArray( const QgsFields &fields, const QString &fieldName, QgsFeatureIterator &it, const QVariant &nullValue )
1561{
1562 const int fieldIndex = fields.lookupField( fieldName );
1563 if ( fieldIndex < 0 )
1564 return QByteArray();
1565
1566 QVector< QVariant > values;
1567 QgsFeature f;
1568 while ( it.nextFeature( f ) )
1569 {
1570 values.append( f.attribute( fieldIndex ) );
1571 }
1572
1573 const QgsField field = fields.at( fieldIndex );
1574 QByteArray res;
1575 switch ( field.type() )
1576 {
1577 case QMetaType::Int:
1578 {
1579 populateFieldDataArray<int>( values, nullValue, res, []( const QVariant &v ) { return v.toInt(); } );
1580 break;
1581 }
1582
1583 case QMetaType::UInt:
1584 {
1585 populateFieldDataArray<unsigned int>( values, nullValue, res, []( const QVariant &v ) { return v.toUInt(); } );
1586 break;
1587 }
1588
1589 case QMetaType::LongLong:
1590 {
1591 populateFieldDataArray<long long>( values, nullValue, res, []( const QVariant &v ) { return v.toLongLong(); } );
1592 break;
1593 }
1594
1595 case QMetaType::ULongLong:
1596 {
1597 populateFieldDataArray<unsigned long long>( values, nullValue, res, []( const QVariant &v ) { return v.toULongLong(); } );
1598 break;
1599 }
1600
1601 case QMetaType::Double:
1602 {
1603 populateFieldDataArray<double>( values, nullValue, res, []( const QVariant &v ) { return v.toDouble(); } );
1604 break;
1605 }
1606
1607 case QMetaType::Long:
1608 {
1609 populateFieldDataArray<long>( values, nullValue, res, []( const QVariant &v ) { return v.toLongLong(); } );
1610 break;
1611 }
1612
1613 case QMetaType::Short:
1614 {
1615 populateFieldDataArray<short>( values, nullValue, res, []( const QVariant &v ) { return v.toInt(); } );
1616 break;
1617 }
1618
1619 case QMetaType::ULong:
1620 {
1621 populateFieldDataArray<unsigned long>( values, nullValue, res, []( const QVariant &v ) { return v.toULongLong(); } );
1622 break;
1623 }
1624
1625 case QMetaType::UShort:
1626 {
1627 populateFieldDataArray<unsigned short>( values, nullValue, res, []( const QVariant &v ) { return v.toUInt(); } );
1628 break;
1629 }
1630
1631 case QMetaType::Float:
1632 {
1633 populateFieldDataArray<float>( values, nullValue, res, []( const QVariant &v ) { return v.toFloat(); } );
1634 break;
1635 }
1636
1637 default:
1638 break;
1639 }
1640
1641 return res;
1642}
1643
1645{
1646 if ( !layer )
1647 return QgsFeatureIds();
1648
1649 if ( featureIds.isEmpty() )
1650 return QgsFeatureIds();
1651
1652 // build up an optimised feature request
1653 QgsFeatureRequest request;
1654 request.setFilterFids( featureIds );
1655 request.setNoAttributes();
1657
1658 QgsFeatureIds validIds;
1659 validIds.reserve( featureIds.size() );
1660
1661 QgsFeature feat;
1662 QgsFeatureIterator it = layer->getFeatures( request );
1663 while ( it.nextFeature( feat ) )
1664 {
1665 validIds.insert( feat.id() );
1666 }
1667
1668 return validIds;
1669}
@ 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:4818
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
Definition qgis.h:4817
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2343
@ NoFlags
No flags are set.
Definition qgis.h:2342
@ Label
A mask generated from a labeling provider.
Definition qgis.h:3251
@ SymbolLayer
A mask generated from a symbol layer.
Definition qgis.h:3250
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:4144
@ DefaultValue
Use default field value.
Definition qgis.h:4142
@ Duplicate
Duplicate original value.
Definition qgis.h:4143
@ Provider
Field originates from the underlying data provider of the vector layer.
Definition qgis.h:1840
@ Join
Field originates from a joined layer.
Definition qgis.h:1841
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.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
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:64
QgsFields fields
Definition qgsfeature.h:65
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
QgsFeatureId id
Definition qgsfeature.h:63
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:66
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:485
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:779
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:114
QgsRelationManager * relationManager
Definition qgsproject.h:125
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:1547
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1462
@ LabelSettingsEntity
Label settings.
Definition qgsstyle.h:212
@ SymbolEntity
Symbols.
Definition qgsstyle.h:207
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.
Q_INVOKABLE 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
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.
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.