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