QGIS API Documentation  2.99.0-Master (7fe5405)
qgsvectorlayerundocommand.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerundocommand.cpp
3  ---------------------
4  begin : June 2009
5  copyright : (C) 2009 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  ***************************************************************************/
15 
17 
18 #include "qgsfeatureiterator.h"
19 #include "qgsgeometry.h"
20 #include "qgsfeature.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsgeometrycache.h"
24 
25 #include "qgslogger.h"
26 
27 
29  : QgsVectorLayerUndoCommand( buffer )
30 {
31  static int sAddedIdLowWaterMark = -1;
32 
33  //assign a temporary id to the feature (use negative numbers)
34  sAddedIdLowWaterMark--;
35 
36  QgsDebugMsgLevel( "Assigned feature id " + QString::number( sAddedIdLowWaterMark ), 4 );
37 
38  // Force a feature ID (to keep other functions in QGIS happy,
39  // providers will use their own new feature ID when we commit the new feature)
40  // and add to the known added features.
41  f.setId( sAddedIdLowWaterMark );
42 
43  mFeature = f;
44 }
45 
47 {
48 #ifndef QT_NO_DEBUG
49  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFeature.id() );
50  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
51 #endif
52  mBuffer->mAddedFeatures.remove( mFeature.id() );
53 
54  if ( mFeature.hasGeometry() )
55  cache()->removeGeometry( mFeature.id() );
56 
57  emit mBuffer->featureDeleted( mFeature.id() );
58 }
59 
61 {
62  mBuffer->mAddedFeatures.insert( mFeature.id(), mFeature );
63 
64  if ( mFeature.hasGeometry() )
65  cache()->cacheGeometry( mFeature.id(), mFeature.geometry() );
66 
67  emit mBuffer->featureAdded( mFeature.id() );
68 }
69 
70 
71 
73  : QgsVectorLayerUndoCommand( buffer )
74 {
75  mFid = fid;
76 
77  if ( FID_IS_NEW( mFid ) )
78  {
79  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
80  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
81  mOldAddedFeature = it.value();
82  }
83 }
84 
86 {
87  if ( FID_IS_NEW( mFid ) )
88  {
89  mBuffer->mAddedFeatures.insert( mOldAddedFeature.id(), mOldAddedFeature );
90  }
91  else
92  {
93  mBuffer->mDeletedFeatureIds.remove( mFid );
94  }
95 
96  emit mBuffer->featureAdded( mFid );
97 }
98 
100 {
101  if ( FID_IS_NEW( mFid ) )
102  {
103  mBuffer->mAddedFeatures.remove( mFid );
104  }
105  else
106  {
107  mBuffer->mDeletedFeatureIds.insert( mFid );
108  }
109 
110  emit mBuffer->featureDeleted( mFid );
111 }
112 
113 
114 
116  : QgsVectorLayerUndoCommand( buffer )
117  , mFid( fid )
118  , mNewGeom( newGeom )
119 {
120  if ( FID_IS_NEW( mFid ) )
121  {
122  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
123  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
124  mOldGeom = ( it.value().geometry() );
125  }
126  else
127  {
128  bool changedAlready = mBuffer->mChangedGeometries.contains( mFid );
129  QgsGeometry geom;
130  bool cachedGeom = cache()->geometry( mFid, geom );
131  mOldGeom = ( changedAlready && cachedGeom ) ? geom : QgsGeometry();
132  }
133 }
134 
136 {
137  return 1;
138 }
139 
140 bool QgsVectorLayerUndoCommandChangeGeometry::mergeWith( const QUndoCommand *other )
141 {
142  if ( other->id() != id() )
143  return false;
144 
145  const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
146  if ( !merge )
147  return false;
148 
149  if ( merge->mFid != mFid )
150  return false;
151 
152  mNewGeom = merge->mNewGeom;
153  merge->mNewGeom = QgsGeometry();
154 
155  return true;
156 }
157 
159 {
160  if ( FID_IS_NEW( mFid ) )
161  {
162  // modify added features
163  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
164  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
165  it.value().setGeometry( mOldGeom );
166 
167  cache()->cacheGeometry( mFid, mOldGeom );
168  emit mBuffer->geometryChanged( mFid, mOldGeom );
169  }
170  else
171  {
172  // existing feature
173 
174  if ( mOldGeom.isEmpty() )
175  {
176  mBuffer->mChangedGeometries.remove( mFid );
177 
178  QgsFeature f;
179  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.hasGeometry() )
180  {
181  cache()->cacheGeometry( mFid, f.geometry() );
182  emit mBuffer->geometryChanged( mFid, f.geometry() );
183  }
184  }
185  else
186  {
187  mBuffer->mChangedGeometries[mFid] = mOldGeom;
188  cache()->cacheGeometry( mFid, mOldGeom );
189  emit mBuffer->geometryChanged( mFid, mOldGeom );
190  }
191  }
192 
193 }
194 
196 {
197  if ( FID_IS_NEW( mFid ) )
198  {
199  // modify added features
200  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
201  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
202  it.value().setGeometry( mNewGeom );
203  }
204  else
205  {
206  mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
207  }
208  cache()->cacheGeometry( mFid, mNewGeom );
209  emit mBuffer->geometryChanged( mFid, mNewGeom );
210 }
211 
212 
213 QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer* buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
214  : QgsVectorLayerUndoCommand( buffer )
215  , mFid( fid )
216  , mFieldIndex( fieldIndex )
217  , mOldValue( oldValue )
218  , mNewValue( newValue )
219  , mFirstChange( true )
220 {
221  if ( FID_IS_NEW( mFid ) )
222  {
223  // work with added feature
224  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
225  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
226  if ( it.value().attribute( mFieldIndex ).isValid() )
227  {
228  mOldValue = it.value().attribute( mFieldIndex );
229  mFirstChange = false;
230  }
231  }
232  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
233  {
234  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
235  mFirstChange = false;
236  }
237 
238 }
239 
241 {
242  QVariant original = mOldValue;
243 
244  if ( FID_IS_NEW( mFid ) )
245  {
246  // added feature
247  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
248  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
249  it.value().setAttribute( mFieldIndex, mOldValue );
250  }
251  else if ( mFirstChange )
252  {
253  // existing feature
254  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
255  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
256  mBuffer->mChangedAttributeValues.remove( mFid );
257 
258  if ( !mOldValue.isValid() )
259  {
260  // get old value from provider
261  QgsFeature tmp;
262  QgsFeatureRequest request;
263  request.setFilterFid( mFid );
265  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
266  QgsFeatureIterator fi = layer()->getFeatures( request );
267  if ( fi.nextFeature( tmp ) )
268  original = tmp.attribute( mFieldIndex );
269  }
270  }
271  else
272  {
273  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
274  }
275 
276  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
277 }
278 
280 {
281  if ( FID_IS_NEW( mFid ) )
282  {
283  // updated added feature
284  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
285  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
286  it.value().setAttribute( mFieldIndex, mNewValue );
287  }
288  else
289  {
290  // changed attribute of existing feature
291  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
292  {
294  }
295 
296  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
297  }
298 
299  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
300 }
301 
302 
304  : QgsVectorLayerUndoCommand( buffer )
305  , mField( field )
306 {
307  const QgsFields &fields = layer()->fields();
308  int i;
309  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
310  ;
311  mFieldIndex = i;
312 }
313 
315 {
316  int index = layer()->fields().fieldOriginIndex( mFieldIndex );
317 
318  mBuffer->mAddedAttributes.removeAt( index );
319  mBuffer->handleAttributeDeleted( mFieldIndex );
321 
322  emit mBuffer->attributeDeleted( mFieldIndex );
323 }
324 
326 {
327  mBuffer->mAddedAttributes.append( mField );
329  mBuffer->handleAttributeAdded( mFieldIndex );
330 
331  emit mBuffer->attributeAdded( mFieldIndex );
332 }
333 
334 
336  : QgsVectorLayerUndoCommand( buffer )
337  , mFieldIndex( fieldIndex )
338 {
339  const QgsFields& fields = layer()->fields();
340  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
341  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
342  mProviderField = ( origin == QgsFields::OriginProvider );
343  mFieldName = fields.field( mFieldIndex ).name();
344 
345  if ( !mProviderField )
346  {
347  // need to store the field definition
348  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
349  }
350 
351  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
352  {
353  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
354  }
355 
356  // save values of new features
357  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
358  {
359  const QgsFeature& f = it.value();
360  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
361  }
362 
363  // save changed values
364  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
365  {
366  const QgsAttributeMap& attrs = it.value();
367  if ( attrs.contains( mFieldIndex ) )
368  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
369  }
370 }
371 
373 {
374  if ( mProviderField )
375  {
376  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
377  }
378  else
379  {
380  // newly added attribute
381  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
382  }
383 
385  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
386 
387  if ( !mOldName.isEmpty() )
388  {
389  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
391  }
392 
393  // set previously used attributes of new features
394  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
395  {
396  QgsFeature& f = it.value();
397  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
398  }
399  // set previously used changed attributes
400  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
401  {
402  if ( !FID_IS_NEW( it.key() ) )
403  {
404  QgsAttributeMap& attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
405  attrs.insert( mFieldIndex, it.value() );
406  }
407  }
408 
409  QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
410  mBuffer->L->setEditFormConfig( formConfig );
411 
412  emit mBuffer->attributeAdded( mFieldIndex );
413 }
414 
416 {
417  if ( mProviderField )
418  {
419  mBuffer->mDeletedAttributeIds.append( mOriginIndex );
420  qSort( mBuffer->mDeletedAttributeIds ); // keep it sorted
421  }
422  else
423  {
424  // newly added attribute
425  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
426  }
427 
428  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
430  emit mBuffer->attributeDeleted( mFieldIndex );
431 }
432 
433 
435  : QgsVectorLayerUndoCommand( buffer )
436  , mFieldIndex( fieldIndex )
437  , mOldName( layer()->fields().at( fieldIndex ).name() )
438  , mNewName( newName )
439 {
440 }
441 
443 {
444  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
446  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
447 }
448 
450 {
451  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
453  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
454 }
QgsFeatureId id
Definition: qgsfeature.h:140
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature&#39;s geometry is changed.
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:47
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:161
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
QString name
Definition: qgsfield.h:53
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:45
void attributeDeleted(int idx)
QgsVectorLayerEditBuffer * mBuffer
Associated edit buffer.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Base class for undo commands within a QgsVectorLayerEditBuffer.
Container of fields for a vector layer.
Definition: qgsfields.h:39
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:79
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:213
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:46
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:136
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
QgsVectorLayerUndoCommandAddAttribute(QgsVectorLayerEditBuffer *buffer, const QgsField &field)
Constructor for QgsVectorLayerUndoCommandAddAttribute.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:199
int count() const
Return number of items.
Definition: qgsfields.cpp:115
QgsFields fields() const
Returns the list of fields of this layer.
QgsVectorLayerUndoCommandDeleteAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex)
Constructor for QgsVectorLayerUndoCommandDeleteAttribute.
int fieldOriginIndex(int fieldIdx) const
Get field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:169
void featureAdded(QgsFeatureId fid)
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Set feature ID that should be fetched.
void removeGeometry(QgsFeatureId fid)
get rid of the cached geometry
Undo command for modifying the geometry of a feature from a vector layer.
QgsVectorLayerUndoCommandChangeAttribute(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue)
Constructor for QgsVectorLayerUndoCommandChangeAttribute.
void attributeAdded(int idx)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
bool geometry(QgsFeatureId fid, QgsGeometry &geometry)
fetch geometry from cache, return true if successful
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
QgsVectorLayer * layer()
Returns the layer associated with the undo command.
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void handleAttributeAdded(int index)
Update added and changed features after addition of an attribute.
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
QgsVectorLayerUndoCommandChangeGeometry(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, const QgsGeometry &newGeom)
Constructor for QgsVectorLayerUndoCommandChangeGeometry.
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:45
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:124
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
QgsVectorLayerUndoCommandRenameAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex, const QString &newName)
Constructor for QgsVectorLayerUndoCommandRenameAttribute.
QgsEditFormConfig editFormConfig
void attributeRenamed(int idx, const QString &newName)
Emitted when an attribute has been renamed.
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
void cacheGeometry(QgsFeatureId fid, const QgsGeometry &geom)
store a geometry in the cache
qint64 QgsFeatureId
Definition: qgsfeature.h:33
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:39
virtual bool mergeWith(const QUndoCommand *) override
QgsVectorLayerUndoCommandDeleteFeature(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid)
Constructor for QgsVectorLayerUndoCommandDeleteFeature.
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Get the configuration of the form used to represent this vector layer.
QgsFeatureMap mAddedFeatures
New features which are not committed.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
QgsField field(int fieldIdx) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:140
void featureDeleted(QgsFeatureId fid)
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.