QGIS API Documentation  3.17.0-Master (8af46bc54f)
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() ||
251  L->fields().fieldOrigin( field ) == QgsFields::OriginJoin ||
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  // first of all check if feature to add is compatible with provider type
343  // this check have to be done before all checks to avoid to clear internal
344  // buffer if some of next steps success.
345  if ( success && !mAddedFeatures.isEmpty() )
346  {
348  {
349  if ( provider->doesStrictFeatureTypeCheck() )
350  {
351  for ( const QgsFeature &f : qgis::as_const( mAddedFeatures ) )
352  {
353  if ( ( ! f.hasGeometry() ) ||
354  ( f.geometry().wkbType() == provider->wkbType() ) )
355  continue;
356 
357  if ( provider->convertToProviderType( f.geometry() ).isNull() )
358  {
359  commitErrors << tr( "ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.", "not added features count", mAddedFeatures.size() );
360  success = false;
361  break;
362  }
363  }
364  }
365  }
366  else
367  {
368  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
369  success = false;
370  }
371  }
372 
373  //
374  // update geometries
375  //
376  if ( !mChangedGeometries.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
377  {
378  if ( provider->changeGeometryValues( mChangedGeometries ) )
379  {
380  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
381 
383  mChangedGeometries.clear();
384  }
385  else
386  {
387  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
388  success = false;
389  }
390  }
391 
392  QgsFields oldFields = L->fields();
393 
394  //
395  // delete attributes
396  //
397  bool attributesChanged = false;
398  if ( !mDeletedAttributeIds.isEmpty() )
399  {
400  if ( ( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( qgis::listToSet( mDeletedAttributeIds ) ) )
401  {
402  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
403 
405 
406  mDeletedAttributeIds.clear();
407  attributesChanged = true;
408  }
409  else
410  {
411  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
412 #if 0
413  QString list = "ERROR: Pending attribute deletes:";
414  const auto constMDeletedAttributeIds = mDeletedAttributeIds;
415  for ( int idx : constMDeletedAttributeIds )
416  {
417  list.append( ' ' + L->fields().at( idx ).name() );
418  }
419  commitErrors << list;
420 #endif
421  success = false;
422  }
423  }
424 
425  // rename attributes
426  if ( !mRenamedAttributes.isEmpty() )
427  {
429  {
430  commitErrors << tr( "SUCCESS: %n attribute(s) renamed.", "renamed attributes count", mRenamedAttributes.size() );
431 
433 
434  mRenamedAttributes.clear();
435  attributesChanged = true;
436  }
437  else
438  {
439  commitErrors << tr( "ERROR: %n attribute(s) not renamed", "not renamed attributes count", mRenamedAttributes.size() );
440  success = false;
441  }
442  }
443 
444  //
445  // add attributes
446  //
447  if ( !mAddedAttributes.isEmpty() )
448  {
450  {
451  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
452 
454 
455  mAddedAttributes.clear();
456  attributesChanged = true;
457  }
458  else
459  {
460  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
461 #if 0
462  QString list = "ERROR: Pending adds:";
463  const auto constMAddedAttributes = mAddedAttributes;
464  for ( QgsField f : constMAddedAttributes )
465  {
466  list.append( ' ' + f.name() );
467  }
468  commitErrors << list;
469 #endif
470  success = false;
471  }
472  }
473 
474  //
475  // check that addition/removal went as expected
476  //
477  bool attributeChangesOk = true;
478  if ( attributesChanged )
479  {
480  L->updateFields();
481  QgsFields newFields = L->fields();
482 
483  if ( oldFields.count() != newFields.count() )
484  {
485  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
486  attributeChangesOk = false; // don't try attribute updates - they'll fail.
487  }
488 
489  for ( int i = 0; i < std::min( oldFields.count(), newFields.count() ); ++i )
490  {
491  QgsField oldField = oldFields.at( i );
492  QgsField newField = newFields.at( i );
493  if ( attributeChangesOk && oldField != newField )
494  {
495  commitErrors
496  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
497  << tr( "Provider: %1" ).arg( L->providerType() )
498  << tr( "Storage: %1" ).arg( L->storageType() )
499  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
500  .arg( tr( "expected field" ),
501  oldField.name(),
502  QVariant::typeToName( oldField.type() ),
503  oldField.typeName() )
504  .arg( oldField.length() )
505  .arg( oldField.precision() )
506  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
507  .arg( tr( "retrieved field" ),
508  newField.name(),
509  QVariant::typeToName( newField.type() ),
510  newField.typeName() )
511  .arg( newField.length() )
512  .arg( newField.precision() );
513  attributeChangesOk = false; // don't try attribute updates - they'll fail.
514  }
515  }
516  }
517 
518  if ( attributeChangesOk )
519  {
521  {
523 
525  {
526  commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
528  mChangedAttributeValues.clear();
529 
531  mChangedGeometries.clear();
532  }
533  else
534  {
535  success = false;
536  }
537  }
538  else
539  {
540  //
541  // change attributes
542  //
543  if ( !mChangedAttributeValues.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
544  {
546  {
547  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
548 
550  mChangedAttributeValues.clear();
551  }
552  else
553  {
554  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
555 #if 0
556  QString list = "ERROR: pending changes:";
557  const auto constKeys = mChangedAttributeValues.keys();
558  for ( QgsFeatureId id : constKeys )
559  {
560  list.append( "\n " + FID_TO_STRING( id ) + '[' );
561  const auto constKeys = mChangedAttributeValues[ id ].keys();
562  for ( int idx : constKeys )
563  {
564  list.append( QString( " %1:%2" ).arg( L->fields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
565  }
566  list.append( " ]" );
567  }
568  commitErrors << list;
569 #endif
570  success = false;
571  }
572  }
573  }
574 
575  //
576  // delete features
577  //
578  if ( success && !mDeletedFeatureIds.isEmpty() )
579  {
581  {
582  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
583  // TODO[MD]: we should not need this here
584  for ( QgsFeatureId id : qgis::as_const( mDeletedFeatureIds ) )
585  {
586  mChangedAttributeValues.remove( id );
587  mChangedGeometries.remove( id );
588  }
589 
591 
592  mDeletedFeatureIds.clear();
593  }
594  else
595  {
596  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
597 #if 0
598  QString list = "ERROR: pending deletes:";
599  const auto constMDeletedFeatureIds = mDeletedFeatureIds;
600  for ( QgsFeatureId id : constMDeletedFeatureIds )
601  {
602  list.append( ' ' + FID_TO_STRING( id ) );
603  }
604  commitErrors << list;
605 #endif
606  success = false;
607  }
608  }
609 
610  //
611  // add features
612  //
613  if ( success && !mAddedFeatures.isEmpty() )
614  {
616  {
617  QList<QgsFeatureId> ids;
618  QgsFeatureList featuresToAdd;
619  // get the list of added features in reversed order
620  // 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)
621  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
622 
623  // we need to strip any extra attributes here -- e.g. virtual fields, which should
624  // not be sent to the data provider. Refs #18784
625  for ( int i = 0; i < featuresToAdd.count(); ++i )
626  {
627  QgsVectorLayerUtils::matchAttributesToFields( featuresToAdd[i], provider->fields() );
628  }
629 
630  if ( provider->addFeatures( featuresToAdd, QgsFeatureSink::Flag::RollBackOnErrors ) )
631  {
632  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
633 
634  emit committedFeaturesAdded( L->id(), featuresToAdd );
635 
636  // notify everyone that the features with temporary ids were updated with permanent ids
637  for ( int i = 0; i < featuresToAdd.count(); ++i )
638  {
639  if ( featuresToAdd[i].id() != ids[i] )
640  {
641  //update selection
642  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
643  {
644  L->mSelectedFeatureIds.remove( ids[i] );
645  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
646  }
647  emit featureDeleted( ids[i] );
648  emit featureAdded( featuresToAdd[i].id() );
649  }
650  }
651 
652  mAddedFeatures.clear();
653  }
654  else
655  {
656  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
657 #if 0
658  QString list = "ERROR: pending adds:";
659  const auto constMAddedFeatures = mAddedFeatures;
660  for ( QgsFeature f : constMAddedFeatures )
661  {
662  list.append( ' ' + FID_TO_STRING( f.id() ) + '[' );
663  for ( int i = 0; i < L->fields().size(); i++ )
664  {
665  list.append( QString( " %1:%2" ).arg( L->fields().at( i ).name() ).arg( f.attributes()[i].toString() ) );
666  }
667  list.append( " ]" );
668  }
669  commitErrors << list;
670 #endif
671  success = false;
672  }
673  }
674  else
675  {
676  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
677  success = false;
678  }
679  }
680  }
681  else
682  {
683  success = false;
684  }
685 
686  if ( !success && provider->hasErrors() )
687  {
688  commitErrors << tr( "\n Provider errors:" );
689  const auto constErrors = provider->errors();
690  for ( QString e : constErrors )
691  {
692  commitErrors << " " + e.replace( '\n', QLatin1String( "\n " ) );
693  }
694  provider->clearErrors();
695  }
696 
697  return success;
698 }
699 
700 
702 {
703  if ( !isModified() )
704  return;
705 
706  // limit canvas redraws to one by jumping to beginning of stack
707  // see QgsUndoWidget::indexChanged
708  L->undoStack()->setIndex( 0 );
709 
710  Q_ASSERT( mAddedAttributes.isEmpty() );
711  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
712  Q_ASSERT( mChangedAttributeValues.isEmpty() );
713  Q_ASSERT( mChangedGeometries.isEmpty() );
714  Q_ASSERT( mAddedFeatures.isEmpty() );
715 }
716 
717 #if 0
718 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
719 {
720  QString msg;
721  if ( !mChangedGeometries.isEmpty() )
722  {
723  msg += "CHANGED GEOMETRIES:\n";
724  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
725  {
726  // QgsFeatureId, QgsGeometry
727  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
728  }
729  }
730  return msg;
731 }
732 #endif
733 
735 {
736  // go through the changed attributes map and adapt indices
737  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
738  for ( ; it != mChangedAttributeValues.end(); ++it )
739  {
740  updateAttributeMapIndex( it.value(), index, + 1 );
741  }
742 
743  // go through added features and adapt attributes
744  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
745  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
746  {
747  QgsAttributes attrs = featureIt->attributes();
748  attrs.insert( index, QVariant() );
749  featureIt->setAttributes( attrs );
750  }
751 
752  // go through renamed attributes and adapt
753  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
754  //sort keys
755  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
756  const auto constSortedRenamedIndices = sortedRenamedIndices;
757  for ( int renameIndex : constSortedRenamedIndices )
758  {
759  if ( renameIndex >= index )
760  {
761  mRenamedAttributes[ renameIndex + 1 ] = mRenamedAttributes.value( renameIndex );
762  }
763  }
764  //remove last
765  mRenamedAttributes.remove( index );
766 }
767 
769 {
770  // go through the changed attributes map and adapt indices
771  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
772  for ( ; it != mChangedAttributeValues.end(); ++it )
773  {
774  QgsAttributeMap &attrMap = it.value();
775  // remove the attribute
776  if ( attrMap.contains( index ) )
777  attrMap.remove( index );
778 
779  // update attribute indices
780  updateAttributeMapIndex( attrMap, index, -1 );
781  }
782 
783  // go through added features and adapt attributes
784  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
785  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
786  {
787  QgsAttributes attrs = featureIt->attributes();
788  attrs.remove( index );
789  featureIt->setAttributes( attrs );
790  }
791 
792  // go through rename attributes and adapt
793  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
794  //sort keys
795  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
796  int last = -1;
797  mRenamedAttributes.remove( index );
798  const auto constSortedRenamedIndices = sortedRenamedIndices;
799  for ( int renameIndex : constSortedRenamedIndices )
800  {
801  if ( renameIndex > index )
802  {
803  mRenamedAttributes.insert( renameIndex - 1, mRenamedAttributes.value( renameIndex ) );
804  last = renameIndex;
805  }
806  }
807  //remove last
808  if ( last > -1 )
809  mRenamedAttributes.remove( last );
810 }
811 
812 
813 
815 {
816  QgsAttributeMap updatedMap;
817  for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
818  {
819  int attrIndex = it.key();
820  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
821  }
822  map = updatedMap;
823 }
824 
825 
826 
828 {
829  L->updateFields();
830 }
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:52
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
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:59
int precision
Definition: qgsfield.h:56
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:53
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:583
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
64 bit feature ids negative numbers are used for uncommitted/newly added features ...
Definition: qgsfeatureid.h:28
friend class QgsVectorLayerUndoCommandChangeGeometry
Container of fields for a vector layer.
Definition: qgsfields.h:44
virtual void rollBack()
Stop editing and discard the edits.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:123
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:129
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:51
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:55
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)
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
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:138
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.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
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:49
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.
Supports joint updates for attributes and geometry. Providers supporting this should still define Cha...
#define FID_IS_NEW(fid)
Definition: qgsfeatureid.h:31
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:33
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:139
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:54
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
Allows modification of attribute values.
const QgsField & field
Definition: qgsfield.h:471
void featureDeleted(QgsFeatureId fid)
QVariant::Type type
Definition: qgsfield.h:57
QgsAttributes attributes
Definition: qgsfeature.h:65
Supports renaming attributes (fields). Since QGIS 2.16.
friend class QgsVectorLayerUndoCommandChangeAttribute