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