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