QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
23 
25  : L( layer )
26 {
27  connect( L->undoStack(), SIGNAL( indexChanged( int ) ), this, SLOT( undoIndexChanged( int ) ) ); // TODO[MD]: queued?
28 }
29 
31 {
32 }
33 
34 
36 {
37  return !L->undoStack()->isClean();
38 }
39 
40 
42 {
43  QgsDebugMsg( QString( "undo index changed %1" ).arg( index ) );
44  Q_UNUSED( index );
45  emit layerModified();
46 }
47 
48 
50 {
51  // delete attributes from the higher indices to lower indices
52  for ( int i = mDeletedAttributeIds.count() - 1; i >= 0; --i )
53  {
54  fields.remove( mDeletedAttributeIds[i] );
55  }
56  // add new fields
57  for ( int i = 0; i < mAddedAttributes.count(); ++i )
58  {
60  }
61 }
62 
63 
65 {
66  if ( mChangedGeometries.contains( f.id() ) )
68 }
69 
70 
72 {
73  QgsAttributes& attrs = f.attributes();
74 
75  // remove all attributes that will disappear - from higher indices to lower
76  for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
77  {
78  attrs.remove( mDeletedAttributeIds[idx] );
79  }
80 
81  // adjust size to accommodate added attributes
82  attrs.resize( attrs.count() + mAddedAttributes.count() );
83 
84  // update changed attributes
85  if ( mChangedAttributeValues.contains( f.id() ) )
86  {
87  const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
88  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
89  attrs[it.key()] = it.value();
90  }
91 }
92 
93 
94 
95 
97 {
99  {
100  return false;
101  }
102  if ( L->mUpdatedFields.count() != f.attributes().count() )
103  return false;
104 
105  // TODO: check correct geometry type
106 
107  L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
108  return true;
109 }
110 
111 
113 {
115  return false;
116 
117  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
118  {
119  addFeature( *iter );
120  }
121 
122  L->updateExtents();
123  return true;
124 }
125 
126 
127 
129 {
131  return false;
132 
133  if ( FID_IS_NEW( fid ) )
134  {
135  if ( !mAddedFeatures.contains( fid ) )
136  return false;
137  }
138  else // existing feature
139  {
140  if ( mDeletedFeatureIds.contains( fid ) )
141  return false;
142  }
143 
144  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
145  return true;
146 }
147 
148 
150 {
152  return false;
153 
154  if ( !L->hasGeometryType() )
155  {
156  return false;
157  }
158 
159  if ( FID_IS_NEW( fid ) )
160  {
161  if ( !mAddedFeatures.contains( fid ) )
162  return false;
163  }
164 
165  // TODO: check compatible geometry
166 
167  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
168  return true;
169 }
170 
171 
172 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
173 {
175  return false;
176 
177  if ( FID_IS_NEW( fid ) )
178  {
179  if ( !mAddedFeatures.contains( fid ) )
180  return false;
181  }
182 
183  if ( field < 0 || field >= L->pendingFields().count() ||
186  return false;
187 
188  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
189  return true;
190 }
191 
192 
194 {
196  return false;
197 
198  if ( field.name().isEmpty() )
199  return false;
200 
201  const QgsFields& updatedFields = L->pendingFields();
202  for ( int idx = 0; idx < updatedFields.count(); ++idx )
203  {
204  if ( updatedFields[idx].name() == field.name() )
205  return false;
206  }
207 
208  if ( !L->dataProvider()->supportedType( field ) )
209  return false;
210 
211  L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
212  return true;
213 }
214 
215 
217 {
219  return false;
220 
221  if ( index < 0 || index >= L->pendingFields().count() )
222  return false;
223 
224  // find out source of the field
225  QgsFields::FieldOrigin origin = L->pendingFields().fieldOrigin( index );
226  int originIndex = L->pendingFields().fieldOriginIndex( index );
227 
228  if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
229  return false;
230 
231  if ( origin == QgsFields::OriginJoin )
232  return false;
233 
234  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
235  return true;
236 }
237 
238 
239 bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
240 {
241  QgsVectorDataProvider* provider = L->dataProvider();
242  commitErrors.clear();
243 
244  int cap = provider->capabilities();
245  bool success = true;
246 
247  QgsFields oldFields = L->pendingFields();
248 
249  //
250  // delete attributes
251  //
252  bool attributesChanged = false;
253  if ( !mDeletedAttributeIds.isEmpty() )
254  {
256  {
257  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
258 
260 
261  mDeletedAttributeIds.clear();
262  attributesChanged = true;
263  }
264  else
265  {
266  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
267 #if 0
268  QString list = "ERROR: Pending attribute deletes:";
269  foreach ( int idx, mDeletedAttributeIds )
270  {
271  list.append( " " + L->pendingFields()[idx].name() );
272  }
273  commitErrors << list;
274 #endif
275  success = false;
276  }
277  }
278 
279  //
280  // add attributes
281  //
282  if ( !mAddedAttributes.isEmpty() )
283  {
285  {
286  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
287 
289 
290  mAddedAttributes.clear();
291  attributesChanged = true;
292  }
293  else
294  {
295  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
296 #if 0
297  QString list = "ERROR: Pending adds:";
298  foreach ( QgsField f, mAddedAttributes )
299  {
300  list.append( " " + f.name() );
301  }
302  commitErrors << list;
303 #endif
304  success = false;
305  }
306  }
307 
308  //
309  // check that addition/removal went as expected
310  //
311  bool attributeChangesOk = true;
312  if ( attributesChanged )
313  {
314  L->updateFields();
315  QgsFields newFields = L->pendingFields();
316 
317  if ( oldFields.count() != newFields.count() )
318  {
319  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
320  attributeChangesOk = false; // don't try attribute updates - they'll fail.
321  }
322 
323  for ( int i = 0; i < qMin( oldFields.count(), newFields.count() ); ++i )
324  {
325  const QgsField& oldField = oldFields[i];
326  const QgsField& newField = newFields[i];
327  if ( attributeChangesOk && oldField != newField )
328  {
329  commitErrors
330  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
331  << tr( "Provider: %1" ).arg( L->providerType() )
332  << tr( "Storage: %1" ).arg( L->storageType() )
333  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
334  .arg( tr( "expected field" ) )
335  .arg( oldField.name() )
336  .arg( QVariant::typeToName( oldField.type() ) )
337  .arg( oldField.typeName() )
338  .arg( oldField.length() )
339  .arg( oldField.precision() )
340  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
341  .arg( tr( "retrieved field" ) )
342  .arg( newField.name() )
343  .arg( QVariant::typeToName( newField.type() ) )
344  .arg( newField.typeName() )
345  .arg( newField.length() )
346  .arg( newField.precision() );
347  attributeChangesOk = false; // don't try attribute updates - they'll fail.
348  }
349  }
350  }
351 
352  if ( attributeChangesOk )
353  {
354  //
355  // change attributes
356  //
357  if ( !mChangedAttributeValues.isEmpty() )
358  {
360  {
361  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
362 
364 
365  mChangedAttributeValues.clear();
366  }
367  else
368  {
369  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
370 #if 0
371  QString list = "ERROR: pending changes:";
372  foreach ( QgsFeatureId id, mChangedAttributeValues.keys() )
373  {
374  list.append( "\n " + FID_TO_STRING( id ) + "[" );
375  foreach ( int idx, mChangedAttributeValues[ id ].keys() )
376  {
377  list.append( QString( " %1:%2" ).arg( L->pendingFields()[idx].name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
378  }
379  list.append( " ]" );
380  }
381  commitErrors << list;
382 #endif
383  success = false;
384  }
385  }
386 
387  //
388  // delete features
389  //
390  if ( success && !mDeletedFeatureIds.isEmpty() )
391  {
393  {
394  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
395  // TODO[MD]: we should not need this here
396  for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); ++it )
397  {
398  mChangedAttributeValues.remove( *it );
399  mChangedGeometries.remove( *it );
400  }
401 
403 
404  mDeletedFeatureIds.clear();
405  }
406  else
407  {
408  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
409 #if 0
410  QString list = "ERROR: pending deletes:";
411  foreach ( QgsFeatureId id, mDeletedFeatureIds )
412  {
413  list.append( " " + FID_TO_STRING( id ) );
414  }
415  commitErrors << list;
416 #endif
417  success = false;
418  }
419  }
420 
421  //
422  // add features
423  //
424  if ( success && !mAddedFeatures.isEmpty() )
425  {
427  {
428  QList<QgsFeatureId> ids = mAddedFeatures.keys();
429  QgsFeatureList featuresToAdd = mAddedFeatures.values();
430 
431  if ( provider->addFeatures( featuresToAdd ) )
432  {
433  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
434 
435  emit committedFeaturesAdded( L->id(), featuresToAdd );
436 
437  // notify everyone that the features with temporary ids were updated with permanent ids
438  for ( int i = 0; i < featuresToAdd.count(); ++i )
439  {
440  if ( featuresToAdd[i].id() != ids[i] )
441  {
442  //update selection
443  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
444  {
445  L->mSelectedFeatureIds.remove( ids[i] );
446  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
447  }
448  emit featureDeleted( ids[i] );
449  emit featureAdded( featuresToAdd[i].id() );
450  }
451  }
452 
453  mAddedFeatures.clear();
454  }
455  else
456  {
457  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
458 #if 0
459  QString list = "ERROR: pending adds:";
460  foreach ( QgsFeature f, mAddedFeatures )
461  {
462  list.append( " " + FID_TO_STRING( f.id() ) + "[" );
463  for ( int i = 0; i < L->pendingFields().size(); i++ )
464  {
465  list.append( QString( " %1:%2" ).arg( L->pendingFields()[i].name() ).arg( f.attributes()[i].toString() ) );
466  }
467  list.append( " ]" );
468  }
469  commitErrors << list;
470 #endif
471  success = false;
472  }
473  }
474  else
475  {
476  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
477  success = false;
478  }
479  }
480  }
481  else
482  {
483  success = false;
484  }
485 
486  //
487  // update geometries
488  //
489  if ( success && !mChangedGeometries.isEmpty() )
490  {
492  {
493  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
494 
496 
497  mChangedGeometries.clear();
498  }
499  else
500  {
501  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
502  success = false;
503  }
504  }
505 
506  if ( !success && provider->hasErrors() )
507  {
508  commitErrors << tr( "\n Provider errors:" );
509  foreach ( QString e, provider->errors() )
510  {
511  commitErrors << " " + e.replace( "\n", "\n " );
512  }
513  provider->clearErrors();
514  }
515 
516  return success;
517 }
518 
519 
521 {
522  if ( !isModified() )
523  return;
524 
525  // limit canvas redraws to one by jumping to beginning of stack
526  // see QgsUndoWidget::indexChanged
527  L->undoStack()->setIndex( 0 );
528 
529  Q_ASSERT( mAddedAttributes.isEmpty() );
530  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
531  Q_ASSERT( mChangedAttributeValues.isEmpty() );
532  Q_ASSERT( mChangedGeometries.isEmpty() );
533  Q_ASSERT( mAddedFeatures.isEmpty() );
534 }
535 
536 #if 0
537 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
538 {
539  QString msg;
540  if ( !mChangedGeometries.isEmpty() )
541  {
542  msg += "CHANGED GEOMETRIES:\n";
543  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
544  {
545  // QgsFeatureId, QgsGeometry
546  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
547  }
548  }
549  return msg;
550 }
551 #endif
552 
554 {
555  // go through the changed attributes map and adapt indices
556  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
557  {
559  }
560 
561  // go through added features and adapt attributes
562  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
563  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
564  {
565  QgsAttributes& attrs = featureIt->attributes();
566  attrs.insert( index, QVariant() );
567  }
568 }
569 
571 {
572  // go through the changed attributes map and adapt indices
573  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
574  {
576  // remove the attribute
577  if ( attrMap.contains( index ) )
578  attrMap.remove( index );
579 
580  // update attribute indices
581  updateAttributeMapIndex( attrMap, index, -1 );
582  }
583 
584  // go through added features and adapt attributes
585  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
586  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
587  {
588  QgsAttributes& attrs = featureIt->attributes();
589  attrs.remove( index );
590  }
591 }
592 
593 
594 
596 {
597  QgsAttributeMap updatedMap;
598  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
599  {
600  int attrIndex = it.key();
601  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
602  }
603  map = updatedMap;
604 }
605 
606 
607 
609 {
610  L->updateFields();
611 }
QgsFeatureId id() const
Get the feature id for this feature.
Definition: qgsfeature.cpp:100
void updateFields()
Assembles mUpdatedFields considering provider fields, joined fields and added fields.
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommited attribute updates.
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:58
allows modification of attribute values
static unsigned index
void handleAttributeDeleted(int index)
update added and changed features after removal of an attribute
allows modifications of geometries
bool addAttribute(const QgsField &field)
add an attribute field (but does not commit it) returns true if the field was added ...
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Signals emitted after committing changes.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:98
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
bool addFeature(QgsFeature &f)
Adds a feature.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:330
virtual bool deleteFeatures(const QgsFeatureIds &id)
Deletes one or more features.
int precision() const
Gets the precision of the field.
Definition: qgsfield.cpp:78
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:83
friend class QgsVectorLayerUndoCommandChangeGeometry
Container of fields for a vector layer.
Definition: qgsfield.h:163
void rollBack()
Stop editing and discard the edits.
QStringList errors()
Get recorded errors.
friend class QgsVectorLayerUndoCommandAddAttribute
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not commited.
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommited geometry updates.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
virtual bool addFeatures(QgsFeatureList &flist)
Adds a list of features.
friend class QgsVectorLayerUndoCommandDeleteAttribute
QgsVectorLayerEditBuffer(QgsVectorLayer *layer)
virtual void updateExtents()
Update the extents for the layer.
void featureAdded(QgsFeatureId fid)
field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfield.h:170
void setGeometry(const QgsGeometry &geom)
Set this feature's geometry from another QgsGeometry object (deep copy)
Definition: qgsfeature.cpp:134
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
bool supportedType(const QgsField &field) const
check if provider supports type of field
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
bool hasErrors()
Provider has errors to report.
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
allows deletion of attributes (fields)
int fieldOriginIndex(int fieldIdx) const
Get field's origin index (its meaning is specific to each type of origin)
Definition: qgsfield.h:222
QgsGeometryMap mChangedGeometries
Changed geometries which are not commited.
void handleAttributeAdded(int index)
update added and changed features after addition of an attribute
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
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: qgsfield.cpp:140
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:95
field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfield.h:172
void clearErrors()
Clear recorded errors.
int count() const
Return number of items.
Definition: qgsfield.h:200
field is calculated from an expression
Definition: qgsfield.h:173
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not commited.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:33
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfield.cpp:164
bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
bool deleteAttribute(int attr)
delete an attribute field (but does not commit it)
friend class QgsVectorLayerUndoCommandDeleteFeature
virtual bool changeGeometryValues(QgsGeometryMap &geometry_map)
Changes geometries of existing features.
QString providerType() const
Return the provider type for this layer.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QList< QgsField > mAddedAttributes
added attributes fields which are not commited
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
FieldOrigin fieldOrigin(int fieldIdx) const
Get field's origin (value from an enumeration)
Definition: qgsfield.h:220
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
const QString & typeName() const
Gets the field type.
Definition: qgsfield.cpp:68
int length() const
Gets the length of the field.
Definition: qgsfield.cpp:73
int size() const
Return number of items.
Definition: qgsfield.h:202
virtual bool deleteAttributes(const QgsAttributeIds &attributes)
Deletes existing attributes.
bool deleteFeature(QgsFeatureId fid)
delete a feature from the layer (but does not commit it)
qint64 QgsFeatureId
Definition: qgsfeature.h:30
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:81
allows addition of new attributes (fields)
QUndoStack * undoStack()
Return pointer to layer's undo stack.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfield.h:171
QgsVectorDataProvider * dataProvider()
Returns the data provider.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
This is the base class for vector data providers.
QgsFields mUpdatedFields
field map to commit
QgsFeatureMap mAddedFeatures
New features which are not commited.
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.
bool isModified() const
Returns true if the provider has been modified since the last commit.
QgsFeatureIds mSelectedFeatureIds
Set holding the feature IDs that are activated.
QgsAttributeList mDeletedAttributeIds
deleted attributes fields which are not commited.
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) ...
bool changeGeometry(QgsFeatureId fid, QgsGeometry *geom)
change feature's geometry
void featureDeleted(QgsFeatureId fid)
friend class QgsVectorLayerUndoCommandChangeAttribute
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:63
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
#define tr(sourceText)