QGIS API Documentation  2.99.0-Master (c42dad3)
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 addedIdLowWaterMark = -1;
32 
33  //assign a temporary id to the feature (use negative numbers)
34  addedIdLowWaterMark--;
35 
36  QgsDebugMsgLevel( "Assigned feature id " + QString::number( addedIdLowWaterMark ), 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.setFeatureId( addedIdLowWaterMark );
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 }
161 
163 {
164  if ( FID_IS_NEW( mFid ) )
165  {
166  // modify added features
167  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
168  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
169  it.value().setGeometry( mOldGeom );
170 
171  cache()->cacheGeometry( mFid, mOldGeom );
172  emit mBuffer->geometryChanged( mFid, mOldGeom );
173  }
174  else
175  {
176  // existing feature
177 
178  if ( mOldGeom.isEmpty() )
179  {
180  mBuffer->mChangedGeometries.remove( mFid );
181 
182  QgsFeature f;
183  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.hasGeometry() )
184  {
185  cache()->cacheGeometry( mFid, f.geometry() );
186  emit mBuffer->geometryChanged( mFid, f.geometry() );
187  }
188  }
189  else
190  {
191  mBuffer->mChangedGeometries[mFid] = mOldGeom;
192  cache()->cacheGeometry( mFid, mOldGeom );
193  emit mBuffer->geometryChanged( mFid, mOldGeom );
194  }
195  }
196 
197 }
198 
200 {
201  if ( FID_IS_NEW( mFid ) )
202  {
203  // modify added features
204  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
205  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
206  it.value().setGeometry( mNewGeom );
207  }
208  else
209  {
210  mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
211  }
212  cache()->cacheGeometry( mFid, mNewGeom );
213  emit mBuffer->geometryChanged( mFid, mNewGeom );
214 }
215 
216 
217 QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer* buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
218  : QgsVectorLayerUndoCommand( buffer )
219  , mFid( fid )
220  , mFieldIndex( fieldIndex )
221  , mOldValue( oldValue )
222  , mNewValue( newValue )
223  , mFirstChange( true )
224 {
225  if ( FID_IS_NEW( mFid ) )
226  {
227  // work with added feature
228  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
229  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
230  if ( it.value().attribute( mFieldIndex ).isValid() )
231  {
232  mOldValue = it.value().attribute( mFieldIndex );
233  mFirstChange = false;
234  }
235  }
236  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
237  {
238  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
239  mFirstChange = false;
240  }
241 
242 }
243 
245 {
246  QVariant original = mOldValue;
247 
248  if ( FID_IS_NEW( mFid ) )
249  {
250  // added feature
251  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
252  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
253  it.value().setAttribute( mFieldIndex, mOldValue );
254  }
255  else if ( mFirstChange )
256  {
257  // existing feature
258  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
259  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
260  mBuffer->mChangedAttributeValues.remove( mFid );
261 
262  if ( !mOldValue.isValid() )
263  {
264  // get old value from provider
265  QgsFeature tmp;
266  QgsFeatureRequest request;
267  request.setFilterFid( mFid );
269  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
270  QgsFeatureIterator fi = layer()->getFeatures( request );
271  if ( fi.nextFeature( tmp ) )
272  original = tmp.attribute( mFieldIndex );
273  }
274  }
275  else
276  {
277  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
278  }
279 
280  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
281 }
282 
284 {
285  if ( FID_IS_NEW( mFid ) )
286  {
287  // updated added feature
288  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
289  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
290  it.value().setAttribute( mFieldIndex, mNewValue );
291  }
292  else
293  {
294  // changed attribute of existing feature
295  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
296  {
298  }
299 
300  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
301  }
302 
303  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
304 }
305 
306 
308  : QgsVectorLayerUndoCommand( buffer )
309  , mField( field )
310 {
311  const QgsFields &fields = layer()->fields();
312  int i;
313  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
314  ;
315  mFieldIndex = i;
316 }
317 
319 {
320  int index = layer()->fields().fieldOriginIndex( mFieldIndex );
321 
322  mBuffer->mAddedAttributes.removeAt( index );
323  mBuffer->handleAttributeDeleted( mFieldIndex );
325 
326  emit mBuffer->attributeDeleted( mFieldIndex );
327 }
328 
330 {
331  mBuffer->mAddedAttributes.append( mField );
333  mBuffer->handleAttributeAdded( mFieldIndex );
334 
335  emit mBuffer->attributeAdded( mFieldIndex );
336 }
337 
338 
340  : QgsVectorLayerUndoCommand( buffer )
341  , mFieldIndex( fieldIndex )
342 {
343  const QgsFields& fields = layer()->fields();
344  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
345  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
346  mProviderField = ( origin == QgsFields::OriginProvider );
347  mFieldName = fields.field( mFieldIndex ).name();
348  mOldEditorWidgetConfig = mBuffer->L->editFormConfig().widgetConfig( mFieldName );
349 
350  if ( !mProviderField )
351  {
352  // need to store the field definition
353  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
354  }
355 
356  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
357  {
358  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
359  }
360 
361  // save values of new features
362  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
363  {
364  const QgsFeature& f = it.value();
365  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
366  }
367 
368  // save changed values
369  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
370  {
371  const QgsAttributeMap& attrs = it.value();
372  if ( attrs.contains( mFieldIndex ) )
373  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
374  }
375 }
376 
378 {
379  if ( mProviderField )
380  {
381  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
382  }
383  else
384  {
385  // newly added attribute
386  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
387  }
388 
390  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
391 
392  if ( !mOldName.isEmpty() )
393  {
394  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
396  }
397 
398  // set previously used attributes of new features
399  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
400  {
401  QgsFeature& f = it.value();
402  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
403  }
404  // set previously used changed attributes
405  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
406  {
407  if ( !FID_IS_NEW( it.key() ) )
408  {
409  QgsAttributeMap& attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistant
410  attrs.insert( mFieldIndex, it.value() );
411  }
412  }
413 
414  QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
415  formConfig.setWidgetConfig( mFieldName, mOldEditorWidgetConfig );
416  mBuffer->L->setEditFormConfig( formConfig );
417 
418  emit mBuffer->attributeAdded( mFieldIndex );
419 }
420 
422 {
423  if ( mProviderField )
424  {
425  mBuffer->mDeletedAttributeIds.append( mOriginIndex );
426  qSort( mBuffer->mDeletedAttributeIds ); // keep it sorted
427  }
428  else
429  {
430  // newly added attribute
431  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
432  }
433 
434  mBuffer->L->editFormConfig().removeWidgetConfig( mFieldName );
435  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
437  emit mBuffer->attributeDeleted( mFieldIndex );
438 }
439 
440 
442  : QgsVectorLayerUndoCommand( buffer )
443  , mFieldIndex( fieldIndex )
444  , mOldName( layer()->fields().at( fieldIndex ).name() )
445  , mNewName( newName )
446 {
447 }
448 
450 {
451  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
453  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
454 }
455 
457 {
458  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
460  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
461 }
QgsFeatureId id
Definition: qgsfeature.h:139
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:44
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:163
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
QString name
Definition: qgsfield.h:55
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:44
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:36
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:78
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:228
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:43
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
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:214
int count() const
Return number of items.
Definition: qgsfields.cpp:117
void setWidgetConfig(const QString &fieldName, const QgsEditorWidgetConfig &config)
Set the editor widget config for a widget.
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:171
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.
void setFeatureId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:124
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:34
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.
bool removeWidgetConfig(const QString &fieldName)
Remove the configuration for the editor widget used to represent the field with the given name...
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:47
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 &)
QgsEditorWidgetConfig widgetConfig(const QString &fieldName) const
Get the configuration for the editor widget used to represent the field with the given name Don&#39;t use...
void cacheGeometry(QgsFeatureId fid, const QgsGeometry &geom)
store a geometry in the cache
qint64 QgsFeatureId
Definition: qgsfeature.h:32
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:38
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:277
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:142
void featureDeleted(QgsFeatureId fid)
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.