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