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