QGIS API Documentation  2.99.0-Master (cb63e82)
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.isNull() )
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  std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // 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:70
Wrapper for iterator of features from vector data provider or vector layer.
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
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
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:204
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:61
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:190
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.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:39
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.
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:112
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
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:37
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:50
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:255
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.