QGIS API Documentation  2.99.0-Master (009e47e)
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->hasGeometryType() )
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  for ( QgsFeature f : mAddedFeatures )
322  {
323  if ( ( ! f.hasGeometry() ) ||
324  ( f.geometry().wkbType() == provider->wkbType() ) )
325  continue;
326 
327  if ( provider->convertToProviderType( f.geometry() ).isNull() )
328  {
329  commitErrors << tr( "ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.", "not added features count", mAddedFeatures.size() );
330  success = false;
331  break;
332  }
333  }
334  }
335  else
336  {
337  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
338  success = false;
339  }
340  }
341 
342  //
343  // update geometries
344  //
345  if ( !mChangedGeometries.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
346  {
347  if ( provider->changeGeometryValues( mChangedGeometries ) )
348  {
349  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
350 
352  mChangedGeometries.clear();
353  }
354  else
355  {
356  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
357  success = false;
358  }
359  }
360 
361  QgsFields oldFields = L->fields();
362 
363  //
364  // delete attributes
365  //
366  bool attributesChanged = false;
367  if ( !mDeletedAttributeIds.isEmpty() )
368  {
369  if ( ( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( mDeletedAttributeIds.toSet() ) )
370  {
371  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
372 
374 
375  mDeletedAttributeIds.clear();
376  attributesChanged = true;
377  }
378  else
379  {
380  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
381 #if 0
382  QString list = "ERROR: Pending attribute deletes:";
383  Q_FOREACH ( int idx, mDeletedAttributeIds )
384  {
385  list.append( ' ' + L->pendingFields().at( idx ).name() );
386  }
387  commitErrors << list;
388 #endif
389  success = false;
390  }
391  }
392 
393  //
394  // add attributes
395  //
396  if ( !mAddedAttributes.isEmpty() )
397  {
399  {
400  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
401 
403 
404  mAddedAttributes.clear();
405  attributesChanged = true;
406  }
407  else
408  {
409  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
410 #if 0
411  QString list = "ERROR: Pending adds:";
412  Q_FOREACH ( QgsField f, mAddedAttributes )
413  {
414  list.append( ' ' + f.name() );
415  }
416  commitErrors << list;
417 #endif
418  success = false;
419  }
420  }
421 
422  // rename attributes
423  if ( !mRenamedAttributes.isEmpty() )
424  {
426  {
427  commitErrors << tr( "SUCCESS: %n attribute(s) renamed.", "renamed attributes count", mRenamedAttributes.size() );
428 
430 
431  mRenamedAttributes.clear();
432  attributesChanged = true;
433  }
434  else
435  {
436  commitErrors << tr( "ERROR: %n attribute(s) not renamed", "not renamed attributes count", mRenamedAttributes.size() );
437  success = false;
438  }
439  }
440 
441  //
442  // check that addition/removal went as expected
443  //
444  bool attributeChangesOk = true;
445  if ( attributesChanged )
446  {
447  L->updateFields();
448  QgsFields newFields = L->fields();
449 
450  if ( oldFields.count() != newFields.count() )
451  {
452  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
453  attributeChangesOk = false; // don't try attribute updates - they'll fail.
454  }
455 
456  for ( int i = 0; i < qMin( oldFields.count(), newFields.count() ); ++i )
457  {
458  QgsField oldField = oldFields.at( i );
459  QgsField newField = newFields.at( i );
460  if ( attributeChangesOk && oldField != newField )
461  {
462  commitErrors
463  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
464  << tr( "Provider: %1" ).arg( L->providerType() )
465  << tr( "Storage: %1" ).arg( L->storageType() )
466  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
467  .arg( tr( "expected field" ),
468  oldField.name(),
469  QVariant::typeToName( oldField.type() ),
470  oldField.typeName() )
471  .arg( oldField.length() )
472  .arg( oldField.precision() )
473  << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
474  .arg( tr( "retrieved field" ),
475  newField.name(),
476  QVariant::typeToName( newField.type() ),
477  newField.typeName() )
478  .arg( newField.length() )
479  .arg( newField.precision() );
480  attributeChangesOk = false; // don't try attribute updates - they'll fail.
481  }
482  }
483  }
484 
485  if ( attributeChangesOk )
486  {
488  {
490 
492  {
493  commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
495  mChangedAttributeValues.clear();
496 
498  mChangedGeometries.clear();
499  }
500  else
501  {
502  success = false;
503  }
504  }
505  else
506  {
507  //
508  // change attributes
509  //
510  if ( !mChangedAttributeValues.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
511  {
513  {
514  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
515 
517  mChangedAttributeValues.clear();
518  }
519  else
520  {
521  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
522 #if 0
523  QString list = "ERROR: pending changes:";
524  Q_FOREACH ( QgsFeatureId id, mChangedAttributeValues.keys() )
525  {
526  list.append( "\n " + FID_TO_STRING( id ) + '[' );
527  Q_FOREACH ( int idx, mChangedAttributeValues[ id ].keys() )
528  {
529  list.append( QString( " %1:%2" ).arg( L->pendingFields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
530  }
531  list.append( " ]" );
532  }
533  commitErrors << list;
534 #endif
535  success = false;
536  }
537  }
538  }
539 
540  //
541  // delete features
542  //
543  if ( success && !mDeletedFeatureIds.isEmpty() )
544  {
546  {
547  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
548  // TODO[MD]: we should not need this here
549  Q_FOREACH ( QgsFeatureId id, mDeletedFeatureIds )
550  {
551  mChangedAttributeValues.remove( id );
552  mChangedGeometries.remove( id );
553  }
554 
556 
557  mDeletedFeatureIds.clear();
558  }
559  else
560  {
561  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
562 #if 0
563  QString list = "ERROR: pending deletes:";
564  Q_FOREACH ( QgsFeatureId id, mDeletedFeatureIds )
565  {
566  list.append( ' ' + FID_TO_STRING( id ) );
567  }
568  commitErrors << list;
569 #endif
570  success = false;
571  }
572  }
573 
574  //
575  // add features
576  //
577  if ( success && !mAddedFeatures.isEmpty() )
578  {
580  {
581  QList<QgsFeatureId> ids;
582  QgsFeatureList featuresToAdd;
583  // get the list of added features in reversed order
584  // 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)
585  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
586 
587  if ( provider->addFeatures( featuresToAdd ) )
588  {
589  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
590 
591  emit committedFeaturesAdded( L->id(), featuresToAdd );
592 
593  // notify everyone that the features with temporary ids were updated with permanent ids
594  for ( int i = 0; i < featuresToAdd.count(); ++i )
595  {
596  if ( featuresToAdd[i].id() != ids[i] )
597  {
598  //update selection
599  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
600  {
601  L->mSelectedFeatureIds.remove( ids[i] );
602  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
603  }
604  emit featureDeleted( ids[i] );
605  emit featureAdded( featuresToAdd[i].id() );
606  }
607  }
608 
609  mAddedFeatures.clear();
610  }
611  else
612  {
613  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
614 #if 0
615  QString list = "ERROR: pending adds:";
616  Q_FOREACH ( QgsFeature f, mAddedFeatures )
617  {
618  list.append( ' ' + FID_TO_STRING( f.id() ) + '[' );
619  for ( int i = 0; i < L->pendingFields().size(); i++ )
620  {
621  list.append( QString( " %1:%2" ).arg( L->pendingFields().at( i ).name() ).arg( f.attributes()[i].toString() ) );
622  }
623  list.append( " ]" );
624  }
625  commitErrors << list;
626 #endif
627  success = false;
628  }
629  }
630  else
631  {
632  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
633  success = false;
634  }
635  }
636  }
637  else
638  {
639  success = false;
640  }
641 
642  if ( !success && provider->hasErrors() )
643  {
644  commitErrors << tr( "\n Provider errors:" );
645  Q_FOREACH ( QString e, provider->errors() )
646  {
647  commitErrors << " " + e.replace( '\n', QLatin1String( "\n " ) );
648  }
649  provider->clearErrors();
650  }
651 
652  return success;
653 }
654 
655 
657 {
658  if ( !isModified() )
659  return;
660 
661  // limit canvas redraws to one by jumping to beginning of stack
662  // see QgsUndoWidget::indexChanged
663  L->undoStack()->setIndex( 0 );
664 
665  Q_ASSERT( mAddedAttributes.isEmpty() );
666  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
667  Q_ASSERT( mChangedAttributeValues.isEmpty() );
668  Q_ASSERT( mChangedGeometries.isEmpty() );
669  Q_ASSERT( mAddedFeatures.isEmpty() );
670 }
671 
672 #if 0
673 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
674 {
675  QString msg;
676  if ( !mChangedGeometries.isEmpty() )
677  {
678  msg += "CHANGED GEOMETRIES:\n";
679  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
680  {
681  // QgsFeatureId, QgsGeometry
682  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
683  }
684  }
685  return msg;
686 }
687 #endif
688 
690 {
691  // go through the changed attributes map and adapt indices
692  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
693  for ( ; it != mChangedAttributeValues.end(); ++it )
694  {
695  updateAttributeMapIndex( it.value(), index, + 1 );
696  }
697 
698  // go through added features and adapt attributes
699  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
700  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
701  {
702  QgsAttributes attrs = featureIt->attributes();
703  attrs.insert( index, QVariant() );
704  featureIt->setAttributes( attrs );
705  }
706 
707  // go through renamed attributes and adapt
708  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
709  //sort keys
710  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
711  Q_FOREACH ( int renameIndex, sortedRenamedIndices )
712  {
713  if ( renameIndex >= index )
714  {
715  mRenamedAttributes[ renameIndex + 1 ] = mRenamedAttributes.value( renameIndex );
716  }
717  }
718  //remove last
719  mRenamedAttributes.remove( index );
720 }
721 
723 {
724  // go through the changed attributes map and adapt indices
725  QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
726  for ( ; it != mChangedAttributeValues.end(); ++it )
727  {
728  QgsAttributeMap &attrMap = it.value();
729  // remove the attribute
730  if ( attrMap.contains( index ) )
731  attrMap.remove( index );
732 
733  // update attribute indices
734  updateAttributeMapIndex( attrMap, index, -1 );
735  }
736 
737  // go through added features and adapt attributes
738  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
739  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
740  {
741  QgsAttributes attrs = featureIt->attributes();
742  attrs.remove( index );
743  featureIt->setAttributes( attrs );
744  }
745 
746  // go through rename attributes and adapt
747  QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
748  //sort keys
749  std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
750  int last = -1;
751  mRenamedAttributes.remove( index );
752  Q_FOREACH ( int renameIndex, sortedRenamedIndices )
753  {
754  if ( renameIndex > index )
755  {
756  mRenamedAttributes.insert( renameIndex - 1, mRenamedAttributes.value( renameIndex ) );
757  last = renameIndex;
758  }
759  }
760  //remove last
761  if ( last > -1 )
762  mRenamedAttributes.remove( last );
763 }
764 
765 
766 
768 {
769  QgsAttributeMap updatedMap;
770  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
771  {
772  int attrIndex = it.key();
773  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
774  }
775  map = updatedMap;
776 }
777 
778 
779 
781 {
782  L->updateFields();
783 }
void updateFields()
Assembles mUpdatedFields considering provider fields, joined fields and added fields.
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureId id
Definition: qgsfeature.h:70
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:49
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:161
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:54
int precision
Definition: qgsfield.h:52
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:50
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:519
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:524
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:41
virtual void rollBack()
Stop editing and discard the edits.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:96
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:48
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:61
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
friend class QgsVectorLayerUndoCommandRenameAttribute
virtual bool addFeatures(QgsFeatureList &flist) override
Adds a list of features to the sink.
int count() const
Return number of items.
Definition: qgsfields.cpp:115
friend class QgsVectorLayerUndoCommandDeleteAttribute
virtual void updateExtents()
Update the extents for the layer.
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:135
int length
Definition: qgsfield.h:51
int fieldOriginIndex(int fieldIdx) const
Get field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:169
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
void featureAdded(QgsFeatureId fid)
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
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:104
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 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.
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:46
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: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.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:94
Field is calculated from an expression.
Definition: qgsfields.h:51
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:71
Supports joint updates for attributes and geometry Providers supporting this should still define Chan...
friend class QgsVectorLayerUndoCommandChangeAttribute