QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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
static unsigned index
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: qgsfield.h:171
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.
field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfield.h:172
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.
allows deletion of attributes (fields)
field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfield.h:170
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)
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
allows addition of new attributes (fields)
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.
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
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: 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
void clearErrors()
Clear recorded errors.
int count() const
Return number of items.
Definition: qgsfield.h:200
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
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)
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.
field is calculated from an expression
Definition: qgsfield.h:173
QgsFeatureIds mSelectedFeatureIds
Set holding the feature IDs that are activated.
QgsAttributeList mDeletedAttributeIds
deleted attributes fields which are not commited.
allows modification of attribute values
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)