QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  mOldGeom = mBuffer->mChangedGeometries.value( mFid, QgsGeometry() );
122  }
123 }
124 
126 {
127  return 1;
128 }
129 
130 bool QgsVectorLayerUndoCommandChangeGeometry::mergeWith( const QUndoCommand *other )
131 {
132  if ( other->id() != id() )
133  return false;
134 
135  const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
136  if ( !merge )
137  return false;
138 
139  if ( merge->mFid != mFid )
140  return false;
141 
142  mNewGeom = merge->mNewGeom;
143  merge->mNewGeom = QgsGeometry();
144 
145  return true;
146 }
147 
149 {
150  if ( FID_IS_NEW( mFid ) )
151  {
152  // modify added features
153  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
154  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
155  it.value().setGeometry( mOldGeom );
156 
157  emit mBuffer->geometryChanged( mFid, mOldGeom );
158  }
159  else
160  {
161  // existing feature
162 
163  if ( mOldGeom.isNull() )
164  {
165  mBuffer->mChangedGeometries.remove( mFid );
166 
167  QgsFeature f;
168  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setNoAttributes() ).nextFeature( f ) && f.hasGeometry() )
169  {
170  emit mBuffer->geometryChanged( mFid, f.geometry() );
171  }
172  }
173  else
174  {
175  mBuffer->mChangedGeometries[mFid] = mOldGeom;
176  emit mBuffer->geometryChanged( mFid, mOldGeom );
177  }
178  }
179 
180 }
181 
183 {
184  if ( FID_IS_NEW( mFid ) )
185  {
186  // modify added features
187  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
188  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
189  it.value().setGeometry( mNewGeom );
190  }
191  else
192  {
193  mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
194  }
195  emit mBuffer->geometryChanged( mFid, mNewGeom );
196 }
197 
198 
199 QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
200  : QgsVectorLayerUndoCommand( buffer )
201  , mFid( fid )
202  , mFieldIndex( fieldIndex )
203  , mOldValue( oldValue )
204  , mNewValue( newValue )
205  , mFirstChange( true )
206 {
207  if ( FID_IS_NEW( mFid ) )
208  {
209  // work with added feature
210  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
211  Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
212  if ( it.value().attribute( mFieldIndex ).isValid() )
213  {
214  mOldValue = it.value().attribute( mFieldIndex );
215  mFirstChange = false;
216  }
217  }
218  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
219  {
220  mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
221  mFirstChange = false;
222  }
223 
224 }
225 
227 {
228  QVariant original = mOldValue;
229 
230  if ( FID_IS_NEW( mFid ) )
231  {
232  // added feature
233  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
234  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
235  it.value().setAttribute( mFieldIndex, mOldValue );
236  }
237  else if ( mFirstChange )
238  {
239  // existing feature
240  mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
241  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
242  mBuffer->mChangedAttributeValues.remove( mFid );
243 
244  if ( !mOldValue.isValid() )
245  {
246  // get old value from provider
247  QgsFeature tmp;
248  QgsFeatureRequest request;
249  request.setFilterFid( mFid );
251  request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
252  QgsFeatureIterator fi = layer()->getFeatures( request );
253  if ( fi.nextFeature( tmp ) )
254  original = tmp.attribute( mFieldIndex );
255  }
256  }
257  else
258  {
259  mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
260  }
261 
262  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
263 }
264 
266 {
267  if ( FID_IS_NEW( mFid ) )
268  {
269  // updated added feature
270  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
271  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
272  it.value().setAttribute( mFieldIndex, mNewValue );
273  }
274  else
275  {
276  // changed attribute of existing feature
277  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
278  {
280  }
281 
282  mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
283  }
284 
285  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
286 }
287 
288 
290  : QgsVectorLayerUndoCommand( buffer )
291  , mField( field )
292 {
293  const QgsFields &fields = layer()->fields();
294  int i;
295  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
296  ;
297  mFieldIndex = i;
298 }
299 
301 {
302  int index = layer()->fields().fieldOriginIndex( mFieldIndex );
303 
304  mBuffer->mAddedAttributes.removeAt( index );
305  mBuffer->handleAttributeDeleted( mFieldIndex );
307 
308  emit mBuffer->attributeDeleted( mFieldIndex );
309 }
310 
312 {
313  mBuffer->mAddedAttributes.append( mField );
314  mBuffer->handleAttributeAdded( mFieldIndex );
316 
317  emit mBuffer->attributeAdded( mFieldIndex );
318 }
319 
320 
322  : QgsVectorLayerUndoCommand( buffer )
323  , mFieldIndex( fieldIndex )
324 {
325  const QgsFields &fields = layer()->fields();
326  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
327  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
328  mProviderField = ( origin == QgsFields::OriginProvider );
329  mFieldName = fields.field( mFieldIndex ).name();
330 
331  if ( !mProviderField )
332  {
333  // need to store the field definition
334  mOldField = mBuffer->mAddedAttributes[mOriginIndex];
335  }
336 
337  if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
338  {
339  mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
340  }
341 
342  // save values of new features
343  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
344  {
345  const QgsFeature &f = it.value();
346  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
347  }
348 
349  // save changed values
350  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
351  {
352  const QgsAttributeMap &attrs = it.value();
353  if ( attrs.contains( mFieldIndex ) )
354  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
355  }
356 }
357 
359 {
360  if ( mProviderField )
361  {
362  mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
363  }
364  else
365  {
366  // newly added attribute
367  mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
368  }
369 
371  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
372 
373  if ( !mOldName.isEmpty() )
374  {
375  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
377  }
378 
379  // set previously used attributes of new features
380  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
381  {
382  QgsFeature &f = it.value();
383  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
384  }
385  // set previously used changed attributes
386  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
387  {
388  if ( !FID_IS_NEW( it.key() ) )
389  {
390  QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
391  attrs.insert( mFieldIndex, it.value() );
392  }
393  }
394 
395  QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
396  mBuffer->L->setEditFormConfig( formConfig );
397 
398  emit mBuffer->attributeAdded( mFieldIndex );
399 }
400 
402 {
403  if ( mProviderField )
404  {
405  mBuffer->mDeletedAttributeIds.append( mOriginIndex );
406  std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
407  }
408  else
409  {
410  // newly added attribute
411  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
412  }
413 
414  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
416  emit mBuffer->attributeDeleted( mFieldIndex );
417 }
418 
419 
421  : QgsVectorLayerUndoCommand( buffer )
422  , mFieldIndex( fieldIndex )
423  , mOldName( layer()->fields().at( fieldIndex ).name() )
424  , mNewName( newName )
425 {
426  const QgsFields &fields = layer()->fields();
427  QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
428  mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
429  mProviderField = ( origin == QgsFields::OriginProvider );
430 }
431 
433 {
434  if ( mProviderField )
435  {
436  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
437  }
438  else
439  {
440  // newly added attribute
441  mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
442  }
444  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
445 }
446 
448 {
449  if ( mProviderField )
450  {
451  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
452  }
453  else
454  {
455  // newly added attribute
456  mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
457  }
459  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
460 }
QgsFeatureId id
Definition: qgsfeature.h:64
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
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
QString name
Definition: qgsfield.h:57
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.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
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:106
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
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:55
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
QgsVectorLayerUndoCommandAddAttribute(QgsVectorLayerEditBuffer *buffer, const QgsField &field)
Constructor for QgsVectorLayerUndoCommandAddAttribute.
QgsVectorLayerUndoCommandDeleteAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex)
Constructor for QgsVectorLayerUndoCommandDeleteAttribute.
void featureAdded(QgsFeatureId fid)
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
Undo command for modifying the geometry of a feature from a vector layer.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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:39
QgsVectorLayer * layer()
Returns the layer associated with the undo command.
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
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.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
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
QgsVectorLayerUndoCommandRenameAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex, const QString &newName)
Constructor for QgsVectorLayerUndoCommandRenameAttribute.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:168
QgsEditFormConfig editFormConfig
void attributeRenamed(int idx, const QString &newName)
Emitted when an attribute has been renamed.
#define FID_IS_NEW(fid)
Definition: qgsfeatureid.h:28
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
bool mergeWith(const QUndoCommand *) override
QgsGeometry geometry
Definition: qgsfeature.h:67
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)
Set the editFormConfig (configuration) of the form used to represent this vector layer.
QgsFeatureMap mAddedFeatures
New features which are not committed.
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
void featureDeleted(QgsFeatureId fid)
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.