QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 <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 "qgsmultisurface.h"
30 #include "qgsgeometryfactory.h"
31 #include "qgscurvepolygon.h"
32 #include "qgspolygon.h"
33 #include "qgslinestring.h"
34 #include "qgsmultipoint.h"
35 
36 QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
37 {
38  std::unique_ptr<QgsExpression> expression;
39  QgsExpressionContext context;
40 
41  int attrNum = layer->fields().lookupField( fieldOrExpression );
42  if ( attrNum == -1 )
43  {
44  // try to use expression
45  expression.reset( new QgsExpression( fieldOrExpression ) );
47 
48  if ( expression->hasParserError() || !expression->prepare( &context ) )
49  {
50  ok = false;
51  return QgsFeatureIterator();
52  }
53  }
54 
55  QSet<QString> lst;
56  if ( !expression )
57  lst.insert( fieldOrExpression );
58  else
59  lst = expression->referencedColumns();
60 
62  .setFlags( ( expression && expression->needsGeometry() ) ?
65  .setSubsetOfAttributes( lst, layer->fields() );
66 
67  ok = true;
68  if ( !selectedOnly )
69  {
70  return layer->getFeatures( request );
71  }
72  else
73  {
74  return layer->getSelectedFeatures( request );
75  }
76 }
77 
78 QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
79 {
80  QList<QVariant> values;
81  QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
82  if ( ok )
83  {
84  std::unique_ptr<QgsExpression> expression;
85  QgsExpressionContext context;
86 
87  int attrNum = layer->fields().lookupField( fieldOrExpression );
88  if ( attrNum == -1 )
89  {
90  // use expression, already validated in the getValuesIterator() function
91  expression.reset( new QgsExpression( fieldOrExpression ) );
93  }
94 
95  QgsFeature f;
96  while ( fit.nextFeature( f ) )
97  {
98  if ( expression )
99  {
100  context.setFeature( f );
101  QVariant v = expression->evaluate( &context );
102  values << v;
103  }
104  else
105  {
106  values << f.attribute( attrNum );
107  }
108  if ( feedback && feedback->isCanceled() )
109  {
110  ok = false;
111  return values;
112  }
113  }
114  }
115  return values;
116 }
117 
118 QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
119 {
120  QList<double> values;
121 
122  if ( nullCount )
123  *nullCount = 0;
124 
125  QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
126  if ( !ok )
127  return values;
128 
129  bool convertOk;
130  Q_FOREACH ( const QVariant &value, variantValues )
131  {
132  double val = value.toDouble( &convertOk );
133  if ( convertOk )
134  values << val;
135  else if ( value.isNull() )
136  {
137  if ( nullCount )
138  *nullCount += 1;
139  }
140  if ( feedback && feedback->isCanceled() )
141  {
142  ok = false;
143  return values;
144  }
145  }
146  return values;
147 }
148 
149 bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
150 {
151  if ( !layer )
152  return false;
153 
154  QgsFields fields = layer->fields();
155 
156  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
157  return false;
158 
159  QString fieldName = fields.at( fieldIndex ).name();
160 
161  // build up an optimised feature request
162  QgsFeatureRequest request;
163  request.setNoAttributes();
165 
166  // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
167  int limit = ignoreIds.size() + 1;
168  request.setLimit( limit );
169 
170  request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
171  QgsExpression::quotedValue( value ) ) );
172 
173  QgsFeature feat;
174  QgsFeatureIterator it = layer->getFeatures( request );
175  while ( it.nextFeature( feat ) )
176  {
177  if ( ignoreIds.contains( feat.id() ) )
178  continue;
179 
180  return true;
181  }
182 
183  return false;
184 }
185 
186 QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
187 {
188  if ( !layer )
189  return QVariant();
190 
191  QgsFields fields = layer->fields();
192 
193  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
194  return QVariant();
195 
196  QgsField field = fields.at( fieldIndex );
197 
198  if ( field.isNumeric() )
199  {
200  QVariant maxVal = layer->maximumValue( fieldIndex );
201  QVariant newVar( maxVal.toLongLong() + 1 );
202  if ( field.convertCompatible( newVar ) )
203  return newVar;
204  else
205  return QVariant();
206  }
207  else
208  {
209  switch ( field.type() )
210  {
211  case QVariant::String:
212  {
213  QString base;
214  if ( seed.isValid() )
215  base = seed.toString();
216 
217  if ( !base.isEmpty() )
218  {
219  // strip any existing _1, _2 from the seed
220  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
221  QRegularExpressionMatch match = rx.match( base );
222  if ( match.hasMatch() )
223  {
224  base = match.captured( 1 );
225  }
226  }
227  else
228  {
229  // no base seed - fetch first value from layer
230  QgsFeatureRequest req;
231  req.setLimit( 1 );
232  req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
234  QgsFeature f;
235  layer->getFeatures( req ).nextFeature( f );
236  base = f.attribute( fieldIndex ).toString();
237  }
238 
239  // try variants like base_1, base_2, etc until a new value found
240  QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
241 
242  // might already be unique
243  if ( !base.isEmpty() && !vals.contains( base ) )
244  return base;
245 
246  for ( int i = 1; i < 10000; ++i )
247  {
248  QString testVal = base + '_' + QString::number( i );
249  if ( !vals.contains( testVal ) )
250  return testVal;
251  }
252 
253  // failed
254  return QVariant();
255  }
256 
257  default:
258  // todo other types - dates? times?
259  break;
260  }
261  }
262 
263  return QVariant();
264 }
265 
266 bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
268 {
269  if ( !layer )
270  return false;
271 
272  if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
273  return false;
274 
275  QgsFields fields = layer->fields();
276  QgsField field = fields.at( attributeIndex );
277  QVariant value = feature.attribute( attributeIndex );
278  bool valid = true;
279  errors.clear();
280 
281  QgsFieldConstraints constraints = field.constraints();
282 
283  if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
286  {
288  context.setFeature( feature );
289 
290  QgsExpression expr( constraints.constraintExpression() );
291 
292  valid = expr.evaluate( &context ).toBool();
293 
294  if ( expr.hasParserError() )
295  {
296  errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
297  }
298  else if ( expr.hasEvalError() )
299  {
300  errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
301  }
302  else if ( !valid )
303  {
304  errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
305  }
306  }
307 
311  {
312  bool exempt = false;
313  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
315  {
316  int providerIdx = fields.fieldOriginIndex( attributeIndex );
317  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
318  }
319 
320  if ( !exempt )
321  {
322  valid = valid && !value.isNull();
323 
324  if ( value.isNull() )
325  {
326  errors << QObject::tr( "value is NULL" );
327  }
328  }
329  }
330 
334  {
335  bool exempt = false;
336  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
338  {
339  int providerIdx = fields.fieldOriginIndex( attributeIndex );
340  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
341  }
342 
343  if ( !exempt )
344  {
345  bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
346  valid = valid && !alreadyExists;
347 
348  if ( alreadyExists )
349  {
350  errors << QObject::tr( "value is not unique" );
351  }
352  }
353  }
354 
355  return valid;
356 }
357 
359  const QgsAttributeMap &attributes, QgsExpressionContext *context )
360 {
361  if ( !layer )
362  {
363  return QgsFeature();
364  }
365 
366  QgsExpressionContext *evalContext = context;
367  std::unique_ptr< QgsExpressionContext > tempContext;
368  if ( !evalContext )
369  {
370  // no context passed, so we create a default one
372  evalContext = tempContext.get();
373  }
374 
375  QgsFields fields = layer->fields();
376 
377  QgsFeature newFeature( fields );
378  newFeature.setValid( true );
379  newFeature.setGeometry( geometry );
380 
381  // initialize attributes
382  newFeature.initAttributes( fields.count() );
383  for ( int idx = 0; idx < fields.count(); ++idx )
384  {
385  QVariant v;
386  bool checkUnique = true;
387  bool hasUniqueConstraint = fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique;
388 
389  // in order of priority:
390  // 1. passed attribute value and if field does not have a unique constraint like primary key
391  if ( attributes.contains( idx ) )
392  {
393  v = attributes.value( idx );
394  }
395 
396  // 2. client side default expression
397  // note - deliberately not using else if!
398  if ( ( v.isNull() || ( hasUniqueConstraint && QgsVectorLayerUtils::valueExists( layer, idx, v ) ) )
399  && layer->defaultValueDefinition( idx ).isValid() )
400  {
401  // client side default expression set - takes precedence over all. Why? Well, this is the only default
402  // which QGIS users have control over, so we assume that they're deliberately overriding any
403  // provider defaults for some good reason and we should respect that
404  v = layer->defaultValue( idx, newFeature, evalContext );
405  }
406 
407  // 3. provider side default value clause
408  // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
409  if ( ( v.isNull() || ( hasUniqueConstraint && QgsVectorLayerUtils::valueExists( layer, idx, v ) ) )
410  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
411  {
412  int providerIndex = fields.fieldOriginIndex( idx );
413  QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
414  if ( !providerDefault.isEmpty() )
415  {
416  v = providerDefault;
417  checkUnique = false;
418  }
419  }
420 
421  // 4. provider side default literal
422  // note - deliberately not using else if!
423  if ( ( v.isNull() || ( checkUnique && hasUniqueConstraint && QgsVectorLayerUtils::valueExists( layer, idx, v ) ) )
424  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
425  {
426  int providerIndex = fields.fieldOriginIndex( idx );
427  v = layer->dataProvider()->defaultValue( providerIndex );
428  if ( v.isValid() )
429  {
430  //trust that the provider default has been sensibly set not to violate any constraints
431  checkUnique = false;
432  }
433  }
434 
435  // 5. passed attribute value
436  // note - deliberately not using else if!
437  if ( v.isNull() && attributes.contains( idx ) )
438  {
439  v = attributes.value( idx );
440  }
441 
442  // last of all... check that unique constraints are respected
443  // we can't handle not null or expression constraints here, since there's no way to pick a sensible
444  // value if the constraint is violated
445  if ( checkUnique && hasUniqueConstraint )
446  {
447  if ( QgsVectorLayerUtils::valueExists( layer, idx, v ) )
448  {
449  // unique constraint violated
450  QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValue( layer, idx, v );
451  if ( uniqueValue.isValid() )
452  v = uniqueValue;
453  }
454  }
455 
456  newFeature.setAttribute( idx, v );
457  }
458 
459  return newFeature;
460 }
461 
462 QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
463 {
464  if ( !layer )
465  return QgsFeature();
466 
467  if ( !layer->isEditable() )
468  return QgsFeature();
469 
470  //get context from layer
472  context.setFeature( feature );
473 
474  QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
475 
476  const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
477 
478  for ( const QgsRelation &relation : relations )
479  {
480  //check if composition (and not association)
481  if ( relation.strength() == QgsRelation::Composition && depth < 1 )
482  {
483  depth++;
484  //get features connected over this relation
485  QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
486  QgsFeatureIds childFeatureIds;
487  QgsFeature childFeature;
488  while ( relatedFeaturesIt.nextFeature( childFeature ) )
489  {
490  //set childlayer editable
491  relation.referencingLayer()->startEditing();
492  //change the fk of the child to the id of the new parent
493  const auto pairs = relation.fieldPairs();
494  for ( const QgsRelation::FieldPair &fieldPair : pairs )
495  {
496  childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
497  }
498  //call the function for the child
499  childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, depth, duplicateFeatureContext ).id() );
500  }
501 
502  //store for feedback
503  duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
504  }
505  }
506 
507  layer->addFeature( newFeature );
508 
509  return newFeature;
510 }
511 
512 std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
513 {
514  std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
515 
516  auto getFeatureSource = [ layer, &featureSource, feedback ]
517  {
518 #if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
519  Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
520 #else
521  Q_UNUSED( feedback )
522 #endif
523  QgsVectorLayer *lyr = layer.data();
524 
525  if ( lyr )
526  {
527  featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
528  }
529  };
530 
532 
533  return featureSource;
534 }
535 
537 {
538  if ( !feature.fields().isEmpty() )
539  {
540  QgsAttributes attributes;
541  attributes.reserve( fields.size() );
542  // feature has a field mapping, so we can match attributes to field names
543  for ( const QgsField &field : fields )
544  {
545  int index = feature.fields().lookupField( field.name() );
546  attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
547  }
548  feature.setAttributes( attributes );
549  }
550  else
551  {
552  // no field name mapping in feature, just use order
553  const int lengthDiff = feature.attributes().count() - fields.count();
554  if ( lengthDiff > 0 )
555  {
556  // truncate extra attributes
557  QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
558  feature.setAttributes( attributes );
559  }
560  else if ( lengthDiff < 0 )
561  {
562  // add missing null attributes
563  QgsAttributes attributes = feature.attributes();
564  attributes.reserve( fields.count() );
565  for ( int i = feature.attributes().count(); i < fields.count(); ++i )
566  {
567  attributes.append( QVariant( fields.at( i ).type() ) );
568  }
569  feature.setAttributes( attributes );
570  }
571  }
572 }
573 
575 {
576  QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
577  QgsFeatureList resultFeatures;
578  QgsFeature newF( feature );
579  // Fix attributes
581  // Does geometry need transformations?
583  bool newFHasGeom = newFGeomType !=
584  QgsWkbTypes::GeometryType::UnknownGeometry &&
585  newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
586  bool layerHasGeom = inputWkbType !=
587  QgsWkbTypes::Type::NoGeometry &&
588  inputWkbType != QgsWkbTypes::Type::Unknown;
589  // Drop geometry if layer is geometry-less
590  if ( newFHasGeom && ! layerHasGeom )
591  {
592  QgsFeature _f = QgsFeature( layer->fields() );
593  _f.setAttributes( newF.attributes() );
594  resultFeatures.append( _f );
595  }
596  else
597  {
598  // Geometry need fixing
599  if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType )
600  {
601  // Curved -> straight
602  if ( !QgsWkbTypes::isCurvedType( inputWkbType ) && QgsWkbTypes::isCurvedType( newF.geometry().wkbType() ) )
603  {
604  QgsGeometry newGeom( newF.geometry().constGet()->segmentize() );
605  newF.setGeometry( newGeom );
606  }
607 
608  // polygon -> line
609  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::LineGeometry &&
611  {
612  // boundary gives us a (multi)line string of exterior + interior rings
613  QgsGeometry newGeom( newF.geometry().constGet()->boundary() );
614  newF.setGeometry( newGeom );
615  }
616  // line -> polygon
619  {
620  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( inputWkbType ) );
621  const QgsGeometry source = newF.geometry();
622  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
623  {
624  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
625  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
626  {
627  if ( QgsWkbTypes::isCurvedType( inputWkbType ) )
628  {
629  std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
630  cp->setExteriorRing( curve );
631  exterior.release();
632  gc->addGeometry( cp.release() );
633  }
634  else
635  {
636  std::unique_ptr< QgsPolygon > p = qgis::make_unique< QgsPolygon >();
637  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
638  exterior.release();
639  gc->addGeometry( p.release() );
640  }
641  }
642  }
643  QgsGeometry newGeom( std::move( gc ) );
644  newF.setGeometry( newGeom );
645  }
646 
647  // line/polygon -> points
648  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::PointGeometry &&
649  ( newF.geometry().type() == QgsWkbTypes::LineGeometry ||
651  {
652  // lines/polygons to a point layer, extract all vertices
653  std::unique_ptr< QgsMultiPoint > mp = qgis::make_unique< QgsMultiPoint >();
654  const QgsGeometry source = newF.geometry();
655  QSet< QgsPoint > added;
656  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
657  {
658  if ( added.contains( *vertex ) )
659  continue; // avoid duplicate points, e.g. start/end of rings
660  mp->addGeometry( ( *vertex ).clone() );
661  added.insert( *vertex );
662  }
663  QgsGeometry newGeom( std::move( mp ) );
664  newF.setGeometry( newGeom );
665  }
666 
667  // Single -> multi
668  if ( QgsWkbTypes::isMultiType( inputWkbType ) && ! newF.geometry().isMultipart( ) )
669  {
670  QgsGeometry newGeom( newF.geometry( ) );
671  newGeom.convertToMultiType();
672  newF.setGeometry( newGeom );
673  }
674  // Drop Z/M
675  if ( newF.geometry().constGet()->is3D() && ! QgsWkbTypes::hasZ( inputWkbType ) )
676  {
677  QgsGeometry newGeom( newF.geometry( ) );
678  newGeom.get()->dropZValue();
679  newF.setGeometry( newGeom );
680  }
681  if ( newF.geometry().constGet()->isMeasure() && ! QgsWkbTypes::hasM( inputWkbType ) )
682  {
683  QgsGeometry newGeom( newF.geometry( ) );
684  newGeom.get()->dropMValue();
685  newF.setGeometry( newGeom );
686  }
687  // Add Z/M back, set to 0
688  if ( ! newF.geometry().constGet()->is3D() && QgsWkbTypes::hasZ( inputWkbType ) )
689  {
690  QgsGeometry newGeom( newF.geometry( ) );
691  newGeom.get()->addZValue( 0.0 );
692  newF.setGeometry( newGeom );
693  }
694  if ( ! newF.geometry().constGet()->isMeasure() && QgsWkbTypes::hasM( inputWkbType ) )
695  {
696  QgsGeometry newGeom( newF.geometry( ) );
697  newGeom.get()->addMValue( 0.0 );
698  newF.setGeometry( newGeom );
699  }
700  // Multi -> single
701  if ( ! QgsWkbTypes::isMultiType( inputWkbType ) && newF.geometry().isMultipart( ) )
702  {
703  QgsGeometry newGeom( newF.geometry( ) );
704  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
705  QgsAttributeMap attrMap;
706  for ( int j = 0; j < newF.fields().count(); j++ )
707  {
708  attrMap[j] = newF.attribute( j );
709  }
710  resultFeatures.reserve( parts->partCount() );
711  for ( int i = 0; i < parts->partCount( ); i++ )
712  {
713  QgsGeometry g( parts->geometryN( i )->clone() );
714  QgsFeature _f( createFeature( layer, g, attrMap ) );
715  resultFeatures.append( _f );
716  }
717  }
718  else
719  {
720  resultFeatures.append( newF );
721  }
722  }
723  else
724  {
725  resultFeatures.append( newF );
726  }
727  }
728  return resultFeatures;
729 }
730 
732 {
733  QgsFeatureList resultFeatures;
734  for ( const QgsFeature &f : features )
735  {
736  const QgsFeatureList features( makeFeatureCompatible( f, layer ) );
737  for ( const auto &_f : features )
738  {
739  resultFeatures.append( _f );
740  }
741  }
742  return resultFeatures;
743 }
744 
746 {
747  QList<QgsVectorLayer *> layers;
748  QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
749  for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
750  layers.append( i.key() );
751  return layers;
752 }
753 
755 {
756  return mDuplicatedFeatures[layer];
757 }
758 
759 void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
760 {
761  mDuplicatedFeatures.insert( layer, ids );
762 }
763 /*
764 QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
765 {
766  return mDuplicatedFeatures;
767 }
768 */
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
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 QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString name
Definition: qgsfield.h:57
static std::unique_ptr< QgsVectorLayerFeatureSource > getFeatureSource(QPointer< QgsVectorLayer > layer, QgsFeedback *feedback=nullptr)
Gets the feature source from a QgsVectorLayer pointer.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:695
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features...
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
ConstraintOrigin
Origin of 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.
QVariant evaluate()
Evaluate the feature and return the result.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
Container of fields for a vector layer.
Definition: qgsfields.h:42
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
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.
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Stores information about constraints which may be present on a field.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:49
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static bool validateAttribute(const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthNotSet, QgsFieldConstraints::ConstraintOrigin origin=QgsFieldConstraints::ConstraintOriginNotSet)
Tests an attribute value to check whether it passes all constraints which are present on the correspo...
QgsFields fields
Definition: qgsfeature.h:66
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:906
static QgsFeatureIterator getValuesIterator(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly)
Create a feature iterator for a specified field name or expression.
Constraint was set at data provider.
Field has an expression constraint set. See constraintExpression().
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:44
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
bool isMeasure() const
Returns true if the geometry contains m values.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:74
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
Geometry collection.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:202
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
void seed(uint32_t value)
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:801
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
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.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Reads and writes project states.
Definition: qgsproject.h:89
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
QString constraintExpression() const
Returns the constraint expression for the field, if set.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:320
QgsRelationManager relationManager
Definition: qgsproject.h:100
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static bool runOnMainThread(const Func &func, QgsFeedback *feedback=nullptr)
Guarantees that func is executed on the main thread.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field...
static QgsFeatureList makeFeaturesCompatible(const QgsFeatureList &features, const QgsVectorLayer *layer)
Converts input features to be compatible with the given layer.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
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...
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:138
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
QgsFieldConstraints constraints
Definition: qgsfield.h:60
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:272
ConstraintStrength
Strength of constraints.
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext)
Duplicates a feature and it&#39;s children (one level deep).
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:744
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...
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index...
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
bool isNumeric
Definition: qgsfield.h:52
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:956
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
bool nextFeature(QgsFeature &f)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
static QgsFeatureList makeFeatureCompatible(const QgsFeature &feature, const QgsVectorLayer *layer)
Converts input feature to be compatible with the given layer.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsattributes.h:57
virtual QString defaultValueClause(int fieldIndex) const
Returns any default value clauses which are present at the provider for a specified field index...
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error...
Represents a vector layer which manages a vector based data sets.
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QVariant::Type type
Definition: qgsfield.h:55
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
QgsAttributes attributes
Definition: qgsfeature.h:65
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
Definition: qgsrelation.h:60
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Field must have a unique value.
bool isValid() const
Returns if this default value should be applied.