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