QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsvectorlayereditbuffer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayereditbuffer.cpp
3  ---------------------
4  begin : Dezember 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk 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  ***************************************************************************/
16 
17 #include "qgsgeometry.h"
18 #include "qgslogger.h"
20 #include "qgsvectordataprovider.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsvectorlayerutils.h"
23 
25 template <class Key, class T> void mapToReversedLists( const QMap< Key, T > &map, QList<Key> &ks, QList<T> &vs )
26 {
27  ks.reserve( map.size() );
28  vs.reserve( map.size() );
29  typename QMap<Key, T>::const_iterator i = map.constEnd();
30  while ( i-- != map.constBegin() )
31  {
32  ks.append( i.key() );
33  vs.append( i.value() );
34  }
35 }
36 
37 
39  : L( layer )
40 {
41  connect( L->undoStack(), &QUndoStack::indexChanged, this, &QgsVectorLayerEditBuffer::undoIndexChanged ); // TODO[MD]: queued?
42 }
43 
45 {
46  return !L->undoStack()->isClean();
47 }
48 
49 
51 {
52  QgsDebugMsgLevel( QStringLiteral( "undo index changed %1" ).arg( index ), 4 );
53  Q_UNUSED( index );
54  emit layerModified();
55 }
56 
57 
59 {
60  // delete attributes from the higher indices to lower indices
61  for ( int i = mDeletedAttributeIds.count() - 1; i >= 0; --i )
62  {
63  fields.remove( mDeletedAttributeIds.at( i ) );
64  }
65 
66  // rename fields
67  QgsFieldNameMap::const_iterator renameIt = mRenamedAttributes.constBegin();
68  for ( ; renameIt != mRenamedAttributes.constEnd(); ++renameIt )
69  {
70  fields.rename( renameIt.key(), renameIt.value() );
71  }
72 
73  // add new fields
74  for ( int i = 0; i < mAddedAttributes.count(); ++i )
75  {
76  fields.append( mAddedAttributes.at( i ), QgsFields::OriginEdit, i );
77  }
78 }
79 
80 
82 {
83  if ( mChangedGeometries.contains( f.id() ) )
85 }
86 
87 
89 {
90  QgsAttributes attrs = f.attributes();
91 
92  // remove all attributes that will disappear - from higher indices to lower
93  for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
94  {
95  attrs.remove( mDeletedAttributeIds[idx] );
96  }
97 
98  // adjust size to accommodate added attributes
99  attrs.resize( attrs.count() + mAddedAttributes.count() );
100 
101  // update changed attributes
102  if ( mChangedAttributeValues.contains( f.id() ) )
103  {
104  const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
105  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
106  attrs[it.key()] = it.value();
107  }
108 
109  f.setAttributes( attrs );
110 }
111 
112 
113 
114 
116 {
118  {
119  return false;
120  }
121  if ( L->mFields.count() != f.attributes().count() )
122  return false;
123 
124  // TODO: check correct geometry type
125 
126  L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
127  return true;
128 }
129 
130 
132 {
134  return false;
135 
136  bool result = true;
137  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
138  {
139  result = result && addFeature( *iter );
140  }
141 
142  L->updateExtents();
143  return result;
144 }
145 
146 
147 
149 {
151  {
152  QgsDebugMsg( QStringLiteral( "Cannot delete features (missing DeleteFeature capability)" ) );
153  return false;
154  }
155 
156  if ( FID_IS_NEW( fid ) )
157  {
158  if ( !mAddedFeatures.contains( fid ) )
159  {
160  QgsDebugMsg( QStringLiteral( "Cannot delete features (in the list of added features)" ) );
161  return false;
162  }
163  }
164  else // existing feature
165  {
166  if ( mDeletedFeatureIds.contains( fid ) )
167  {
168  QgsDebugMsg( QStringLiteral( "Cannot delete features (in the list of deleted features)" ) );
169  return false;
170  }
171  }
172 
173  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
174  return true;
175 }
176 
178 {
180  {
181  QgsDebugMsg( QStringLiteral( "Cannot delete features (missing DeleteFeatures capability)" ) );
182  return false;
183  }
184 
185  bool ok = true;
186  Q_FOREACH ( QgsFeatureId fid, fids )
187  ok = deleteFeature( fid ) && ok;
188 
189  return ok;
190 }
191 
192 
194 {
195  if ( !L->isSpatial() )
196  {
197  return false;
198  }
199 
200  if ( FID_IS_NEW( fid ) )
201  {
202  if ( !mAddedFeatures.contains( fid ) )
203  return false;
204  }
206  return false;
207 
208  // TODO: check compatible geometry
209 
210  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
211  return true;
212 }
213 
215 {
216  bool success = true;
217  for ( auto it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
218  {
219  const int field = it.key();
220  const QVariant newValue = it.value();
221  QVariant oldValue;
222 
223  if ( oldValues.contains( field ) )
224  oldValue = oldValues[field];
225 
226  success &= changeAttributeValue( fid, field, newValue, oldValue );
227  }
228 
229  return success;
230 }
231 
232 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
233 {
234  if ( FID_IS_NEW( fid ) )
235  {
236  if ( !mAddedFeatures.contains( fid ) )
237  return false;
238  }
240  {
241  return false;
242  }
243 
244  if ( field < 0 || field >= L->fields().count() ||
245  L->fields().fieldOrigin( field ) == QgsFields::OriginJoin ||
247  return false;
248 
249  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
250  return true;
251 }
252 
253 
255 {
257  return false;
258 
259  if ( field.name().isEmpty() )
260  return false;
261 
262  const QgsFields fields = L->fields();
263  for ( const QgsField &updatedField : fields )
264  {
265  if ( updatedField.name() == field.name() )
266  return false;
267  }
268 
269  if ( !L->dataProvider()->supportedType( field ) )
270  return false;
271 
272  L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
273  return true;
274 }
275 
276 
278 {
280  return false;
281 
282  if ( index < 0 || index >= L->fields().count() )
283  return false;
284 
285  // find out source of the field
286  QgsFields::FieldOrigin origin = L->fields().fieldOrigin( index );
287  int originIndex = L->fields().fieldOriginIndex( index );
288 
289  if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
290  return false;
291 
292  if ( origin == QgsFields::OriginJoin )
293  return false;
294 
295  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
296  return true;
297 }
298 
299 bool QgsVectorLayerEditBuffer::renameAttribute( int index, const QString &newName )
300 {
302  return false;
303 
304  if ( newName.isEmpty() )
305  return false;
306 
307  if ( index < 0 || index >= L->fields().count() )
308  return false;
309 
310  const QgsFields fields = L->fields();
311  for ( const QgsField &updatedField : fields )
312  {
313  if ( updatedField.name() == newName )
314  return false;
315  }
316 
317  L->undoStack()->push( new QgsVectorLayerUndoCommandRenameAttribute( this, index, newName ) );
318  return true;
319 }
320 
321 
322 bool QgsVectorLayerEditBuffer::commitChanges( QStringList &commitErrors )
323 {
324  QgsVectorDataProvider *provider = L->dataProvider();
325  commitErrors.clear();
326 
327  int cap = provider->capabilities();
328  bool success = true;
329 
330  // geometry updates attribute updates
331  // yes no => changeGeometryValues
332  // no yes => changeAttributeValues
333  // yes yes => changeFeatures
334 
335  // to fix https://issues.qgis.org/issues/15741
336  // first of all check if feature to add is compatible with provider type
337  // this check have to be done before all checks to avoid to clear internal
338  // buffer if some of next steps success.
339  if ( success && !mAddedFeatures.isEmpty() )
340  {
342  {
343  if ( provider->doesStrictFeatureTypeCheck() )
344  {
345  for ( const auto &f : qgis::as_const( mAddedFeatures ) )
346  {
347  if ( ( ! f.hasGeometry() ) ||
348  ( f.geometry().wkbType() == provider->wkbType() ) )
349  continue;
350 
351  if ( provider->convertToProviderType( f.geometry() ).isNull() )
352  {
353  commitErrors << tr( "ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.", "not added features count", mAddedFeatures.size() );
354  success = false;
355  break;
356  }
357  }
358  }
359  }
360  else
361  {
362  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
363  success = false;
364  }
365  }
366 
367  //
368  // update geometries
369  //
370  if ( !mChangedGeometries.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
371  {
372  if ( provider->changeGeometryValues( mChangedGeometries ) )
373  {
374  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
375 
377  mChangedGeometries.clear();
378  }
379  else
380  {
381  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
382  success = false;
383  }
384  }
385 
386  QgsFields oldFields = L->fields();
387 
388  //
389  // delete attributes
390  //
391  bool attributesChanged = false;
392  if ( !mDeletedAttributeIds.isEmpty() )
393  {
394  if ( ( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( mDeletedAttributeIds.toSet() ) )
395  {
396  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
397 
399 
400  mDeletedAttributeIds.clear();
401  attributesChanged = true;
402  }
403  else
404  {
405  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
406 #if 0
407  QString list = "ERROR: Pending attribute deletes:";
408  Q_FOREACH ( int idx, mDeletedAttributeIds )
409  {
410  list.append( ' ' + L->fields().at( idx ).name() );
411  }
412  commitErrors << list;
413 #endif
414  success = false;
415  }
416  }
417 
418  // rename attributes
419  if ( !mRenamedAttributes.isEmpty() )
420  {
422  {
423  commitErrors << tr( "SUCCESS: %n attribute(s) renamed.", "renamed attributes count", mRenamedAttributes.size() );
424 
426 
427  mRenamedAttributes.clear();
428  attributesChanged = true;
429  }
430  else
431  {
432  commitErrors << tr( "ERROR: %n attribute(s) not renamed", "not renamed attributes count", mRenamedAttributes.size() );
433  success = false;
434  }
435  }
436 
437  //
438  // add attributes
439  //
440  if ( !mAddedAttributes.isEmpty() )
441  {
443  {
444  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
445 
447 
448  mAddedAttributes.clear();
449  attributesChanged = true;
450  }
451  else
452  {
453  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
454 #if 0
455  QString list = "ERROR: Pending adds:";
456  Q_FOREACH ( QgsField f, mAddedAttributes )
457  {
458  list.append( ' ' + f.name() );
459  }
460  commitErrors << list;
461 #endif
462  success = false;
463  }
464  }
465 
466  //
467  // check that addition/removal went as expected
468  //
469  bool attributeChangesOk = true;
470  if ( attributesChanged )
471  {
472  L->updateFields();
473  QgsFields newFields = L->fields();
474 
475  if ( oldFields.count() != newFields.count() )
476  {
477  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
478  attributeChangesOk = false; // don't try attribute updates - they'll fail.
479  }
480 
481  for ( int i = 0; i < std::min( oldFields.count(), newFields.count() ); ++i )
482  {
483  QgsField oldField = oldFields.at( i );
484  QgsField newField = newFields.at( i );
485  if ( attributeChangesOk && oldField != newField )
486  {
487  commitErrors
488  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
489  << tr( "Provider: %1" ).arg( L->providerType() )
490  << tr( "Storage: %1" ).arg( L->storageType() )
491  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
492  .arg( tr( "expected field" ),
493  oldField.name(),
494  QVariant::typeToName( oldField.type() ),
495  oldField.typeName() )
496  .arg( oldField.length() )
497  .arg( oldField.precision() )
498  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
499  .arg( tr( "retrieved field" ),
500  newField.name(),
501  QVariant::typeToName( newField.type() ),
502  newField.typeName() )
503  .arg( newField.length() )
504  .arg( newField.precision() );
505  attributeChangesOk = false; // don't try attribute updates - they'll fail.
506  }
507  }
508  }
509 
510  if ( attributeChangesOk )
511  {
513  {
515 
517  {
518  commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
520  mChangedAttributeValues.clear();
521 
523  mChangedGeometries.clear();
524  }
525  else
526  {
527  success = false;
528  }
529  }
530  else
531  {
532  //
533  // change attributes
534  //
535  if ( !mChangedAttributeValues.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
536  {
538  {
539  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
540 
542  mChangedAttributeValues.clear();
543  }
544  else
545  {
546  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
547 #if 0
548  QString list = "ERROR: pending changes:";
549  Q_FOREACH ( QgsFeatureId id, mChangedAttributeValues.keys() )
550  {
551  list.append( "\n " + FID_TO_STRING( id ) + '[' );
552  Q_FOREACH ( int idx, mChangedAttributeValues[ id ].keys() )
553  {
554  list.append( QString( " %1:%2" ).arg( L->fields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
555  }
556  list.append( " ]" );
557  }
558  commitErrors << list;
559 #endif
560  success = false;
561  }
562  }
563  }
564 
565  //
566  // delete features
567  //
568  if ( success && !mDeletedFeatureIds.isEmpty() )
569  {
571  {
572  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
573  // TODO[MD]: we should not need this here
574  Q_FOREACH ( QgsFeatureId id, mDeletedFeatureIds )
575  {
576  mChangedAttributeValues.remove( id );
577  mChangedGeometries.remove( id );
578  }
579 
581 
582  mDeletedFeatureIds.clear();
583  }
584  else
585  {
586  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
587 #if 0
588  QString list = "ERROR: pending deletes:";
589  Q_FOREACH ( QgsFeatureId id, mDeletedFeatureIds )
590  {
591  list.append( ' ' + FID_TO_STRING( id ) );
592  }
593  commitErrors << list;
594 #endif
595  success = false;
596  }
597  }
598 
599  //
600  // add features
601  //
602  if ( success && !mAddedFeatures.isEmpty() )
603  {
605  {
606  QList<QgsFeatureId> ids;
607  QgsFeatureList featuresToAdd;
608  // get the list of added features in reversed order
609  // this will preserve the order how they have been added e.g. (-1, -2, -3) while in the map they are ordered (-3, -2, -1)
610  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
611 
612  // we need to strip any extra attributes here -- e.g. virtual fields, which should
613  // not be sent to the data provider. Refs #18784
614  for ( int i = 0; i < featuresToAdd.count(); ++i )
615  {
616  QgsVectorLayerUtils::matchAttributesToFields( featuresToAdd[i], provider->fields() );
617  }
618 
619  if ( provider->addFeatures( featuresToAdd ) )
620  {
621  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
622 
623  emit committedFeaturesAdded( L->id(), featuresToAdd );
624 
625  // notify everyone that the features with temporary ids were updated with permanent ids
626  for ( int i = 0; i < featuresToAdd.count(); ++i )
627  {
628  if ( featuresToAdd[i].id() != ids[i] )
629  {
630  //update selection
631  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
632  {
633  L->mSelectedFeatureIds.remove( ids[i] );
634  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
635  }
636  emit featureDeleted( ids[i] );
637  emit featureAdded( featuresToAdd[i].id() );
638  }
639  }
640 
641  mAddedFeatures.clear();
642  }
643  else
644  {
645  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
646 #if 0
647  QString list = "ERROR: pending adds:";
648  Q_FOREACH ( QgsFeature f, mAddedFeatures )
649  {
650  list.append( ' ' + FID_TO_STRING( f.id() ) + '[' );
651  for ( int i = 0; i < L->fields().size(); i++ )
652  {
653  list.append( QString( " %1:%2" ).arg( L->fields().at( i ).name() ).arg( f.attributes()[i].toString() ) );
654  }
655  list.append( " ]" );
656  }
657  commitErrors << list;
658 #endif
659  success = false;
660  }
661  }
662  else
663  {
664  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
665  success = false;
666  }
667  }
668  }
669  else
670  {
671  success = false;
672  }
673 
674  if ( !success && provider->hasErrors() )
675  {
676  commitErrors << tr( "\n Provider errors:" );
677  Q_FOREACH ( QString e, provider->errors() )
678  {
679  commitErrors << " " + e.replace( '\n', QLatin1String( "\n " ) );
680  }
681  provider->clearErrors();
682  }
683 
684  return success;
685 }
686 
687 
689 {
690  if ( !isModified() )
691  return;
692 
693  // limit canvas redraws to one by jumping to beginning of stack
694  // see QgsUndoWidget::indexChanged
695  L->undoStack()->setIndex( 0 );
696 
697  Q_ASSERT( mAddedAttributes.isEmpty() );
698  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
699  Q_ASSERT( mChangedAttributeValues.isEmpty() );
700  Q_ASSERT( mChangedGeometries.isEmpty() );
701  Q_ASSERT( mAddedFeatures.isEmpty() );
702 }
703 
704 #if 0
705 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
706 {
707  QString msg;
708  if ( !mChangedGeometries.isEmpty() )
709  {
710  msg += "CHANGED GEOMETRIES:\n";
711  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
712  {
713  // QgsFeatureId, QgsGeometry
714  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
715  }
716  }
717  return msg;
718 }
719 #endif
720 
722 {
723  // go through the changed attributes map and adapt indices
724  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
725  for ( ; it != mChangedAttributeValues.end(); ++it )
726  {
727  updateAttributeMapIndex( it.value(), index, + 1 );
728  }
729 
730  // go through added features and adapt attributes
731  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
732  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
733  {
734  QgsAttributes attrs = featureIt->attributes();
735  attrs.insert( index, QVariant() );
736  featureIt->setAttributes( attrs );
737  }
738 
739  // go through renamed attributes and adapt
740  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
741  //sort keys
742  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
743  Q_FOREACH ( int renameIndex, sortedRenamedIndices )
744  {
745  if ( renameIndex >= index )
746  {
747  mRenamedAttributes[ renameIndex + 1 ] = mRenamedAttributes.value( renameIndex );
748  }
749  }
750  //remove last
751  mRenamedAttributes.remove( index );
752 }
753 
755 {
756  // go through the changed attributes map and adapt indices
757  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
758  for ( ; it != mChangedAttributeValues.end(); ++it )
759  {
760  QgsAttributeMap &attrMap = it.value();
761  // remove the attribute
762  if ( attrMap.contains( index ) )
763  attrMap.remove( index );
764 
765  // update attribute indices
766  updateAttributeMapIndex( attrMap, index, -1 );
767  }
768 
769  // go through added features and adapt attributes
770  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
771  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
772  {
773  QgsAttributes attrs = featureIt->attributes();
774  attrs.remove( index );
775  featureIt->setAttributes( attrs );
776  }
777 
778  // go through rename attributes and adapt
779  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
780  //sort keys
781  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
782  int last = -1;
783  mRenamedAttributes.remove( index );
784  Q_FOREACH ( int renameIndex, sortedRenamedIndices )
785  {
786  if ( renameIndex > index )
787  {
788  mRenamedAttributes.insert( renameIndex - 1, mRenamedAttributes.value( renameIndex ) );
789  last = renameIndex;
790  }
791  }
792  //remove last
793  if ( last > -1 )
794  mRenamedAttributes.remove( last );
795 }
796 
797 
798 
800 {
801  QgsAttributeMap updatedMap;
802  for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
803  {
804  int attrIndex = it.key();
805  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
806  }
807  map = updatedMap;
808 }
809 
810 
811 
813 {
814  L->updateFields();
815 }
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider...
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureId id
Definition: qgsfeature.h:64
void handleAttributeDeleted(int index)
Update added and changed features after removal of an attribute.
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
virtual bool renameAttribute(int attr, const QString &newName)
Renames an attribute field (but does not commit it)
virtual bool addAttribute(const QgsField &field)
Add an attribute field (but does not commit it) returns true if the field was added.
QgsWkbTypes::Type wkbType() const override=0
Returns the geometry type which is returned by this layer.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Signals emitted after committing changes.
void mapToReversedLists(const QMap< Key, T > &map, QList< Key > &ks, QList< T > &vs)
populate two lists (ks, vs) from map - in reverse order
QString name
Definition: qgsfield.h:57
int precision
Definition: qgsfield.h:54
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
virtual bool addFeature(QgsFeature &f)
Adds a feature.
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:51
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
virtual bool deleteFeatures(const QgsFeatureIds &id)
Deletes one or more features from the provider.
virtual bool renameAttributes(const QgsFieldNameMap &renamedAttributes)
Renames existing attributes.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
friend class QgsVectorLayerUndoCommandChangeGeometry
Container of fields for a vector layer.
Definition: qgsfields.h:42
virtual void rollBack()
Stop editing and discard the edits.
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
friend class QgsVectorLayerUndoCommandAddAttribute
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
Allows deletion of attributes (fields)
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
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
Definition: qgsfields.cpp:72
friend class QgsVectorLayerUndoCommandRenameAttribute
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
friend class QgsVectorLayerUndoCommandDeleteAttribute
QgsGeometry convertToProviderType(const QgsGeometry &geom) const
Converts the geometry to the provider type if possible / necessary.
int length
Definition: qgsfield.h:53
void featureAdded(QgsFeatureId fid)
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
virtual void updateExtents(bool force=false)
Update the extents for the layer.
bool supportedType(const QgsField &field) const
check if provider supports type of field
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:105
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
Allows addition of new attributes (fields)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsFields fields() const override=0
Returns the fields associated with this data provider.
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
virtual bool changeFeatures(const QgsChangedAttributesMap &attr_map, const QgsGeometryMap &geometry_map)
Changes attribute values and geometries of existing features.
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
bool hasErrors() const
Provider has errors to report.
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature&#39;s geometry.
void handleAttributeAdded(int index)
Update added and changed features after addition of an attribute.
Allows modifications of geometries.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:59
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
virtual bool deleteFeatures(const QgsFeatureIds &fid)
Deletes a set of features from the layer (but does not commit it)
void clearErrors()
Clear recorded errors.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
virtual bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues)
Changes values of attributes (but does not commit it).
virtual bool changeGeometryValues(const QgsGeometryMap &geometry_map)
Changes geometries of existing features.
void remove(int fieldIdx)
Removes a field with the given index.
Definition: qgsfields.cpp:101
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
virtual bool deleteAttribute(int attr)
Delete an attribute field (but does not commit it)
friend class QgsVectorLayerUndoCommandDeleteFeature
QgsVectorLayerEditBuffer()=default
Constructor for QgsVectorLayerEditBuffer.
#define FID_IS_NEW(fid)
Definition: qgsfeatureid.h:28
QString providerType() const
Returns the provider type for this layer.
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:30
virtual QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
virtual bool doesStrictFeatureTypeCheck() const
Returns true if the provider is strict about the type of inserted features (e.g.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
void committedAttributesRenamed(const QString &layerId, const QgsFieldNameMap &renamedAttributes)
Emitted after committing an attribute rename.
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
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
QStringList errors() const
Gets recorded errors.
virtual bool deleteAttributes(const QgsAttributeIds &attributes)
Deletes existing attributes from the provider.
virtual bool deleteFeature(QgsFeatureId fid)
Delete a feature from the layer (but does not commit it)
virtual bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changed an attribute value (but does not commit it)
QUndoStack * undoStack()
Returns pointer to layer&#39;s undo stack.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
This is the base class for vector data providers.
QgsFeatureMap mAddedFeatures
New features which are not committed.
A vector of attributes.
Definition: qgsattributes.h:57
void updateFields(QgsFields &fields)
void layerModified()
This signal is emitted when modifications has been done on layer.
Represents a vector layer which manages a vector based data sets.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
Field is calculated from an expression.
Definition: qgsfields.h:52
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
Allows modification of attribute values.
void updateAttributeMapIndex(QgsAttributeMap &attrs, int index, int offset) const
Updates an index in an attribute map to a new value (for updates of changed attributes) ...
void featureDeleted(QgsFeatureId fid)
QVariant::Type type
Definition: qgsfield.h:55
QgsAttributes attributes
Definition: qgsfeature.h:65
Supports joint updates for attributes and geometry Providers supporting this should still define Chan...
friend class QgsVectorLayerUndoCommandChangeAttribute
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.