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 <QRegularExpression>
17
18 #include "qgsexpressioncontext.h"
19 #include "qgsfeatureiterator.h"
20 #include "qgsfeaturerequest.h"
21 #include "qgsvectorlayerutils.h"
22 #include "qgsvectordataprovider.h"
23 #include "qgsproject.h"
24 #include "qgsrelationmanager.h"
25 #include "qgsfeedback.h"
26 #include "qgsvectorlayer.h"
27 #include "qgsthreadingutils.h"
28 #include "qgsgeometrycollection.h"
29 #include "qgsexpressioncontextutils.h"
30 #include "qgsmultisurface.h"
31 #include "qgsgeometryfactory.h"
32 #include "qgscurvepolygon.h"
33 #include "qgspolygon.h"
34 #include "qgslinestring.h"
35 #include "qgsmultipoint.h"
36 #include "qgsvectorlayerjoinbuffer.h"
37 #include "qgsvectorlayerlabeling.h"
38 #include "qgspallabeling.h"
39 #include "qgsrenderer.h"
40 #include "qgssymbollayer.h"
41 #include "qgsstyleentityvisitor.h"
42 #include "qgsstyle.h"
43 #include "qgsauxiliarystorage.h"
44
45
getValuesIterator(const QgsVectorLayer * layer,const QString & fieldOrExpression,bool & ok,bool selectedOnly)46 QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
47 {
48 std::unique_ptr<QgsExpression> expression;
49 QgsExpressionContext context;
50
51 int attrNum = layer->fields().lookupField( fieldOrExpression );
52 if ( attrNum == -1 )
53 {
54 // try to use expression
55 expression.reset( new QgsExpression( fieldOrExpression ) );
56 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
57
58 if ( expression->hasParserError() || !expression->prepare( &context ) )
59 {
60 ok = false;
61 return QgsFeatureIterator();
62 }
63 }
64
65 QSet<QString> lst;
66 if ( !expression )
67 lst.insert( fieldOrExpression );
68 else
69 lst = expression->referencedColumns();
70
71 QgsFeatureRequest request = QgsFeatureRequest()
72 .setFlags( ( expression && expression->needsGeometry() ) ?
73 QgsFeatureRequest::NoFlags :
74 QgsFeatureRequest::NoGeometry )
75 .setSubsetOfAttributes( lst, layer->fields() );
76
77 ok = true;
78 if ( !selectedOnly )
79 {
80 return layer->getFeatures( request );
81 }
82 else
83 {
84 return layer->getSelectedFeatures( request );
85 }
86 }
87
getValues(const QgsVectorLayer * layer,const QString & fieldOrExpression,bool & ok,bool selectedOnly,QgsFeedback * feedback)88 QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
89 {
90 QList<QVariant> values;
91 QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
92 if ( ok )
93 {
94 std::unique_ptr<QgsExpression> expression;
95 QgsExpressionContext context;
96
97 int attrNum = layer->fields().lookupField( fieldOrExpression );
98 if ( attrNum == -1 )
99 {
100 // use expression, already validated in the getValuesIterator() function
101 expression.reset( new QgsExpression( fieldOrExpression ) );
102 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
103 }
104
105 QgsFeature f;
106 while ( fit.nextFeature( f ) )
107 {
108 if ( expression )
109 {
110 context.setFeature( f );
111 QVariant v = expression->evaluate( &context );
112 values << v;
113 }
114 else
115 {
116 values << f.attribute( attrNum );
117 }
118 if ( feedback && feedback->isCanceled() )
119 {
120 ok = false;
121 return values;
122 }
123 }
124 }
125 return values;
126 }
127
getDoubleValues(const QgsVectorLayer * layer,const QString & fieldOrExpression,bool & ok,bool selectedOnly,int * nullCount,QgsFeedback * feedback)128 QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
129 {
130 QList<double> values;
131
132 if ( nullCount )
133 *nullCount = 0;
134
135 QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
136 if ( !ok )
137 return values;
138
139 bool convertOk;
140 const auto constVariantValues = variantValues;
141 for ( const QVariant &value : constVariantValues )
142 {
143 double val = value.toDouble( &convertOk );
144 if ( convertOk )
145 values << val;
146 else if ( value.isNull() )
147 {
148 if ( nullCount )
149 *nullCount += 1;
150 }
151 if ( feedback && feedback->isCanceled() )
152 {
153 ok = false;
154 return values;
155 }
156 }
157 return values;
158 }
159
valueExists(const QgsVectorLayer * layer,int fieldIndex,const QVariant & value,const QgsFeatureIds & ignoreIds)160 bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
161 {
162 if ( !layer )
163 return false;
164
165 QgsFields fields = layer->fields();
166
167 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
168 return false;
169
170 // If it's a joined field search the value in the source layer
171 if ( fields.fieldOrigin( fieldIndex ) == QgsFields::FieldOrigin::OriginJoin )
172 {
173 int srcFieldIndex;
174 const QgsVectorLayerJoinInfo *joinInfo { layer->joinBuffer()->joinForFieldIndex( fieldIndex, fields, srcFieldIndex ) };
175 if ( ! joinInfo )
176 {
177 return false;
178 }
179 fieldIndex = srcFieldIndex;
180 layer = joinInfo->joinLayer();
181 if ( ! layer )
182 {
183 return false;
184 }
185 fields = layer->fields();
186 }
187
188 QString fieldName = fields.at( fieldIndex ).name();
189
190 // build up an optimised feature request
191 QgsFeatureRequest request;
192 request.setNoAttributes();
193 request.setFlags( QgsFeatureRequest::NoGeometry );
194
195 // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
196 int limit = ignoreIds.size() + 1;
197 request.setLimit( limit );
198
199 request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
200 QgsExpression::quotedValue( value ) ) );
201
202 QgsFeature feat;
203 QgsFeatureIterator it = layer->getFeatures( request );
204 while ( it.nextFeature( feat ) )
205 {
206 if ( ignoreIds.contains( feat.id() ) )
207 continue;
208
209 return true;
210 }
211
212 return false;
213 }
214
createUniqueValue(const QgsVectorLayer * layer,int fieldIndex,const QVariant & seed)215 QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
216 {
217 if ( !layer )
218 return QVariant();
219
220 QgsFields fields = layer->fields();
221
222 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
223 return QVariant();
224
225 QgsField field = fields.at( fieldIndex );
226
227 if ( field.isNumeric() )
228 {
229 QVariant maxVal = layer->maximumValue( fieldIndex );
230 QVariant newVar( maxVal.toLongLong() + 1 );
231 if ( field.convertCompatible( newVar ) )
232 return newVar;
233 else
234 return QVariant();
235 }
236 else
237 {
238 switch ( field.type() )
239 {
240 case QVariant::String:
241 {
242 QString base;
243 if ( seed.isValid() )
244 base = seed.toString();
245
246 if ( !base.isEmpty() )
247 {
248 // strip any existing _1, _2 from the seed
249 QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
250 QRegularExpressionMatch match = rx.match( base );
251 if ( match.hasMatch() )
252 {
253 base = match.captured( 1 );
254 }
255 }
256 else
257 {
258 // no base seed - fetch first value from layer
259 QgsFeatureRequest req;
260 req.setLimit( 1 );
261 req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
262 req.setFlags( QgsFeatureRequest::NoGeometry );
263 QgsFeature f;
264 layer->getFeatures( req ).nextFeature( f );
265 base = f.attribute( fieldIndex ).toString();
266 }
267
268 // try variants like base_1, base_2, etc until a new value found
269 QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
270
271 // might already be unique
272 if ( !base.isEmpty() && !vals.contains( base ) )
273 return base;
274
275 for ( int i = 1; i < 10000; ++i )
276 {
277 QString testVal = base + '_' + QString::number( i );
278 if ( !vals.contains( testVal ) )
279 return testVal;
280 }
281
282 // failed
283 return QVariant();
284 }
285
286 default:
287 // todo other types - dates? times?
288 break;
289 }
290 }
291
292 return QVariant();
293 }
294
createUniqueValueFromCache(const QgsVectorLayer * layer,int fieldIndex,const QSet<QVariant> & existingValues,const QVariant & seed)295 QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
296 {
297 if ( !layer )
298 return QVariant();
299
300 QgsFields fields = layer->fields();
301
302 if ( fieldIndex < 0 || fieldIndex >= fields.count() )
303 return QVariant();
304
305 QgsField field = fields.at( fieldIndex );
306
307 if ( field.isNumeric() )
308 {
309 QVariant maxVal = existingValues.isEmpty() ? 0 : *std::max_element( existingValues.begin(), existingValues.end() );
310 QVariant newVar( maxVal.toLongLong() + 1 );
311 if ( field.convertCompatible( newVar ) )
312 return newVar;
313 else
314 return QVariant();
315 }
316 else
317 {
318 switch ( field.type() )
319 {
320 case QVariant::String:
321 {
322 QString base;
323 if ( seed.isValid() )
324 base = seed.toString();
325
326 if ( !base.isEmpty() )
327 {
328 // strip any existing _1, _2 from the seed
329 QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
330 QRegularExpressionMatch match = rx.match( base );
331 if ( match.hasMatch() )
332 {
333 base = match.captured( 1 );
334 }
335 }
336 else
337 {
338 // no base seed - fetch first value from layer
339 QgsFeatureRequest req;
340 base = existingValues.isEmpty() ? QString() : existingValues.values().first().toString();
341 }
342
343 // try variants like base_1, base_2, etc until a new value found
344 QStringList vals;
345 for ( const auto &v : qgis::as_const( existingValues ) )
346 {
347 if ( v.toString().startsWith( base ) )
348 vals.push_back( v.toString() );
349 }
350
351 // might already be unique
352 if ( !base.isEmpty() && !vals.contains( base ) )
353 return base;
354
355 for ( int i = 1; i < 10000; ++i )
356 {
357 QString testVal = base + '_' + QString::number( i );
358 if ( !vals.contains( testVal ) )
359 return testVal;
360 }
361
362 // failed
363 return QVariant();
364 }
365
366 default:
367 // todo other types - dates? times?
368 break;
369 }
370 }
371
372 return QVariant();
373
374 }
375
validateAttribute(const QgsVectorLayer * layer,const QgsFeature & feature,int attributeIndex,QStringList & errors,QgsFieldConstraints::ConstraintStrength strength,QgsFieldConstraints::ConstraintOrigin origin)376 bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
377 QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin )
378 {
379 if ( !layer )
380 return false;
381
382 if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
383 return false;
384
385 QgsFields fields = layer->fields();
386 QgsField field = fields.at( attributeIndex );
387 QVariant value = feature.attribute( attributeIndex );
388 bool valid = true;
389 errors.clear();
390
391 QgsFieldConstraints constraints = field.constraints();
392
393 if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
394 && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintExpression ) )
395 && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintExpression ) ) )
396 {
397 QgsExpressionContext context = layer->createExpressionContext();
398 context.setFeature( feature );
399
400 QgsExpression expr( constraints.constraintExpression() );
401
402 valid = expr.evaluate( &context ).toBool();
403
404 if ( expr.hasParserError() )
405 {
406 errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
407 }
408 else if ( expr.hasEvalError() )
409 {
410 errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
411 }
412 else if ( !valid )
413 {
414 errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
415 }
416 }
417
418 bool notNullConstraintViolated { false };
419
420 if ( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull
421 && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintNotNull ) )
422 && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) ) )
423 {
424 bool exempt = false;
425 if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
426 && constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) == QgsFieldConstraints::ConstraintOriginProvider )
427 {
428 int providerIdx = fields.fieldOriginIndex( attributeIndex );
429 exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
430 }
431
432 if ( !exempt )
433 {
434 valid = valid && !value.isNull();
435
436 if ( value.isNull() )
437 {
438 errors << QObject::tr( "value is NULL" );
439 notNullConstraintViolated = true;
440 }
441 }
442 }
443
444 // if a NOT NULL constraint is violated we don't need to check for UNIQUE
445 if ( ! notNullConstraintViolated )
446 {
447
448 if ( constraints.constraints() & QgsFieldConstraints::ConstraintUnique
449 && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintUnique ) )
450 && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintUnique ) ) )
451 {
452 bool exempt = false;
453 if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
454 && constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) == QgsFieldConstraints::ConstraintOriginProvider )
455 {
456 int providerIdx = fields.fieldOriginIndex( attributeIndex );
457 exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
458 }
459
460 if ( !exempt )
461 {
462
463 bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
464 valid = valid && !alreadyExists;
465
466 if ( alreadyExists )
467 {
468 errors << QObject::tr( "value is not unique" );
469 }
470 }
471 }
472 }
473
474 return valid;
475 }
476
createFeature(const QgsVectorLayer * layer,const QgsGeometry & geometry,const QgsAttributeMap & attributes,QgsExpressionContext * context)477 QgsFeature QgsVectorLayerUtils::createFeature( const QgsVectorLayer *layer, const QgsGeometry &geometry,
478 const QgsAttributeMap &attributes, QgsExpressionContext *context )
479 {
480 QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
481 return features.isEmpty() ? QgsFeature() : features.first();
482 }
483
createFeatures(const QgsVectorLayer * layer,const QgsFeaturesDataList & featuresData,QgsExpressionContext * context)484 QgsFeatureList QgsVectorLayerUtils::createFeatures( const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context )
485 {
486 if ( !layer )
487 return QgsFeatureList();
488
489 QgsFeatureList result;
490 result.reserve( featuresData.length() );
491
492 QgsExpressionContext *evalContext = context;
493 std::unique_ptr< QgsExpressionContext > tempContext;
494 if ( !evalContext )
495 {
496 // no context passed, so we create a default one
497 tempContext.reset( new QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) ) );
498 evalContext = tempContext.get();
499 }
500
501 QgsFields fields = layer->fields();
502
503 // Cache unique values
504 QMap<int, QSet<QVariant>> uniqueValueCache;
505
506 auto checkUniqueValue = [ & ]( const int fieldIdx, const QVariant & value )
507 {
508 if ( ! uniqueValueCache.contains( fieldIdx ) )
509 {
510 // If the layer is filtered, get unique values from an unfiltered clone
511 if ( ! layer->subsetString().isEmpty() )
512 {
513 std::unique_ptr<QgsVectorLayer> unfilteredClone { layer->clone( ) };
514 unfilteredClone->setSubsetString( QString( ) );
515 uniqueValueCache[ fieldIdx ] = unfilteredClone->uniqueValues( fieldIdx );
516 }
517 else
518 {
519 uniqueValueCache[ fieldIdx ] = layer->uniqueValues( fieldIdx );
520 }
521 }
522 return uniqueValueCache[ fieldIdx ].contains( value );
523 };
524
525 for ( const auto &fd : qgis::as_const( featuresData ) )
526 {
527
528 QgsFeature newFeature( fields );
529 newFeature.setValid( true );
530 newFeature.setGeometry( fd.geometry() );
531
532 // initialize attributes
533 newFeature.initAttributes( fields.count() );
534 for ( int idx = 0; idx < fields.count(); ++idx )
535 {
536 QVariant v;
537 bool checkUnique = true;
538 const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
539
540 // in order of priority:
541 // 1. passed attribute value and if field does not have a unique constraint like primary key
542 if ( fd.attributes().contains( idx ) )
543 {
544 v = fd.attributes().value( idx );
545 }
546
547 // 2. client side default expression
548 // note - deliberately not using else if!
549 QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
550 if ( ( v.isNull() || ( hasUniqueConstraint
551 && checkUniqueValue( idx, v ) )
552 || defaultValueDefinition.applyOnUpdate() )
553 && defaultValueDefinition.isValid() )
554 {
555 // client side default expression set - takes precedence over all. Why? Well, this is the only default
556 // which QGIS users have control over, so we assume that they're deliberately overriding any
557 // provider defaults for some good reason and we should respect that
558 v = layer->defaultValue( idx, newFeature, evalContext );
559 }
560
561 // 3. provider side default value clause
562 // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
563 if ( ( v.isNull() || ( hasUniqueConstraint
564 && checkUniqueValue( idx, v ) ) )
565 && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
566 {
567 int providerIndex = fields.fieldOriginIndex( idx );
568 QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
569 if ( !providerDefault.isEmpty() )
570 {
571 v = providerDefault;
572 checkUnique = false;
573 }
574 }
575
576 // 4. provider side default literal
577 // note - deliberately not using else if!
578 if ( ( v.isNull() || ( checkUnique
579 && hasUniqueConstraint
580 && checkUniqueValue( idx, v ) ) )
581 && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
582 {
583 int providerIndex = fields.fieldOriginIndex( idx );
584 v = layer->dataProvider()->defaultValue( providerIndex );
585 if ( v.isValid() )
586 {
587 //trust that the provider default has been sensibly set not to violate any constraints
588 checkUnique = false;
589 }
590 }
591
592 // 5. passed attribute value
593 // note - deliberately not using else if!
594 if ( v.isNull() && fd.attributes().contains( idx ) )
595 {
596 v = fd.attributes().value( idx );
597 }
598
599 // last of all... check that unique constraints are respected if the value is valid
600 if ( v.isValid() )
601 {
602 // we can't handle not null or expression constraints here, since there's no way to pick a sensible
603 // value if the constraint is violated
604 if ( checkUnique && hasUniqueConstraint )
605 {
606 if ( checkUniqueValue( idx, v ) )
607 {
608 // unique constraint violated
609 QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCache[ idx ], v );
610 if ( uniqueValue.isValid() )
611 v = uniqueValue;
612 }
613 }
614 if ( hasUniqueConstraint )
615 {
616 uniqueValueCache[ idx ].insert( v );
617 }
618 }
619 newFeature.setAttribute( idx, v );
620 }
621 result.append( newFeature );
622 }
623 return result;
624 }
625
duplicateFeature(QgsVectorLayer * layer,const QgsFeature & feature,QgsProject * project,QgsDuplicateFeatureContext & duplicateFeatureContext,const int maxDepth,int depth,QList<QgsVectorLayer * > referencedLayersBranch)626 QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth, int depth, QList<QgsVectorLayer *> referencedLayersBranch )
627 {
628 if ( !layer )
629 return QgsFeature();
630
631 if ( !layer->isEditable() )
632 return QgsFeature();
633
634 //get context from layer
635 QgsExpressionContext context = layer->createExpressionContext();
636 context.setFeature( feature );
637
638 QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
639 layer->addFeature( newFeature );
640
641 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
642
643 const int effectiveMaxDepth = maxDepth > 0 ? maxDepth : 100;
644
645 for ( const QgsRelation &relation : relations )
646 {
647 //check if composition (and not association)
648 if ( relation.strength() == QgsRelation::Composition && !referencedLayersBranch.contains( relation.referencedLayer() ) && depth < effectiveMaxDepth )
649 {
650 depth++;
651 referencedLayersBranch << layer;
652
653 //get features connected over this relation
654 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
655 QgsFeatureIds childFeatureIds;
656 QgsFeature childFeature;
657 while ( relatedFeaturesIt.nextFeature( childFeature ) )
658 {
659 //set childlayer editable
660 relation.referencingLayer()->startEditing();
661 //change the fk of the child to the id of the new parent
662 const auto pairs = relation.fieldPairs();
663 for ( const QgsRelation::FieldPair &fieldPair : pairs )
664 {
665 childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
666 }
667 //call the function for the child
668 childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, duplicateFeatureContext, maxDepth, depth, referencedLayersBranch ).id() );
669 }
670
671 //store for feedback
672 duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
673 }
674 }
675
676
677 return newFeature;
678 }
679
getFeatureSource(QPointer<QgsVectorLayer> layer,QgsFeedback * feedback)680 std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
681 {
682 std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
683
684 auto getFeatureSource = [ layer, &featureSource, feedback ]
685 {
686 #if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
687 Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
688 #else
689 Q_UNUSED( feedback )
690 #endif
691 QgsVectorLayer *lyr = layer.data();
692
693 if ( lyr )
694 {
695 featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
696 }
697 };
698
699 QgsThreadingUtils::runOnMainThread( getFeatureSource, feedback );
700
701 return featureSource;
702 }
703
matchAttributesToFields(QgsFeature & feature,const QgsFields & fields)704 void QgsVectorLayerUtils::matchAttributesToFields( QgsFeature &feature, const QgsFields &fields )
705 {
706 if ( !feature.fields().isEmpty() )
707 {
708 QgsAttributes attributes;
709 attributes.reserve( fields.size() );
710 // feature has a field mapping, so we can match attributes to field names
711 for ( const QgsField &field : fields )
712 {
713 int index = feature.fields().lookupField( field.name() );
714 attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
715 }
716 feature.setAttributes( attributes );
717 }
718 else
719 {
720 // no field name mapping in feature, just use order
721 const int lengthDiff = feature.attributes().count() - fields.count();
722 if ( lengthDiff > 0 )
723 {
724 // truncate extra attributes
725 QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
726 feature.setAttributes( attributes );
727 }
728 else if ( lengthDiff < 0 )
729 {
730 // add missing null attributes
731 QgsAttributes attributes = feature.attributes();
732 attributes.reserve( fields.count() );
733 for ( int i = feature.attributes().count(); i < fields.count(); ++i )
734 {
735 attributes.append( QVariant( fields.at( i ).type() ) );
736 }
737 feature.setAttributes( attributes );
738 }
739 }
740 feature.setFields( fields );
741 }
742
makeFeatureCompatible(const QgsFeature & feature,const QgsVectorLayer * layer,QgsFeatureSink::SinkFlags sinkFlags)743 QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
744 {
745 QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
746 QgsFeatureList resultFeatures;
747 QgsFeature newF( feature );
748 // Fix attributes
749 QgsVectorLayerUtils::matchAttributesToFields( newF, layer->fields( ) );
750
751 if ( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey )
752 {
753 // drop incoming primary key values, let them be regenerated
754 const QgsAttributeList pkIndexes = layer->dataProvider()->pkAttributeIndexes();
755 for ( int index : pkIndexes )
756 {
757 if ( index >= 0 )
758 newF.setAttribute( index, QVariant() );
759 }
760 }
761
762 // Does geometry need transformations?
763 QgsWkbTypes::GeometryType newFGeomType( QgsWkbTypes::geometryType( newF.geometry().wkbType() ) );
764 bool newFHasGeom = newFGeomType !=
765 QgsWkbTypes::GeometryType::UnknownGeometry &&
766 newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
767 bool layerHasGeom = inputWkbType !=
768 QgsWkbTypes::Type::NoGeometry &&
769 inputWkbType != QgsWkbTypes::Type::Unknown;
770 // Drop geometry if layer is geometry-less
771 if ( ( newFHasGeom && !layerHasGeom ) || !newFHasGeom )
772 {
773 QgsFeature _f = QgsFeature( layer->fields() );
774 _f.setAttributes( newF.attributes() );
775 resultFeatures.append( _f );
776 }
777 else
778 {
779 // Geometry need fixing?
780 const QVector< QgsGeometry > geometries = newF.geometry().coerceToType( inputWkbType );
781
782 if ( geometries.count() != 1 )
783 {
784 QgsAttributeMap attrMap;
785 for ( int j = 0; j < newF.fields().count(); j++ )
786 {
787 attrMap[j] = newF.attribute( j );
788 }
789 resultFeatures.reserve( geometries.size() );
790 for ( const QgsGeometry &geometry : geometries )
791 {
792 QgsFeature _f( createFeature( layer, geometry, attrMap ) );
793 resultFeatures.append( _f );
794 }
795 }
796 else
797 {
798 newF.setGeometry( geometries.at( 0 ) );
799 resultFeatures.append( newF );
800 }
801 }
802 return resultFeatures;
803 }
804
makeFeaturesCompatible(const QgsFeatureList & features,const QgsVectorLayer * layer,QgsFeatureSink::SinkFlags sinkFlags)805 QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
806 {
807 QgsFeatureList resultFeatures;
808 for ( const QgsFeature &f : features )
809 {
810 const QgsFeatureList features( makeFeatureCompatible( f, layer, sinkFlags ) );
811 for ( const auto &_f : features )
812 {
813 resultFeatures.append( _f );
814 }
815 }
816 return resultFeatures;
817 }
818
layers() const819 QList<QgsVectorLayer *> QgsVectorLayerUtils::QgsDuplicateFeatureContext::layers() const
820 {
821 QList<QgsVectorLayer *> layers;
822 QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
823 for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
824 layers.append( i.key() );
825 return layers;
826 }
827
duplicatedFeatures(QgsVectorLayer * layer) const828 QgsFeatureIds QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicatedFeatures( QgsVectorLayer *layer ) const
829 {
830 return mDuplicatedFeatures[layer];
831 }
832
setDuplicatedFeatures(QgsVectorLayer * layer,const QgsFeatureIds & ids)833 void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
834 {
835 if ( mDuplicatedFeatures.contains( layer ) )
836 mDuplicatedFeatures[layer] += ids;
837 else
838 mDuplicatedFeatures.insert( layer, ids );
839 }
840 /*
841 QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
842 {
843 return mDuplicatedFeatures;
844 }
845 */
846
QgsFeatureData(const QgsGeometry & geometry,const QgsAttributeMap & attributes)847 QgsVectorLayerUtils::QgsFeatureData::QgsFeatureData( const QgsGeometry &geometry, const QgsAttributeMap &attributes ):
848 mGeometry( geometry ),
849 mAttributes( attributes )
850 {}
851
geometry() const852 QgsGeometry QgsVectorLayerUtils::QgsFeatureData::geometry() const
853 {
854 return mGeometry;
855 }
856
attributes() const857 QgsAttributeMap QgsVectorLayerUtils::QgsFeatureData::attributes() const
858 {
859 return mAttributes;
860 }
861
_fieldIsEditable(const QgsVectorLayer * layer,int fieldIndex,const QgsFeature & feature)862 bool _fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
863 {
864 return layer->isEditable() &&
865 !layer->editFormConfig().readOnly( fieldIndex ) &&
866 ( ( layer->dataProvider() && layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) || FID_IS_NEW( feature.id() ) );
867 }
868
fieldIsReadOnly(const QgsVectorLayer * layer,int fieldIndex)869 bool QgsVectorLayerUtils::fieldIsReadOnly( const QgsVectorLayer *layer, int fieldIndex )
870 {
871 if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
872 {
873 int srcFieldIndex;
874 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
875
876 if ( !info || !info->isEditable() || !info->joinLayer() )
877 return true;
878
879 return fieldIsReadOnly( info->joinLayer(), srcFieldIndex );
880 }
881 else
882 {
883 // any of these properties makes the field read only
884 if ( !layer->isEditable() ||
885 layer->editFormConfig().readOnly( fieldIndex ) ||
886 !layer->dataProvider() ||
887 ( !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues )
888 && !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) ) )
889 return true;
890
891 return false;
892 }
893 }
894
fieldEditabilityDependsOnFeature(const QgsVectorLayer * layer,int fieldIndex)895 bool QgsVectorLayerUtils::fieldEditabilityDependsOnFeature( const QgsVectorLayer *layer, int fieldIndex )
896 {
897 // editability will vary feature-by-feature only for joined fields
898 if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
899 {
900 int srcFieldIndex;
901 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
902
903 if ( !info || !info->isEditable() || info->hasUpsertOnEdit() )
904 return false;
905
906 // join does not have upsert capabilities, so the ability to edit the joined field will
907 // vary feature-by-feature, depending on whether the join target feature already exists
908 return true;
909 }
910 else
911 {
912 return false;
913 }
914 }
915
fieldIsEditable(const QgsVectorLayer * layer,int fieldIndex,const QgsFeature & feature)916 bool QgsVectorLayerUtils::fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
917 {
918 if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
919 {
920 int srcFieldIndex;
921 const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
922
923 if ( !info || !info->isEditable() )
924 return false;
925
926 // check that joined feature exist, else it is not editable
927 if ( !info->hasUpsertOnEdit() )
928 {
929 const QgsFeature joinedFeature = layer->joinBuffer()->joinedFeatureOf( info, feature );
930 if ( !joinedFeature.isValid() )
931 return false;
932 }
933
934 return _fieldIsEditable( info->joinLayer(), srcFieldIndex, feature );
935 }
936 else
937 return _fieldIsEditable( layer, fieldIndex, feature );
938 }
939
940
labelMasks(const QgsVectorLayer * layer)941 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> QgsVectorLayerUtils::labelMasks( const QgsVectorLayer *layer )
942 {
943 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
944 {
945 public:
946 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
947 {
948 if ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule )
949 {
950 currentRule = node.identifier;
951 return true;
952 }
953 return false;
954 }
955 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
956 {
957 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
958 {
959 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
960 if ( labelSettingsEntity->settings().format().mask().enabled() )
961 {
962 for ( const auto &r : labelSettingsEntity->settings().format().mask().maskedSymbolLayers() )
963 {
964 masks[currentRule][r.layerId()].insert( r.symbolLayerId() );
965 }
966 }
967 }
968 return true;
969 }
970
971 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
972 // Current label rule, empty string for a simple labeling
973 QString currentRule;
974 };
975
976 if ( ! layer->labeling() )
977 return {};
978
979 LabelMasksVisitor visitor;
980 layer->labeling()->accept( &visitor );
981 return std::move( visitor.masks );
982 }
983
symbolLayerMasks(const QgsVectorLayer * layer)984 QHash<QString, QSet<QgsSymbolLayerId>> QgsVectorLayerUtils::symbolLayerMasks( const QgsVectorLayer *layer )
985 {
986 if ( ! layer->renderer() )
987 return {};
988
989 class SymbolLayerVisitor : public QgsStyleEntityVisitorInterface
990 {
991 public:
992 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
993 {
994 return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule );
995 }
996
997 void visitSymbol( const QgsSymbol *symbol )
998 {
999 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1000 {
1001 const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1002 for ( const auto &mask : sl->masks() )
1003 {
1004 masks[mask.layerId()].insert( mask.symbolLayerId() );
1005 }
1006 // recurse over sub symbols
1007 const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
1008 if ( subSymbol )
1009 visitSymbol( subSymbol );
1010 }
1011 }
1012
1013 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1014 {
1015 if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1016 {
1017 auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1018 if ( symbolEntity->symbol() )
1019 visitSymbol( symbolEntity->symbol() );
1020 }
1021 return true;
1022 }
1023 QHash<QString, QSet<QgsSymbolLayerId>> masks;
1024 };
1025
1026 SymbolLayerVisitor visitor;
1027 layer->renderer()->accept( &visitor );
1028 return visitor.masks;
1029 }
1030
getFeatureDisplayString(const QgsVectorLayer * layer,const QgsFeature & feature)1031 QString QgsVectorLayerUtils::getFeatureDisplayString( const QgsVectorLayer *layer, const QgsFeature &feature )
1032 {
1033 QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
1034
1035 QgsExpression exp( layer->displayExpression() );
1036 context.setFeature( feature );
1037 exp.prepare( &context );
1038 QString displayString = exp.evaluate( &context ).toString();
1039
1040 return displayString;
1041 }
1042
impactsCascadeFeatures(const QgsVectorLayer * layer,const QgsFeatureIds & fids,const QgsProject * project,QgsDuplicateFeatureContext & context,CascadedFeatureFlags flags)1043 bool QgsVectorLayerUtils::impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context, CascadedFeatureFlags flags )
1044 {
1045 if ( !layer )
1046 return false;
1047
1048 const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
1049 for ( const QgsRelation &relation : relations )
1050 {
1051 if ( relation.strength() == QgsRelation::Composition )
1052 {
1053 QgsFeatureIds childFeatureIds;
1054
1055 const auto constFids = fids;
1056 for ( const QgsFeatureId fid : constFids )
1057 {
1058 //get features connected over this relation
1059 QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( layer->getFeature( fid ) );
1060 QgsFeature childFeature;
1061 while ( relatedFeaturesIt.nextFeature( childFeature ) )
1062 {
1063 childFeatureIds.insert( childFeature.id() );
1064 }
1065 }
1066
1067 if ( childFeatureIds.count() > 0 )
1068 {
1069 if ( context.layers().contains( relation.referencingLayer() ) )
1070 {
1071 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( relation.referencingLayer() );
1072 // add feature ids
1073 handledFeatureIds.unite( childFeatureIds );
1074 context.setDuplicatedFeatures( relation.referencingLayer(), handledFeatureIds );
1075 }
1076 else
1077 {
1078 // add layer and feature id
1079 context.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
1080 }
1081 }
1082 }
1083 }
1084
1085 if ( layer->joinBuffer()->containsJoins() )
1086 {
1087 const QgsVectorJoinList joins = layer->joinBuffer()->vectorJoins();
1088 for ( const QgsVectorLayerJoinInfo &info : joins )
1089 {
1090 if ( qobject_cast< QgsAuxiliaryLayer * >( info.joinLayer() ) && flags & IgnoreAuxiliaryLayers )
1091 continue;
1092
1093 if ( info.isEditable() && info.hasCascadedDelete() )
1094 {
1095 QgsFeatureIds joinFeatureIds;
1096 const auto constFids = fids;
1097 for ( const QgsFeatureId &fid : constFids )
1098 {
1099 const QgsFeature joinFeature = layer->joinBuffer()->joinedFeatureOf( &info, layer->getFeature( fid ) );
1100 if ( joinFeature.isValid() )
1101 joinFeatureIds.insert( joinFeature.id() );
1102 }
1103
1104 if ( joinFeatureIds.count() > 0 )
1105 {
1106 if ( context.layers().contains( info.joinLayer() ) )
1107 {
1108 QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( info.joinLayer() );
1109 // add feature ids
1110 handledFeatureIds.unite( joinFeatureIds );
1111 context.setDuplicatedFeatures( info.joinLayer(), handledFeatureIds );
1112 }
1113 else
1114 {
1115 // add layer and feature id
1116 context.setDuplicatedFeatures( info.joinLayer(), joinFeatureIds );
1117 }
1118 }
1119 }
1120 }
1121 }
1122
1123 return context.layers().count();
1124 }
1125