QGIS API Documentation  2.99.0-Master (19b062c)
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  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  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  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  bool changedAlready = mBuffer->mChangedGeometries.contains( mFid );
122  QgsGeometry geom;
123  mOldGeom = changedAlready ? geom : QgsGeometry();
124  }
125 }
126 
128 {
129  return 1;
130 }
131 
132 bool QgsVectorLayerUndoCommandChangeGeometry::mergeWith( const QUndoCommand *other )
133 {
134  if ( other->id() != id() )
135  return false;
136 
137  const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
138  if ( !merge )
139  return false;
140 
141  if ( merge->mFid != mFid )
142  return false;
143 
144  mNewGeom = merge->mNewGeom;
145  merge->mNewGeom = QgsGeometry();
146 
147  return true;
148 }
149 
151 {
152  if ( FID_IS_NEW( mFid ) )
153  {
154  // modify added features
155  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
156  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
157  it.value().setGeometry( mOldGeom );
158 
159  emit mBuffer->geometryChanged( mFid, mOldGeom );
160  }
161  else
162  {
163  // existing feature
164 
165  if ( mOldGeom.isNull() )
166  {
167  mBuffer->mChangedGeometries.remove( mFid );
168 
169  QgsFeature f;
170  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.hasGeometry() )
171  {
172  emit mBuffer->geometryChanged( mFid, f.geometry() );
173  }
174  }
175  else
176  {
177  mBuffer->mChangedGeometries[mFid] = mOldGeom;
178  emit mBuffer->geometryChanged( mFid, mOldGeom );
179  }
180  }
181 
182 }
183 
185 {
186  if ( FID_IS_NEW( mFid ) )
187  {
188  // modify added features
189  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
190  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
191  it.value().setGeometry( mNewGeom );
192  }
193  else
194  {
195  mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
196  }
197  emit mBuffer->geometryChanged( mFid, mNewGeom );
198 }
199 
200 
201 QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
202  : QgsVectorLayerUndoCommand( buffer )
203  , mFid( fid )
204  , mFieldIndex( fieldIndex )
205  , mOldValue( oldValue )
206  , mNewValue( newValue )
207  , mFirstChange( true )
208 {
209  if ( FID_IS_NEW( mFid ) )
210  {
211  // work with added feature
212  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
213  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
214  if ( it.value().attribute( mFieldIndex ).isValid() )
215  {
216  mOldValue = it.value().attribute( mFieldIndex );
217  mFirstChange = false;
218  }
219  }
220  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
221  {
222  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
223  mFirstChange = false;
224  }
225 
226 }
227 
229 {
230  QVariant original = mOldValue;
231 
232  if ( FID_IS_NEW( mFid ) )
233  {
234  // added feature
235  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
236  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
237  it.value().setAttribute( mFieldIndex, mOldValue );
238  }
239  else if ( mFirstChange )
240  {
241  // existing feature
242  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
243  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
244  mBuffer->mChangedAttributeValues.remove( mFid );
245 
246  if ( !mOldValue.isValid() )
247  {
248  // get old value from provider
249  QgsFeature tmp;
250  QgsFeatureRequest request;
251  request.setFilterFid( mFid );
253  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
254  QgsFeatureIterator fi = layer()->getFeatures( request );
255  if ( fi.nextFeature( tmp ) )
256  original = tmp.attribute( mFieldIndex );
257  }
258  }
259  else
260  {
261  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
262  }
263 
264  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
265 }
266 
268 {
269  if ( FID_IS_NEW( mFid ) )
270  {
271  // updated added feature
272  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
273  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
274  it.value().setAttribute( mFieldIndex, mNewValue );
275  }
276  else
277  {
278  // changed attribute of existing feature
279  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
280  {
282  }
283 
284  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
285  }
286 
287  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
288 }
289 
290 
292  : QgsVectorLayerUndoCommand( buffer )
293  , mField( field )
294 {
295  const QgsFields &fields = layer()->fields();
296  int i;
297  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
298  ;
299  mFieldIndex = i;
300 }
301 
303 {
304  int index = layer()->fields().fieldOriginIndex( mFieldIndex );
305 
306  mBuffer->mAddedAttributes.removeAt( index );
307  mBuffer->handleAttributeDeleted( mFieldIndex );
309 
310  emit mBuffer->attributeDeleted( mFieldIndex );
311 }
312 
314 {
315  mBuffer->mAddedAttributes.append( mField );
317  mBuffer->handleAttributeAdded( mFieldIndex );
318 
319  emit mBuffer->attributeAdded( mFieldIndex );
320 }
321 
322 
324  : QgsVectorLayerUndoCommand( buffer )
325  , mFieldIndex( fieldIndex )
326 {
327  const QgsFields &fields = layer()->fields();
328  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
329  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
330  mProviderField = ( origin == QgsFields::OriginProvider );
331  mFieldName = fields.field( mFieldIndex ).name();
332 
333  if ( !mProviderField )
334  {
335  // need to store the field definition
336  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
337  }
338 
339  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
340  {
341  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
342  }
343 
344  // save values of new features
345  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
346  {
347  const QgsFeature &f = it.value();
348  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
349  }
350 
351  // save changed values
352  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
353  {
354  const QgsAttributeMap &attrs = it.value();
355  if ( attrs.contains( mFieldIndex ) )
356  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
357  }
358 }
359 
361 {
362  if ( mProviderField )
363  {
364  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
365  }
366  else
367  {
368  // newly added attribute
369  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
370  }
371 
373  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
374 
375  if ( !mOldName.isEmpty() )
376  {
377  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
379  }
380 
381  // set previously used attributes of new features
382  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
383  {
384  QgsFeature &f = it.value();
385  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
386  }
387  // set previously used changed attributes
388  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
389  {
390  if ( !FID_IS_NEW( it.key() ) )
391  {
392  QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
393  attrs.insert( mFieldIndex, it.value() );
394  }
395  }
396 
397  QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
398  mBuffer->L->setEditFormConfig( formConfig );
399 
400  emit mBuffer->attributeAdded( mFieldIndex );
401 }
402 
404 {
405  if ( mProviderField )
406  {
407  mBuffer->mDeletedAttributeIds.append( mOriginIndex );
408  std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
409  }
410  else
411  {
412  // newly added attribute
413  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
414  }
415 
416  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
418  emit mBuffer->attributeDeleted( mFieldIndex );
419 }
420 
421 
423  : QgsVectorLayerUndoCommand( buffer )
424  , mFieldIndex( fieldIndex )
425  , mOldName( layer()->fields().at( fieldIndex ).name() )
426  , mNewName( newName )
427 {
428 }
429 
431 {
432  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
434  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
435 }
436 
438 {
439  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
441  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
442 }
QgsFeatureId id
Definition: qgsfeature.h:71
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:50
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:171
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
QString name
Definition: qgsfield.h:56
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:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
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:49
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
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
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:179
void featureAdded(QgsFeatureId fid)
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Set feature ID that should be fetched.
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)
QgsFields fields() const override
Returns the list of fields of this layer.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
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)...
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:48
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.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
qint64 QgsFeatureId
Definition: qgsfeature.h:37
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:50
virtual bool mergeWith(const QUndoCommand *) override
QList< int > QgsAttributeList
Definition: qgsfield.h:27
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:150
void featureDeleted(QgsFeatureId fid)
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.