QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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"
30 #include "qgsmultisurface.h"
31 #include "qgsgeometryfactory.h"
32 #include "qgscurvepolygon.h"
33 #include "qgspolygon.h"
34 #include "qgslinestring.h"
35 #include "qgsmultipoint.h"
37 
38 QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
39 {
40  std::unique_ptr<QgsExpression> expression;
41  QgsExpressionContext context;
42 
43  int attrNum = layer->fields().lookupField( fieldOrExpression );
44  if ( attrNum == -1 )
45  {
46  // try to use expression
47  expression.reset( new QgsExpression( fieldOrExpression ) );
49 
50  if ( expression->hasParserError() || !expression->prepare( &context ) )
51  {
52  ok = false;
53  return QgsFeatureIterator();
54  }
55  }
56 
57  QSet<QString> lst;
58  if ( !expression )
59  lst.insert( fieldOrExpression );
60  else
61  lst = expression->referencedColumns();
62 
64  .setFlags( ( expression && expression->needsGeometry() ) ?
67  .setSubsetOfAttributes( lst, layer->fields() );
68 
69  ok = true;
70  if ( !selectedOnly )
71  {
72  return layer->getFeatures( request );
73  }
74  else
75  {
76  return layer->getSelectedFeatures( request );
77  }
78 }
79 
80 QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
81 {
82  QList<QVariant> values;
83  QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
84  if ( ok )
85  {
86  std::unique_ptr<QgsExpression> expression;
87  QgsExpressionContext context;
88 
89  int attrNum = layer->fields().lookupField( fieldOrExpression );
90  if ( attrNum == -1 )
91  {
92  // use expression, already validated in the getValuesIterator() function
93  expression.reset( new QgsExpression( fieldOrExpression ) );
95  }
96 
97  QgsFeature f;
98  while ( fit.nextFeature( f ) )
99  {
100  if ( expression )
101  {
102  context.setFeature( f );
103  QVariant v = expression->evaluate( &context );
104  values << v;
105  }
106  else
107  {
108  values << f.attribute( attrNum );
109  }
110  if ( feedback && feedback->isCanceled() )
111  {
112  ok = false;
113  return values;
114  }
115  }
116  }
117  return values;
118 }
119 
120 QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
121 {
122  QList<double> values;
123 
124  if ( nullCount )
125  *nullCount = 0;
126 
127  QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
128  if ( !ok )
129  return values;
130 
131  bool convertOk;
132  const auto constVariantValues = variantValues;
133  for ( const QVariant &value : constVariantValues )
134  {
135  double val = value.toDouble( &convertOk );
136  if ( convertOk )
137  values << val;
138  else if ( value.isNull() )
139  {
140  if ( nullCount )
141  *nullCount += 1;
142  }
143  if ( feedback && feedback->isCanceled() )
144  {
145  ok = false;
146  return values;
147  }
148  }
149  return values;
150 }
151 
152 bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
153 {
154  if ( !layer )
155  return false;
156 
157  QgsFields fields = layer->fields();
158 
159  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
160  return false;
161 
162  QString fieldName = fields.at( fieldIndex ).name();
163 
164  // build up an optimised feature request
165  QgsFeatureRequest request;
166  request.setNoAttributes();
168 
169  // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
170  int limit = ignoreIds.size() + 1;
171  request.setLimit( limit );
172 
173  request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
174  QgsExpression::quotedValue( value ) ) );
175 
176  QgsFeature feat;
177  QgsFeatureIterator it = layer->getFeatures( request );
178  while ( it.nextFeature( feat ) )
179  {
180  if ( ignoreIds.contains( feat.id() ) )
181  continue;
182 
183  return true;
184  }
185 
186  return false;
187 }
188 
189 QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
190 {
191  if ( !layer )
192  return QVariant();
193 
194  QgsFields fields = layer->fields();
195 
196  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
197  return QVariant();
198 
199  QgsField field = fields.at( fieldIndex );
200 
201  if ( field.isNumeric() )
202  {
203  QVariant maxVal = layer->maximumValue( fieldIndex );
204  QVariant newVar( maxVal.toLongLong() + 1 );
205  if ( field.convertCompatible( newVar ) )
206  return newVar;
207  else
208  return QVariant();
209  }
210  else
211  {
212  switch ( field.type() )
213  {
214  case QVariant::String:
215  {
216  QString base;
217  if ( seed.isValid() )
218  base = seed.toString();
219 
220  if ( !base.isEmpty() )
221  {
222  // strip any existing _1, _2 from the seed
223  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
224  QRegularExpressionMatch match = rx.match( base );
225  if ( match.hasMatch() )
226  {
227  base = match.captured( 1 );
228  }
229  }
230  else
231  {
232  // no base seed - fetch first value from layer
233  QgsFeatureRequest req;
234  req.setLimit( 1 );
235  req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
237  QgsFeature f;
238  layer->getFeatures( req ).nextFeature( f );
239  base = f.attribute( fieldIndex ).toString();
240  }
241 
242  // try variants like base_1, base_2, etc until a new value found
243  QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
244 
245  // might already be unique
246  if ( !base.isEmpty() && !vals.contains( base ) )
247  return base;
248 
249  for ( int i = 1; i < 10000; ++i )
250  {
251  QString testVal = base + '_' + QString::number( i );
252  if ( !vals.contains( testVal ) )
253  return testVal;
254  }
255 
256  // failed
257  return QVariant();
258  }
259 
260  default:
261  // todo other types - dates? times?
262  break;
263  }
264  }
265 
266  return QVariant();
267 }
268 
269 QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
270 {
271  if ( !layer )
272  return QVariant();
273 
274  QgsFields fields = layer->fields();
275 
276  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
277  return QVariant();
278 
279  QgsField field = fields.at( fieldIndex );
280 
281  if ( field.isNumeric() )
282  {
283  QVariant maxVal = existingValues.isEmpty() ? 0 : *std::max_element( existingValues.begin(), existingValues.end() );
284  QVariant newVar( maxVal.toLongLong() + 1 );
285  if ( field.convertCompatible( newVar ) )
286  return newVar;
287  else
288  return QVariant();
289  }
290  else
291  {
292  switch ( field.type() )
293  {
294  case QVariant::String:
295  {
296  QString base;
297  if ( seed.isValid() )
298  base = seed.toString();
299 
300  if ( !base.isEmpty() )
301  {
302  // strip any existing _1, _2 from the seed
303  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
304  QRegularExpressionMatch match = rx.match( base );
305  if ( match.hasMatch() )
306  {
307  base = match.captured( 1 );
308  }
309  }
310  else
311  {
312  // no base seed - fetch first value from layer
313  QgsFeatureRequest req;
314  base = existingValues.isEmpty() ? QString() : existingValues.values().first().toString();
315  }
316 
317  // try variants like base_1, base_2, etc until a new value found
318  QStringList vals;
319  for ( const auto &v : qgis::as_const( existingValues ) )
320  {
321  if ( v.toString().startsWith( base ) )
322  vals.push_back( v.toString() );
323  }
324 
325  // might already be unique
326  if ( !base.isEmpty() && !vals.contains( base ) )
327  return base;
328 
329  for ( int i = 1; i < 10000; ++i )
330  {
331  QString testVal = base + '_' + QString::number( i );
332  if ( !vals.contains( testVal ) )
333  return testVal;
334  }
335 
336  // failed
337  return QVariant();
338  }
339 
340  default:
341  // todo other types - dates? times?
342  break;
343  }
344  }
345 
346  return QVariant();
347 
348 }
349 
350 bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
352 {
353  if ( !layer )
354  return false;
355 
356  if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
357  return false;
358 
359  QgsFields fields = layer->fields();
360  QgsField field = fields.at( attributeIndex );
361  QVariant value = feature.attribute( attributeIndex );
362  bool valid = true;
363  errors.clear();
364 
365  QgsFieldConstraints constraints = field.constraints();
366 
367  if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
370  {
372  context.setFeature( feature );
373 
374  QgsExpression expr( constraints.constraintExpression() );
375 
376  valid = expr.evaluate( &context ).toBool();
377 
378  if ( expr.hasParserError() )
379  {
380  errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
381  }
382  else if ( expr.hasEvalError() )
383  {
384  errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
385  }
386  else if ( !valid )
387  {
388  errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
389  }
390  }
391 
395  {
396  bool exempt = false;
397  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
399  {
400  int providerIdx = fields.fieldOriginIndex( attributeIndex );
401  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
402  }
403 
404  if ( !exempt )
405  {
406  valid = valid && !value.isNull();
407 
408  if ( value.isNull() )
409  {
410  errors << QObject::tr( "value is NULL" );
411  }
412  }
413  }
414 
418  {
419  bool exempt = false;
420  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
422  {
423  int providerIdx = fields.fieldOriginIndex( attributeIndex );
424  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
425  }
426 
427  if ( !exempt )
428  {
429  bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
430  valid = valid && !alreadyExists;
431 
432  if ( alreadyExists )
433  {
434  errors << QObject::tr( "value is not unique" );
435  }
436  }
437  }
438 
439  return valid;
440 }
441 
443  const QgsAttributeMap &attributes, QgsExpressionContext *context )
444 {
445  QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
446  return features.isEmpty() ? QgsFeature() : features.first();
447 }
448 
450 {
451  if ( !layer )
452  return QgsFeatureList();
453 
454  QgsFeatureList result;
455  result.reserve( featuresData.length() );
456 
457  QgsExpressionContext *evalContext = context;
458  std::unique_ptr< QgsExpressionContext > tempContext;
459  if ( !evalContext )
460  {
461  // no context passed, so we create a default one
463  evalContext = tempContext.get();
464  }
465 
466  QgsFields fields = layer->fields();
467 
468  // Cache unique values
469  QMap<int, QSet<QVariant>> uniqueValueCaches;
470 
471  for ( const auto &fd : qgis::as_const( featuresData ) )
472  {
473 
474  QgsFeature newFeature( fields );
475  newFeature.setValid( true );
476  newFeature.setGeometry( fd.geometry() );
477 
478  // initialize attributes
479  newFeature.initAttributes( fields.count() );
480  for ( int idx = 0; idx < fields.count(); ++idx )
481  {
482  QVariant v;
483  bool checkUnique = true;
484  const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
485 
486  // in order of priority:
487  // 1. passed attribute value and if field does not have a unique constraint like primary key
488  if ( fd.attributes().contains( idx ) )
489  {
490  v = fd.attributes().value( idx );
491  }
492 
493  // Cache unique values
494  if ( hasUniqueConstraint && ! uniqueValueCaches.contains( idx ) )
495  {
496  // If the layer is filtered, get unique values from an unfiltered clone
497  if ( ! layer->subsetString().isEmpty() )
498  {
499  std::unique_ptr<QgsVectorLayer> unfilteredClone { layer->clone( ) };
500  unfilteredClone->setSubsetString( QString( ) );
501  uniqueValueCaches[ idx ] = unfilteredClone->uniqueValues( idx );
502  }
503  else
504  {
505  uniqueValueCaches[ idx ] = layer->uniqueValues( idx );
506  }
507  }
508 
509  // 2. client side default expression
510  // note - deliberately not using else if!
511  QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
512  if ( ( v.isNull() || ( hasUniqueConstraint
513  && uniqueValueCaches[ idx ].contains( v ) )
514  || defaultValueDefinition.applyOnUpdate() )
515  && defaultValueDefinition.isValid() )
516  {
517  // client side default expression set - takes precedence over all. Why? Well, this is the only default
518  // which QGIS users have control over, so we assume that they're deliberately overriding any
519  // provider defaults for some good reason and we should respect that
520  v = layer->defaultValue( idx, newFeature, evalContext );
521  }
522 
523  // 3. provider side default value clause
524  // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
525  if ( ( v.isNull() || ( hasUniqueConstraint
526  && uniqueValueCaches[ idx ].contains( v ) ) )
527  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
528  {
529  int providerIndex = fields.fieldOriginIndex( idx );
530  QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
531  if ( !providerDefault.isEmpty() )
532  {
533  v = providerDefault;
534  checkUnique = false;
535  }
536  }
537 
538  // 4. provider side default literal
539  // note - deliberately not using else if!
540  if ( ( v.isNull() || ( checkUnique && hasUniqueConstraint
541  && uniqueValueCaches[ idx ].contains( v ) ) )
542  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
543  {
544  int providerIndex = fields.fieldOriginIndex( idx );
545  v = layer->dataProvider()->defaultValue( providerIndex );
546  if ( v.isValid() )
547  {
548  //trust that the provider default has been sensibly set not to violate any constraints
549  checkUnique = false;
550  }
551  }
552 
553  // 5. passed attribute value
554  // note - deliberately not using else if!
555  if ( v.isNull() && fd.attributes().contains( idx ) )
556  {
557  v = fd.attributes().value( idx );
558  }
559 
560  // last of all... check that unique constraints are respected
561  // we can't handle not null or expression constraints here, since there's no way to pick a sensible
562  // value if the constraint is violated
563  if ( checkUnique && hasUniqueConstraint )
564  {
565  if ( uniqueValueCaches[ idx ].contains( v ) )
566  {
567  // unique constraint violated
568  QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCaches[ idx ], v );
569  if ( uniqueValue.isValid() )
570  v = uniqueValue;
571  }
572  }
573  if ( hasUniqueConstraint )
574  uniqueValueCaches[ idx ].insert( v );
575  newFeature.setAttribute( idx, v );
576  }
577  result.append( newFeature );
578  }
579  return result;
580 }
581 
582 QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
583 {
584  if ( !layer )
585  return QgsFeature();
586 
587  if ( !layer->isEditable() )
588  return QgsFeature();
589 
590  //get context from layer
592  context.setFeature( feature );
593 
594  QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
595 
596  const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
597 
598  for ( const QgsRelation &relation : relations )
599  {
600  //check if composition (and not association)
601  if ( relation.strength() == QgsRelation::Composition && depth < 1 )
602  {
603  depth++;
604  //get features connected over this relation
605  QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
606  QgsFeatureIds childFeatureIds;
607  QgsFeature childFeature;
608  while ( relatedFeaturesIt.nextFeature( childFeature ) )
609  {
610  //set childlayer editable
611  relation.referencingLayer()->startEditing();
612  //change the fk of the child to the id of the new parent
613  const auto pairs = relation.fieldPairs();
614  for ( const QgsRelation::FieldPair &fieldPair : pairs )
615  {
616  childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
617  }
618  //call the function for the child
619  childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, depth, duplicateFeatureContext ).id() );
620  }
621 
622  //store for feedback
623  duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
624  }
625  }
626 
627  layer->addFeature( newFeature );
628 
629  return newFeature;
630 }
631 
632 std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
633 {
634  std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
635 
636  auto getFeatureSource = [ layer, &featureSource, feedback ]
637  {
638 #if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
639  Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
640 #else
641  Q_UNUSED( feedback )
642 #endif
643  QgsVectorLayer *lyr = layer.data();
644 
645  if ( lyr )
646  {
647  featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
648  }
649  };
650 
652 
653  return featureSource;
654 }
655 
657 {
658  if ( !feature.fields().isEmpty() )
659  {
660  QgsAttributes attributes;
661  attributes.reserve( fields.size() );
662  // feature has a field mapping, so we can match attributes to field names
663  for ( const QgsField &field : fields )
664  {
665  int index = feature.fields().lookupField( field.name() );
666  attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
667  }
668  feature.setAttributes( attributes );
669  }
670  else
671  {
672  // no field name mapping in feature, just use order
673  const int lengthDiff = feature.attributes().count() - fields.count();
674  if ( lengthDiff > 0 )
675  {
676  // truncate extra attributes
677  QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
678  feature.setAttributes( attributes );
679  }
680  else if ( lengthDiff < 0 )
681  {
682  // add missing null attributes
683  QgsAttributes attributes = feature.attributes();
684  attributes.reserve( fields.count() );
685  for ( int i = feature.attributes().count(); i < fields.count(); ++i )
686  {
687  attributes.append( QVariant( fields.at( i ).type() ) );
688  }
689  feature.setAttributes( attributes );
690  }
691  }
692  feature.setFields( fields );
693 }
694 
696 {
697  QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
698  QgsFeatureList resultFeatures;
699  QgsFeature newF( feature );
700  // Fix attributes
702  // Does geometry need transformations?
704  bool newFHasGeom = newFGeomType !=
705  QgsWkbTypes::GeometryType::UnknownGeometry &&
706  newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
707  bool layerHasGeom = inputWkbType !=
708  QgsWkbTypes::Type::NoGeometry &&
709  inputWkbType != QgsWkbTypes::Type::Unknown;
710  // Drop geometry if layer is geometry-less
711  if ( newFHasGeom && ! layerHasGeom )
712  {
713  QgsFeature _f = QgsFeature( layer->fields() );
714  _f.setAttributes( newF.attributes() );
715  resultFeatures.append( _f );
716  }
717  else
718  {
719  // Geometry need fixing
720  if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType )
721  {
722  // Curved -> straight
723  if ( !QgsWkbTypes::isCurvedType( inputWkbType ) && QgsWkbTypes::isCurvedType( newF.geometry().wkbType() ) )
724  {
725  QgsGeometry newGeom( newF.geometry().constGet()->segmentize() );
726  newF.setGeometry( newGeom );
727  }
728 
729  // polygon -> line
730  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::LineGeometry &&
732  {
733  // boundary gives us a (multi)line string of exterior + interior rings
734  QgsGeometry newGeom( newF.geometry().constGet()->boundary() );
735  newF.setGeometry( newGeom );
736  }
737  // line -> polygon
740  {
741  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( inputWkbType ) );
742  const QgsGeometry source = newF.geometry();
743  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
744  {
745  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
746  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
747  {
748  if ( QgsWkbTypes::isCurvedType( inputWkbType ) )
749  {
750  std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
751  cp->setExteriorRing( curve );
752  exterior.release();
753  gc->addGeometry( cp.release() );
754  }
755  else
756  {
757  std::unique_ptr< QgsPolygon > p = qgis::make_unique< QgsPolygon >();
758  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
759  exterior.release();
760  gc->addGeometry( p.release() );
761  }
762  }
763  }
764  QgsGeometry newGeom( std::move( gc ) );
765  newF.setGeometry( newGeom );
766  }
767 
768  // line/polygon -> points
769  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::PointGeometry &&
770  ( newF.geometry().type() == QgsWkbTypes::LineGeometry ||
772  {
773  // lines/polygons to a point layer, extract all vertices
774  std::unique_ptr< QgsMultiPoint > mp = qgis::make_unique< QgsMultiPoint >();
775  const QgsGeometry source = newF.geometry();
776  QSet< QgsPoint > added;
777  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
778  {
779  if ( added.contains( *vertex ) )
780  continue; // avoid duplicate points, e.g. start/end of rings
781  mp->addGeometry( ( *vertex ).clone() );
782  added.insert( *vertex );
783  }
784  QgsGeometry newGeom( std::move( mp ) );
785  newF.setGeometry( newGeom );
786  }
787 
788  // Single -> multi
789  if ( QgsWkbTypes::isMultiType( inputWkbType ) && ! newF.geometry().isMultipart( ) )
790  {
791  QgsGeometry newGeom( newF.geometry( ) );
792  newGeom.convertToMultiType();
793  newF.setGeometry( newGeom );
794  }
795  // Drop Z/M
796  if ( newF.geometry().constGet()->is3D() && ! QgsWkbTypes::hasZ( inputWkbType ) )
797  {
798  QgsGeometry newGeom( newF.geometry( ) );
799  newGeom.get()->dropZValue();
800  newF.setGeometry( newGeom );
801  }
802  if ( newF.geometry().constGet()->isMeasure() && ! QgsWkbTypes::hasM( inputWkbType ) )
803  {
804  QgsGeometry newGeom( newF.geometry( ) );
805  newGeom.get()->dropMValue();
806  newF.setGeometry( newGeom );
807  }
808  // Add Z/M back, set to 0
809  if ( ! newF.geometry().constGet()->is3D() && QgsWkbTypes::hasZ( inputWkbType ) )
810  {
811  QgsGeometry newGeom( newF.geometry( ) );
812  newGeom.get()->addZValue( 0.0 );
813  newF.setGeometry( newGeom );
814  }
815  if ( ! newF.geometry().constGet()->isMeasure() && QgsWkbTypes::hasM( inputWkbType ) )
816  {
817  QgsGeometry newGeom( newF.geometry( ) );
818  newGeom.get()->addMValue( 0.0 );
819  newF.setGeometry( newGeom );
820  }
821  // Multi -> single
822  if ( ! QgsWkbTypes::isMultiType( inputWkbType ) && newF.geometry().isMultipart( ) )
823  {
824  QgsGeometry newGeom( newF.geometry( ) );
825  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
826  QgsAttributeMap attrMap;
827  for ( int j = 0; j < newF.fields().count(); j++ )
828  {
829  attrMap[j] = newF.attribute( j );
830  }
831  resultFeatures.reserve( parts->partCount() );
832  for ( int i = 0; i < parts->partCount( ); i++ )
833  {
834  QgsGeometry g( parts->geometryN( i )->clone() );
835  QgsFeature _f( createFeature( layer, g, attrMap ) );
836  resultFeatures.append( _f );
837  }
838  }
839  else
840  {
841  resultFeatures.append( newF );
842  }
843  }
844  else
845  {
846  resultFeatures.append( newF );
847  }
848  }
849  return resultFeatures;
850 }
851 
853 {
854  QgsFeatureList resultFeatures;
855  for ( const QgsFeature &f : features )
856  {
857  const QgsFeatureList features( makeFeatureCompatible( f, layer ) );
858  for ( const auto &_f : features )
859  {
860  resultFeatures.append( _f );
861  }
862  }
863  return resultFeatures;
864 }
865 
867 {
868  QList<QgsVectorLayer *> layers;
869  QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
870  for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
871  layers.append( i.key() );
872  return layers;
873 }
874 
876 {
877  return mDuplicatedFeatures[layer];
878 }
879 
880 void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
881 {
882  mDuplicatedFeatures.insert( layer, ids );
883 }
884 /*
885 QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
886 {
887  return mDuplicatedFeatures;
888 }
889 */
890 
892  mGeometry( geometry ),
893  mAttributes( attributes )
894 {}
895 
897 {
898  return mGeometry;
899 }
900 
902 {
903  return mAttributes;
904 }
905 
906 bool _fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
907 {
908  return layer->isEditable() &&
909  !layer->editFormConfig().readOnly( fieldIndex ) &&
910  ( ( layer->dataProvider() && layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) || FID_IS_NEW( feature.id() ) );
911 }
912 
913 bool QgsVectorLayerUtils::fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
914 {
915  if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
916  {
917  int srcFieldIndex;
918  const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
919 
920  if ( !info || !info->isEditable() )
921  return false;
922 
923  // check that joined feature exist, else it is not editable
924  if ( !info->hasUpsertOnEdit() )
925  {
926  const QgsFeature joinedFeature = layer->joinBuffer()->joinedFeatureOf( info, feature );
927  if ( !joinedFeature.isValid() )
928  return false;
929  }
930 
931  return _fieldIsEditable( info->joinLayer(), srcFieldIndex, feature );
932  }
933  else
934  return _fieldIsEditable( layer, fieldIndex, feature );
935 }
bool isMeasure() const
Returns true if the geometry contains m values.
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
bool _fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
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.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:50
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.
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:162
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
QString name
Definition: qgsfield.h:58
bool isValid() const
Returns if this default value should be applied.
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:706
The QgsDefaultValue class provides a container for managing client side default values for fields...
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features...
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
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
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
QVariant evaluate()
Evaluate the feature and return the result.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:281
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
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:122
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
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
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:917
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().
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:44
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...
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
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
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.
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
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet) ...
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
static QVariant createUniqueValueFromCache(const QgsVectorLayer *layer, int fieldIndex, const QSet< QVariant > &existingValues, const QVariant &seed=QVariant())
Returns a new attribute value for the specified field index which is guaranteed to be unique within r...
Geometry collection.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureData(const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap())
Constructs a new QgsFeatureData with given geometry and attributes.
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
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...
QgsAttributeMap attributes() const
Returns attributes.
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.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
Defines left outer join from our vector layer to some other vector layer.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
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:812
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual QString defaultValueClause(int fieldIndex) const
Returns any default value clauses which are present at the provider for a specified field index...
QString subsetString
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:89
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
QgsRelationManager relationManager
Definition: qgsproject.h:100
QgsEditFormConfig editFormConfig
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.
static QgsFeatureList makeFeaturesCompatible(const QgsFeatureList &features, const QgsVectorLayer *layer)
Converts input features to be compatible with the given layer.
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (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...
QgsGeometry geometry() const
Returns geometry.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
#define FID_IS_NEW(fid)
Definition: qgsfeatureid.h:28
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field...
QgsFieldConstraints constraints
Definition: qgsfield.h:61
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
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:755
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsFeature joinedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const
Returns the joined feature corresponding to the feature.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries 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:967
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:126
QgsGeometry geometry
Definition: qgsfeature.h:67
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
bool nextFeature(QgsFeature &f)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
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
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.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Allows modification of attribute values.
QVariant::Type type
Definition: qgsfield.h:56
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
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
Field must have a unique value.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index...