QGIS API Documentation  3.2.0-Bonn (bc43194)
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 ).setSubsetOfAttributes( QgsAttributeList() ) ).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 }
427 
429 {
430  mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
432  emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
433 }
434 
436 {
437  mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
439  emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
440 }
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
Gets 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: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.
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:104
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
Returns number of items.
Definition: qgsfields.cpp:115
QgsVectorLayerUndoCommandDeleteAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex)
Constructor for QgsVectorLayerUndoCommandDeleteAttribute.
int fieldOriginIndex(int fieldIdx) const
Gets 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)
Sets 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:39
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
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)
Set the editFormConfig (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
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:150
void featureDeleted(QgsFeatureId fid)
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.