QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  const auto constFids = fids;
187  for ( QgsFeatureId fid : constFids )
188  ok = deleteFeature( fid ) && ok;
189 
190  return ok;
191 }
192 
193 
195 {
196  if ( !L->isSpatial() )
197  {
198  return false;
199  }
200 
201  if ( FID_IS_NEW( fid ) )
202  {
203  if ( !mAddedFeatures.contains( fid ) )
204  return false;
205  }
207  return false;
208 
209  // TODO: check compatible geometry
210 
211  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
212  return true;
213 }
214 
216 {
217  bool success = true;
218  for ( auto it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
219  {
220  const int field = it.key();
221  const QVariant newValue = it.value();
222  QVariant oldValue;
223 
224  if ( oldValues.contains( field ) )
225  oldValue = oldValues[field];
226 
227  success &= changeAttributeValue( fid, field, newValue, oldValue );
228  }
229 
230  return success;
231 }
232 
233 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
234 {
235  if ( FID_IS_NEW( fid ) )
236  {
237  if ( !mAddedFeatures.contains( fid ) )
238  return false;
239  }
241  {
242  return false;
243  }
244 
245  if ( field < 0 || field >= L->fields().count() ||
246  L->fields().fieldOrigin( field ) == QgsFields::OriginJoin ||
248  return false;
249 
250  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
251  return true;
252 }
253 
254 
256 {
258  return false;
259 
260  if ( field.name().isEmpty() )
261  return false;
262 
263  const QgsFields fields = L->fields();
264  for ( const QgsField &updatedField : fields )
265  {
266  if ( updatedField.name() == field.name() )
267  return false;
268  }
269 
270  if ( !L->dataProvider()->supportedType( field ) )
271  return false;
272 
273  L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
274  return true;
275 }
276 
277 
279 {
281  return false;
282 
283  if ( index < 0 || index >= L->fields().count() )
284  return false;
285 
286  // find out source of the field
287  QgsFields::FieldOrigin origin = L->fields().fieldOrigin( index );
288  int originIndex = L->fields().fieldOriginIndex( index );
289 
290  if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
291  return false;
292 
293  if ( origin == QgsFields::OriginJoin )
294  return false;
295 
296  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
297  return true;
298 }
299 
300 bool QgsVectorLayerEditBuffer::renameAttribute( int index, const QString &newName )
301 {
303  return false;
304 
305  if ( newName.isEmpty() )
306  return false;
307 
308  if ( index < 0 || index >= L->fields().count() )
309  return false;
310 
311  const QgsFields fields = L->fields();
312  for ( const QgsField &updatedField : fields )
313  {
314  if ( updatedField.name() == newName )
315  return false;
316  }
317 
318  L->undoStack()->push( new QgsVectorLayerUndoCommandRenameAttribute( this, index, newName ) );
319  return true;
320 }
321 
322 
323 bool QgsVectorLayerEditBuffer::commitChanges( QStringList &commitErrors )
324 {
325  QgsVectorDataProvider *provider = L->dataProvider();
326  commitErrors.clear();
327 
328  int cap = provider->capabilities();
329  bool success = true;
330 
331  // geometry updates attribute updates
332  // yes no => changeGeometryValues
333  // no yes => changeAttributeValues
334  // yes yes => changeFeatures
335 
336  // to fix https://github.com/qgis/QGIS/issues/23663
337  // first of all check if feature to add is compatible with provider type
338  // this check have to be done before all checks to avoid to clear internal
339  // buffer if some of next steps success.
340  if ( success && !mAddedFeatures.isEmpty() )
341  {
343  {
344  if ( provider->doesStrictFeatureTypeCheck() )
345  {
346  for ( const auto &f : qgis::as_const( mAddedFeatures ) )
347  {
348  if ( ( ! f.hasGeometry() ) ||
349  ( f.geometry().wkbType() == provider->wkbType() ) )
350  continue;
351 
352  if ( provider->convertToProviderType( f.geometry() ).isNull() )
353  {
354  commitErrors << tr( "ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.", "not added features count", mAddedFeatures.size() );
355  success = false;
356  break;
357  }
358  }
359  }
360  }
361  else
362  {
363  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
364  success = false;
365  }
366  }
367 
368  //
369  // update geometries
370  //
371  if ( !mChangedGeometries.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
372  {
373  if ( provider->changeGeometryValues( mChangedGeometries ) )
374  {
375  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
376 
378  mChangedGeometries.clear();
379  }
380  else
381  {
382  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
383  success = false;
384  }
385  }
386 
387  QgsFields oldFields = L->fields();
388 
389  //
390  // delete attributes
391  //
392  bool attributesChanged = false;
393  if ( !mDeletedAttributeIds.isEmpty() )
394  {
395  if ( ( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( mDeletedAttributeIds.toSet() ) )
396  {
397  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
398 
400 
401  mDeletedAttributeIds.clear();
402  attributesChanged = true;
403  }
404  else
405  {
406  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
407 #if 0
408  QString list = "ERROR: Pending attribute deletes:";
409  const auto constMDeletedAttributeIds = mDeletedAttributeIds;
410  for ( int idx : constMDeletedAttributeIds )
411  {
412  list.append( ' ' + L->fields().at( idx ).name() );
413  }
414  commitErrors << list;
415 #endif
416  success = false;
417  }
418  }
419 
420  // rename attributes
421  if ( !mRenamedAttributes.isEmpty() )
422  {
424  {
425  commitErrors << tr( "SUCCESS: %n attribute(s) renamed.", "renamed attributes count", mRenamedAttributes.size() );
426 
428 
429  mRenamedAttributes.clear();
430  attributesChanged = true;
431  }
432  else
433  {
434  commitErrors << tr( "ERROR: %n attribute(s) not renamed", "not renamed attributes count", mRenamedAttributes.size() );
435  success = false;
436  }
437  }
438 
439  //
440  // add attributes
441  //
442  if ( !mAddedAttributes.isEmpty() )
443  {
445  {
446  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
447 
449 
450  mAddedAttributes.clear();
451  attributesChanged = true;
452  }
453  else
454  {
455  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
456 #if 0
457  QString list = "ERROR: Pending adds:";
458  const auto constMAddedAttributes = mAddedAttributes;
459  for ( QgsField f : constMAddedAttributes )
460  {
461  list.append( ' ' + f.name() );
462  }
463  commitErrors << list;
464 #endif
465  success = false;
466  }
467  }
468 
469  //
470  // check that addition/removal went as expected
471  //
472  bool attributeChangesOk = true;
473  if ( attributesChanged )
474  {
475  L->updateFields();
476  QgsFields newFields = L->fields();
477 
478  if ( oldFields.count() != newFields.count() )
479  {
480  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
481  attributeChangesOk = false; // don't try attribute updates - they'll fail.
482  }
483 
484  for ( int i = 0; i < std::min( oldFields.count(), newFields.count() ); ++i )
485  {
486  QgsField oldField = oldFields.at( i );
487  QgsField newField = newFields.at( i );
488  if ( attributeChangesOk && oldField != newField )
489  {
490  commitErrors
491  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
492  << tr( "Provider: %1" ).arg( L->providerType() )
493  << tr( "Storage: %1" ).arg( L->storageType() )
494  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
495  .arg( tr( "expected field" ),
496  oldField.name(),
497  QVariant::typeToName( oldField.type() ),
498  oldField.typeName() )
499  .arg( oldField.length() )
500  .arg( oldField.precision() )
501  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
502  .arg( tr( "retrieved field" ),
503  newField.name(),
504  QVariant::typeToName( newField.type() ),
505  newField.typeName() )
506  .arg( newField.length() )
507  .arg( newField.precision() );
508  attributeChangesOk = false; // don't try attribute updates - they'll fail.
509  }
510  }
511  }
512 
513  if ( attributeChangesOk )
514  {
516  {
518 
520  {
521  commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
523  mChangedAttributeValues.clear();
524 
526  mChangedGeometries.clear();
527  }
528  else
529  {
530  success = false;
531  }
532  }
533  else
534  {
535  //
536  // change attributes
537  //
538  if ( !mChangedAttributeValues.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
539  {
541  {
542  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
543 
545  mChangedAttributeValues.clear();
546  }
547  else
548  {
549  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
550 #if 0
551  QString list = "ERROR: pending changes:";
552  const auto constKeys = mChangedAttributeValues.keys();
553  for ( QgsFeatureId id : constKeys )
554  {
555  list.append( "\n " + FID_TO_STRING( id ) + '[' );
556  const auto constKeys = mChangedAttributeValues[ id ].keys();
557  for ( int idx : constKeys )
558  {
559  list.append( QString( " %1:%2" ).arg( L->fields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
560  }
561  list.append( " ]" );
562  }
563  commitErrors << list;
564 #endif
565  success = false;
566  }
567  }
568  }
569 
570  //
571  // delete features
572  //
573  if ( success && !mDeletedFeatureIds.isEmpty() )
574  {
576  {
577  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
578  // TODO[MD]: we should not need this here
579  const auto constMDeletedFeatureIds = mDeletedFeatureIds;
580  for ( QgsFeatureId id : constMDeletedFeatureIds )
581  {
582  mChangedAttributeValues.remove( id );
583  mChangedGeometries.remove( id );
584  }
585 
587 
588  mDeletedFeatureIds.clear();
589  }
590  else
591  {
592  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
593 #if 0
594  QString list = "ERROR: pending deletes:";
595  const auto constMDeletedFeatureIds = mDeletedFeatureIds;
596  for ( QgsFeatureId id : constMDeletedFeatureIds )
597  {
598  list.append( ' ' + FID_TO_STRING( id ) );
599  }
600  commitErrors << list;
601 #endif
602  success = false;
603  }
604  }
605 
606  //
607  // add features
608  //
609  if ( success && !mAddedFeatures.isEmpty() )
610  {
612  {
613  QList<QgsFeatureId> ids;
614  QgsFeatureList featuresToAdd;
615  // get the list of added features in reversed order
616  // 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)
617  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
618 
619  // we need to strip any extra attributes here -- e.g. virtual fields, which should
620  // not be sent to the data provider. Refs #18784
621  for ( int i = 0; i < featuresToAdd.count(); ++i )
622  {
623  QgsVectorLayerUtils::matchAttributesToFields( featuresToAdd[i], provider->fields() );
624  }
625 
626  if ( provider->addFeatures( featuresToAdd ) )
627  {
628  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
629 
630  emit committedFeaturesAdded( L->id(), featuresToAdd );
631 
632  // notify everyone that the features with temporary ids were updated with permanent ids
633  for ( int i = 0; i < featuresToAdd.count(); ++i )
634  {
635  if ( featuresToAdd[i].id() != ids[i] )
636  {
637  //update selection
638  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
639  {
640  L->mSelectedFeatureIds.remove( ids[i] );
641  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
642  }
643  emit featureDeleted( ids[i] );
644  emit featureAdded( featuresToAdd[i].id() );
645  }
646  }
647 
648  mAddedFeatures.clear();
649  }
650  else
651  {
652  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
653 #if 0
654  QString list = "ERROR: pending adds:";
655  const auto constMAddedFeatures = mAddedFeatures;
656  for ( QgsFeature f : constMAddedFeatures )
657  {
658  list.append( ' ' + FID_TO_STRING( f.id() ) + '[' );
659  for ( int i = 0; i < L->fields().size(); i++ )
660  {
661  list.append( QString( " %1:%2" ).arg( L->fields().at( i ).name() ).arg( f.attributes()[i].toString() ) );
662  }
663  list.append( " ]" );
664  }
665  commitErrors << list;
666 #endif
667  success = false;
668  }
669  }
670  else
671  {
672  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
673  success = false;
674  }
675  }
676  }
677  else
678  {
679  success = false;
680  }
681 
682  if ( !success && provider->hasErrors() )
683  {
684  commitErrors << tr( "\n Provider errors:" );
685  const auto constErrors = provider->errors();
686  for ( QString e : constErrors )
687  {
688  commitErrors << " " + e.replace( '\n', QLatin1String( "\n " ) );
689  }
690  provider->clearErrors();
691  }
692 
693  return success;
694 }
695 
696 
698 {
699  if ( !isModified() )
700  return;
701 
702  // limit canvas redraws to one by jumping to beginning of stack
703  // see QgsUndoWidget::indexChanged
704  L->undoStack()->setIndex( 0 );
705 
706  Q_ASSERT( mAddedAttributes.isEmpty() );
707  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
708  Q_ASSERT( mChangedAttributeValues.isEmpty() );
709  Q_ASSERT( mChangedGeometries.isEmpty() );
710  Q_ASSERT( mAddedFeatures.isEmpty() );
711 }
712 
713 #if 0
714 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
715 {
716  QString msg;
717  if ( !mChangedGeometries.isEmpty() )
718  {
719  msg += "CHANGED GEOMETRIES:\n";
720  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
721  {
722  // QgsFeatureId, QgsGeometry
723  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
724  }
725  }
726  return msg;
727 }
728 #endif
729 
731 {
732  // go through the changed attributes map and adapt indices
733  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
734  for ( ; it != mChangedAttributeValues.end(); ++it )
735  {
736  updateAttributeMapIndex( it.value(), index, + 1 );
737  }
738 
739  // go through added features and adapt attributes
740  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
741  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
742  {
743  QgsAttributes attrs = featureIt->attributes();
744  attrs.insert( index, QVariant() );
745  featureIt->setAttributes( attrs );
746  }
747 
748  // go through renamed attributes and adapt
749  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
750  //sort keys
751  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
752  const auto constSortedRenamedIndices = sortedRenamedIndices;
753  for ( int renameIndex : constSortedRenamedIndices )
754  {
755  if ( renameIndex >= index )
756  {
757  mRenamedAttributes[ renameIndex + 1 ] = mRenamedAttributes.value( renameIndex );
758  }
759  }
760  //remove last
761  mRenamedAttributes.remove( index );
762 }
763 
765 {
766  // go through the changed attributes map and adapt indices
767  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
768  for ( ; it != mChangedAttributeValues.end(); ++it )
769  {
770  QgsAttributeMap &attrMap = it.value();
771  // remove the attribute
772  if ( attrMap.contains( index ) )
773  attrMap.remove( index );
774 
775  // update attribute indices
776  updateAttributeMapIndex( attrMap, index, -1 );
777  }
778 
779  // go through added features and adapt attributes
780  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
781  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
782  {
783  QgsAttributes attrs = featureIt->attributes();
784  attrs.remove( index );
785  featureIt->setAttributes( attrs );
786  }
787 
788  // go through rename attributes and adapt
789  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
790  //sort keys
791  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
792  int last = -1;
793  mRenamedAttributes.remove( index );
794  const auto constSortedRenamedIndices = sortedRenamedIndices;
795  for ( int renameIndex : constSortedRenamedIndices )
796  {
797  if ( renameIndex > index )
798  {
799  mRenamedAttributes.insert( renameIndex - 1, mRenamedAttributes.value( renameIndex ) );
800  last = renameIndex;
801  }
802  }
803  //remove last
804  if ( last > -1 )
805  mRenamedAttributes.remove( last );
806 }
807 
808 
809 
811 {
812  QgsAttributeMap updatedMap;
813  for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
814  {
815  int attrIndex = it.key();
816  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
817  }
818  map = updatedMap;
819 }
820 
821 
822 
824 {
825  L->updateFields();
826 }
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.
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.
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:58
int precision
Definition: qgsfield.h:55
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
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QString providerType() const
Returns the provider type (provider key) for this layer.
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:122
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
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
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
bool supportedType(const QgsField &field) const
check if provider supports type of field
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int length
Definition: qgsfield.h:54
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
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 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
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:105
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.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
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
Gets recorded errors.
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
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)
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
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:30
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
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, it may be nullptr.
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()
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:56
QgsAttributes attributes
Definition: qgsfeature.h:65
Supports joint updates for attributes and geometry Providers supporting this should still define Chan...
friend class QgsVectorLayerUndoCommandChangeAttribute