QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 "qgsgeometry.h"
19 #include "qgsfeature.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsgeometrycache.h"
23 
24 #include "qgslogger.h"
25 
26 
28  : QgsVectorLayerUndoCommand( buffer )
29 {
30  static int addedIdLowWaterMark = -1;
31 
32  //assign a temporary id to the feature (use negative numbers)
33  addedIdLowWaterMark--;
34 
35  QgsDebugMsg( "Assigned feature id " + QString::number( addedIdLowWaterMark ) );
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.setFeatureId( addedIdLowWaterMark );
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  if ( mFeature.constGeometry() )
54  cache()->removeGeometry( mFeature.id() );
55 
56  emit mBuffer->featureDeleted( mFeature.id() );
57 }
58 
60 {
61  mBuffer->mAddedFeatures.insert( mFeature.id(), mFeature );
62 
63  if ( mFeature.constGeometry() )
64  cache()->cacheGeometry( mFeature.id(), *mFeature.constGeometry() );
65 
66  emit mBuffer->featureAdded( mFeature.id() );
67 }
68 
69 
70 
72  : QgsVectorLayerUndoCommand( buffer )
73 {
74  mFid = fid;
75 
76  if ( FID_IS_NEW( mFid ) )
77  {
78  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
79  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
80  mOldAddedFeature = it.value();
81  }
82 }
83 
85 {
86  if ( FID_IS_NEW( mFid ) )
87  {
88  mBuffer->mAddedFeatures.insert( mOldAddedFeature.id(), mOldAddedFeature );
89  }
90  else
91  {
93  }
94 
95  emit mBuffer->featureAdded( mFid );
96 }
97 
99 {
100  if ( FID_IS_NEW( mFid ) )
101  {
102  mBuffer->mAddedFeatures.remove( mFid );
103  }
104  else
105  {
107  }
108 
109  emit mBuffer->featureDeleted( mFid );
110 }
111 
112 
113 
115  : QgsVectorLayerUndoCommand( buffer )
116  , mFid( fid )
117 {
118  if ( FID_IS_NEW( mFid ) )
119  {
120  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
121  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
122  mOldGeom = ( it.value().constGeometry() ? new QgsGeometry( *it.value().constGeometry() ) : nullptr );
123  }
124  else
125  {
126  bool changedAlready = mBuffer->mChangedGeometries.contains( mFid );
127  QgsGeometry geom;
128  bool cachedGeom = cache()->geometry( mFid, geom );
129  mOldGeom = ( changedAlready && cachedGeom ) ? new QgsGeometry( geom ) : nullptr;
130  }
131 
132  mNewGeom = new QgsGeometry( *newGeom );
133 }
134 
136 {
137  return 1;
138 }
139 
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  delete mNewGeom;
153  mNewGeom = merge->mNewGeom;
154  merge->mNewGeom = nullptr;
155 
156  return true;
157 }
158 
160 {
161  delete mOldGeom;
162  delete mNewGeom;
163 }
164 
166 {
167  if ( FID_IS_NEW( mFid ) )
168  {
169  // modify added features
170  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
171  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
172  it.value().setGeometry( *mOldGeom );
173 
174  cache()->cacheGeometry( mFid, *mOldGeom );
175  emit mBuffer->geometryChanged( mFid, *mOldGeom );
176  }
177  else
178  {
179  // existing feature
180 
181  if ( !mOldGeom )
182  {
184 
185  QgsFeature f;
186  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.constGeometry() )
187  {
188  cache()->cacheGeometry( mFid, *f.constGeometry() );
189  emit mBuffer->geometryChanged( mFid, *f.geometry() );
190  }
191  }
192  else
193  {
194  mBuffer->mChangedGeometries[mFid] = *mOldGeom;
195  cache()->cacheGeometry( mFid, *mOldGeom );
196  emit mBuffer->geometryChanged( mFid, *mOldGeom );
197  }
198  }
199 
200 }
201 
203 {
204  if ( FID_IS_NEW( mFid ) )
205  {
206  // modify added features
207  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
208  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
209  it.value().setGeometry( *mNewGeom );
210  }
211  else
212  {
213  mBuffer->mChangedGeometries[ mFid ] = *mNewGeom;
214  }
215  cache()->cacheGeometry( mFid, *mNewGeom );
216  emit mBuffer->geometryChanged( mFid, *mNewGeom );
217 }
218 
219 
221  : QgsVectorLayerUndoCommand( buffer )
222  , mFid( fid )
223  , mFieldIndex( fieldIndex )
224  , mOldValue( oldValue )
225  , mNewValue( newValue )
226  , mFirstChange( true )
227 {
228  if ( FID_IS_NEW( mFid ) )
229  {
230  // work with added feature
231  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
232  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
233  if ( it.value().attribute( mFieldIndex ).isValid() )
234  {
235  mOldValue = it.value().attribute( mFieldIndex );
236  mFirstChange = false;
237  }
238  }
239  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
240  {
241  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
242  mFirstChange = false;
243  }
244 
245 }
246 
248 {
249  QVariant original = mOldValue;
250 
251  if ( FID_IS_NEW( mFid ) )
252  {
253  // added feature
254  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
255  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
256  it.value().setAttribute( mFieldIndex, mOldValue );
257  }
258  else if ( mFirstChange )
259  {
260  // existing feature
261  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
262  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
264 
265  if ( !mOldValue.isValid() )
266  {
267  // get old value from provider
268  QgsFeature tmp;
269  QgsFeatureRequest request;
270  request.setFilterFid( mFid );
272  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
273  QgsFeatureIterator fi = layer()->getFeatures( request );
274  if ( fi.nextFeature( tmp ) )
275  original = tmp.attribute( mFieldIndex );
276  }
277  }
278  else
279  {
280  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
281  }
282 
283  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
284 }
285 
287 {
288  if ( FID_IS_NEW( mFid ) )
289  {
290  // updated added feature
291  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
292  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
293  it.value().setAttribute( mFieldIndex, mNewValue );
294  }
295  else
296  {
297  // changed attribute of existing feature
298  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
299  {
301  }
302 
303  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
304  }
305 
306  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
307 }
308 
309 
311  : QgsVectorLayerUndoCommand( buffer )
312  , mField( field )
313 {
314  const QgsFields &fields = layer()->fields();
315  int i;
316  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
317  ;
318  mFieldIndex = i;
319 }
320 
322 {
323  int index = layer()->fields().fieldOriginIndex( mFieldIndex );
324 
326  mBuffer->handleAttributeDeleted( mFieldIndex );
328 
329  emit mBuffer->attributeDeleted( mFieldIndex );
330 }
331 
333 {
334  mBuffer->mAddedAttributes.append( mField );
336  mBuffer->handleAttributeAdded( mFieldIndex );
337 
338  emit mBuffer->attributeAdded( mFieldIndex );
339 }
340 
341 
343  : QgsVectorLayerUndoCommand( buffer )
344  , mFieldIndex( fieldIndex )
345 {
346  const QgsFields& fields = layer()->fields();
347  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
348  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
349  mProviderField = ( origin == QgsFields::OriginProvider );
350  mOldEditorWidgetConfig = mBuffer->L->editFormConfig()->widgetConfig( mFieldIndex );
351 
352  if ( !mProviderField )
353  {
354  // need to store the field definition
355  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
356  }
357 
358  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
359  {
360  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
361  }
362 
363  // save values of new features
364  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
365  {
366  const QgsFeature& f = it.value();
367  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
368  }
369 
370  // save changed values
371  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
372  {
373  const QgsAttributeMap& attrs = it.value();
374  if ( attrs.contains( mFieldIndex ) )
375  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
376  }
377 }
378 
380 {
381  if ( mProviderField )
382  {
383  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
384  }
385  else
386  {
387  // newly added attribute
388  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
389  }
390 
392  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
393 
394  if ( !mOldName.isEmpty() )
395  {
396  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
398  }
399 
400  // set previously used attributes of new features
401  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
402  {
403  QgsFeature& f = it.value();
404  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
405  }
406  // set previously used changed attributes
407  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
408  {
409  if ( !FID_IS_NEW( it.key() ) )
410  {
411  QgsAttributeMap& attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistant
412  attrs.insert( mFieldIndex, it.value() );
413  }
414  }
415 
416  mBuffer->L->editFormConfig()->setWidgetConfig( mFieldIndex, mOldEditorWidgetConfig );
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( mFieldIndex );
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 }
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
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: qgsfield.h:260
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfield.cpp:448
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
bool contains(const Key &key) const
void setWidgetConfig(int attrIdx, const QgsEditorWidgetConfig &config)
Set the editor widget config for a field.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:104
bool removeWidgetConfig(int fieldIdx)
Remove the configuration for the editor widget used to represent the field at the given index...
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void attributeDeleted(int idx)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
const_iterator constBegin() const
QgsVectorLayerEditBuffer * mBuffer
Associated edit buffer.
void removeAt(int i)
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
T value() const
Base class for undo commands within a QgsVectorLayerEditBuffer.
Container of fields for a vector layer.
Definition: qgsfield.h:252
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not commited.
const_iterator constFind(const Key &key) const
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfield.h:259
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not commited.
QgsVectorLayerUndoCommandAddAttribute(QgsVectorLayerEditBuffer *buffer, const QgsField &field)
Constructor for QgsVectorLayerUndoCommandAddAttribute.
int count() const
Return number of items.
Definition: qgsfield.cpp:402
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
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: qgsfield.cpp:456
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.
QString number(int n, int base)
void append(const T &value)
void setFeatureId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:101
QgsVectorLayerUndoCommandChangeAttribute(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue)
Constructor for QgsVectorLayerUndoCommandChangeAttribute.
void attributeAdded(int idx)
void geometryChanged(QgsFeatureId fid, QgsGeometry &geom)
bool geometry(QgsFeatureId fid, QgsGeometry &geometry)
fetch geometry from cache, return true if successful
bool isEmpty() const
QgsVectorLayer * layer()
Returns the layer associated with the undo command.
const_iterator constEnd() const
QgsGeometryMap mChangedGeometries
Changed geometries which are not commited.
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.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not commited.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
iterator end()
QgsVectorLayerUndoCommandRenameAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex, const QString &newName)
Constructor for QgsVectorLayerUndoCommandRenameAttribute.
void attributeRenamed(int idx, const QString &newName)
Emitted when an attribute has been renamed.
iterator begin()
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:76
QgsEditorWidgetConfig widgetConfig(int fieldIdx) const
Get the configuration for the editor widget used to represent the field at the given index...
QList< QgsField > mAddedAttributes
Added attributes fields which are not commited.
bool remove(const T &value)
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
void insert(int i, const T &value)
void cacheGeometry(QgsFeatureId fid, const QgsGeometry &geom)
store a geometry in the cache
qint64 QgsFeatureId
Definition: qgsfeature.h:31
bool isValid() const
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:87
iterator insert(const Key &key, const T &value)
QgsVectorLayerUndoCommandChangeGeometry(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, QgsGeometry *newGeom)
Constructor for QgsVectorLayerUndoCommandChangeGeometry.
virtual bool mergeWith(const QUndoCommand *) override
bool isEmpty() const
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.
QgsFeatureMap mAddedFeatures
New features which are not commited.
virtual int id() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
bool removeOne(const T &value)
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not commited.
iterator find(const Key &key)
void featureDeleted(QgsFeatureId fid)
const T value(const Key &key) const
int remove(const Key &key)