QGIS API Documentation  3.23.0-Master (dd0cd13a00)
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  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
209  if ( it.value().attribute( mFieldIndex ).isValid() )
210  {
211  mOldValue = it.value().attribute( mFieldIndex );
212  mFirstChange = false;
213  }
214  }
215  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
216  {
217  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
218  mFirstChange = false;
219  }
220 
221 }
222 
224 {
225  QVariant original = mOldValue;
226 
227  if ( FID_IS_NEW( mFid ) )
228  {
229  // added feature
230  const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
231  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
232  it.value().setAttribute( mFieldIndex, mOldValue );
233  }
234  else if ( mFirstChange )
235  {
236  // existing feature
237  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
238  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
239  mBuffer->mChangedAttributeValues.remove( mFid );
240 
241  if ( !mOldValue.isValid() )
242  {
243  // get old value from provider
244  QgsFeature tmp;
245  QgsFeatureRequest request;
246  request.setFilterFid( mFid );
248  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
249  QgsFeatureIterator fi = layer()->getFeatures( request );
250  if ( fi.nextFeature( tmp ) )
251  original = tmp.attribute( mFieldIndex );
252  }
253  }
254  else
255  {
256  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
257  }
258 
259  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
260 }
261 
263 {
264  if ( FID_IS_NEW( mFid ) )
265  {
266  // updated added feature
267  const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
268  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
269  it.value().setAttribute( mFieldIndex, mNewValue );
270  }
271  else
272  {
273  // changed attribute of existing feature
274  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
275  {
277  }
278 
279  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
280  }
281 
282  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
283 }
284 
285 
287  : QgsVectorLayerUndoCommand( buffer )
288  , mField( field )
289 {
290  const QgsFields &fields = layer()->fields();
291  int i;
292  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
293  ;
294  mFieldIndex = i;
295 }
296 
298 {
299  const int index = layer()->fields().fieldOriginIndex( mFieldIndex );
300 
301  mBuffer->mAddedAttributes.removeAt( index );
302  mBuffer->handleAttributeDeleted( mFieldIndex );
304 
305  emit mBuffer->attributeDeleted( mFieldIndex );
306 }
307 
309 {
310  mBuffer->mAddedAttributes.append( mField );
311  mBuffer->handleAttributeAdded( mFieldIndex );
313 
314  emit mBuffer->attributeAdded( mFieldIndex );
315 }
316 
317 
319  : QgsVectorLayerUndoCommand( buffer )
320  , mFieldIndex( fieldIndex )
321 {
322  const QgsFields &fields = layer()->fields();
323  const QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
324  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
325  mProviderField = ( origin == QgsFields::OriginProvider );
326  mFieldName = fields.field( mFieldIndex ).name();
327 
328  if ( !mProviderField )
329  {
330  // need to store the field definition
331  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
332  }
333 
334  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
335  {
336  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
337  }
338 
339  // save values of new features
340  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
341  {
342  const QgsFeature &f = it.value();
343  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
344  }
345 
346  // save changed values
347  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
348  {
349  const QgsAttributeMap &attrs = it.value();
350  if ( attrs.contains( mFieldIndex ) )
351  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
352  }
353 }
354 
356 {
357  if ( mProviderField )
358  {
359  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
360  }
361  else
362  {
363  // newly added attribute
364  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
365  }
366 
368  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
369 
370  if ( !mOldName.isEmpty() )
371  {
372  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
374  }
375 
376  // set previously used attributes of new features
377  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
378  {
379  QgsFeature &f = it.value();
380  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
381  }
382  // set previously used changed attributes
383  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
384  {
385  if ( !FID_IS_NEW( it.key() ) )
386  {
387  QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
388  attrs.insert( mFieldIndex, it.value() );
389  }
390  }
391 
392  const QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
393  mBuffer->L->setEditFormConfig( formConfig );
394 
395  emit mBuffer->attributeAdded( mFieldIndex );
396 }
397 
399 {
400  if ( mProviderField )
401  {
402  mBuffer->mDeletedAttributeIds.append( mOriginIndex );
403  std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
404  }
405  else
406  {
407  // newly added attribute
408  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
409  }
410 
411  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
413  emit mBuffer->attributeDeleted( mFieldIndex );
414 }
415 
416 
418  : QgsVectorLayerUndoCommand( buffer )
419  , mFieldIndex( fieldIndex )
420  , mOldName( layer()->fields().at( fieldIndex ).name() )
421  , mNewName( newName )
422 {
423  const QgsFields &fields = layer()->fields();
424  const QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
425  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
426  mProviderField = ( origin == QgsFields::OriginProvider );
427 }
428 
430 {
431  if ( mProviderField )
432  {
433  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
434  }
435  else
436  {
437  // newly added attribute
438  mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
439  }
441  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
442 }
443 
445 {
446  if ( mProviderField )
447  {
448  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
449  }
450  else
451  {
452  // newly added attribute
453  mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
454  }
456  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
457 }
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