QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
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 const 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
67{
68 mFid = fid;
69
70 if ( FID_IS_NEW( mFid ) )
71 {
72 const 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 const 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
125
126
128{
129 if ( other->id() != id() )
130 return false;
131
132 const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
133 if ( !merge )
134 return false;
135
136 if ( merge->mFid != mFid )
137 return false;
138
139 mNewGeom = merge->mNewGeom;
140 merge->mNewGeom = QgsGeometry();
141
142 return true;
143}
144
146{
147 if ( FID_IS_NEW( mFid ) )
148 {
149 // modify added features
150 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
151 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
152 it.value().setGeometry( mOldGeom );
153
154 emit mBuffer->geometryChanged( mFid, mOldGeom );
155 }
156 else
157 {
158 // existing feature
159
160 if ( mOldGeom.isNull() )
161 {
162 mBuffer->mChangedGeometries.remove( mFid );
163
164 QgsFeature f;
165 if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setNoAttributes() ).nextFeature( f ) && f.hasGeometry() )
166 {
167 emit mBuffer->geometryChanged( mFid, f.geometry() );
168 }
169 }
170 else
171 {
172 mBuffer->mChangedGeometries[mFid] = mOldGeom;
173 emit mBuffer->geometryChanged( mFid, mOldGeom );
174 }
175 }
176
177}
178
180{
181 if ( FID_IS_NEW( mFid ) )
182 {
183 // modify added features
184 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
185 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
186 it.value().setGeometry( mNewGeom );
187 }
188 else
189 {
190 mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
191 }
192 emit mBuffer->geometryChanged( mFid, mNewGeom );
193}
194
195
196QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
197 : QgsVectorLayerUndoCommand( buffer )
198 , mFid( fid )
199 , mFieldIndex( fieldIndex )
200 , mOldValue( oldValue )
201 , mNewValue( newValue )
202 , mFirstChange( true )
203{
204 if ( FID_IS_NEW( mFid ) )
205 {
206 // work with added feature
207 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
208 if ( it != mBuffer->mAddedFeatures.constEnd() )
209 {
210 if ( it.value().attribute( mFieldIndex ).isValid() )
211 {
212 mOldValue = it.value().attribute( mFieldIndex );
213 mFirstChange = false;
214 }
215 }
216 else
217 {
218 // TODO: report a programmatic error ?
219 }
220 }
221 else
222 {
223 // work with existing feature
224 const QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constFind( mFid );
225 if ( it != mBuffer->mChangedAttributeValues.constEnd() )
226 {
227 if ( it->contains( mFieldIndex ) )
228 {
229 mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
230 mFirstChange = false;
231 }
232 }
233 else
234 {
235 // TODO: report a programmatic error ?
236 }
237 }
238
239}
240
242{
243 QVariant original = mOldValue;
244
245 if ( FID_IS_NEW( mFid ) )
246 {
247 // added feature
248 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
249 if ( it == mBuffer->mAddedFeatures.end() )
250 {
251 // the feature must have been removed, nothing to undo here
252 // See https://github.com/qgis/QGIS/issues/23243
253 }
254 else
255 {
256 //Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
257 it.value().setAttribute( mFieldIndex, mOldValue );
258 }
259 }
260 else if ( mFirstChange )
261 {
262 // existing feature
263 mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
264 if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
265 mBuffer->mChangedAttributeValues.remove( mFid );
266
267 if ( !mOldValue.isValid() )
268 {
269 // get old value from provider
270 QgsFeature tmp;
271 QgsFeatureRequest request;
272 request.setFilterFid( mFid );
274 request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
275 QgsFeatureIterator fi = layer()->getFeatures( request );
276 if ( fi.nextFeature( tmp ) )
277 original = tmp.attribute( mFieldIndex );
278 }
279 }
280 else
281 {
282 mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
283 }
284
285 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
286}
287
289{
290 if ( FID_IS_NEW( mFid ) )
291 {
292 // updated added feature
293 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
294 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
295 it.value().setAttribute( mFieldIndex, mNewValue );
296 }
297 else
298 {
299 // changed attribute of existing feature
300 if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
301 {
303 }
304
305 mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
306 }
307
308 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
309}
310
311
313 : QgsVectorLayerUndoCommand( buffer )
314 , mField( field )
315{
316 const QgsFields &fields = layer()->fields();
317 int i;
318 for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
319 ;
320 mFieldIndex = i;
321}
322
324{
325 const int index = layer()->fields().fieldOriginIndex( mFieldIndex );
326
327 mBuffer->mAddedAttributes.removeAt( index );
328 mBuffer->handleAttributeDeleted( mFieldIndex );
330
331 emit mBuffer->attributeDeleted( mFieldIndex );
332}
333
335{
336 mBuffer->mAddedAttributes.append( mField );
337 mBuffer->handleAttributeAdded( mFieldIndex );
339
340 emit mBuffer->attributeAdded( mFieldIndex );
341}
342
343
345 : QgsVectorLayerUndoCommand( buffer )
346 , mFieldIndex( fieldIndex )
347{
348 const QgsFields &fields = layer()->fields();
349 const QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
350 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
351 mProviderField = ( origin == QgsFields::OriginProvider );
352 mFieldName = fields.field( mFieldIndex ).name();
353
354 if ( !mProviderField )
355 {
356 // need to store the field definition
357 mOldField = mBuffer->mAddedAttributes[mOriginIndex];
358 }
359
360 if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
361 {
362 mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
363 }
364
365 // save values of new features
366 for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
367 {
368 const QgsFeature &f = it.value();
369 mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
370 }
371
372 // save changed values
373 for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
374 {
375 const QgsAttributeMap &attrs = it.value();
376 if ( attrs.contains( mFieldIndex ) )
377 mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
378 }
379}
380
382{
383 if ( mProviderField )
384 {
385 mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
386 }
387 else
388 {
389 // newly added attribute
390 mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
391 }
392
394 mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
395
396 if ( !mOldName.isEmpty() )
397 {
398 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
400 }
401
402 // set previously used attributes of new features
403 for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
404 {
405 QgsFeature &f = it.value();
406 f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
407 }
408 // set previously used changed attributes
409 for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
410 {
411 if ( !FID_IS_NEW( it.key() ) )
412 {
413 QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
414 attrs.insert( mFieldIndex, it.value() );
415 }
416 }
417
418 const QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
419 mBuffer->L->setEditFormConfig( formConfig );
420
421 emit mBuffer->attributeAdded( mFieldIndex );
422}
423
425{
426 if ( mProviderField )
427 {
428 mBuffer->mDeletedAttributeIds.append( mOriginIndex );
429 std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
430 }
431 else
432 {
433 // newly added attribute
434 mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
435 }
436
437 mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
439 emit mBuffer->attributeDeleted( mFieldIndex );
440}
441
442
444 : QgsVectorLayerUndoCommand( buffer )
445 , mFieldIndex( fieldIndex )
446 , mOldName( layer()->fields().at( fieldIndex ).name() )
447 , mNewName( newName )
448{
449 const QgsFields &fields = layer()->fields();
450 const QgsFields::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
451 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
452 mProviderField = ( origin == QgsFields::OriginProvider );
453}
454
456{
457 if ( mProviderField )
458 {
459 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
460 }
461 else
462 {
463 // newly added attribute
464 mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
465 }
467 emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
468}
469
471{
472 if ( mProviderField )
473 {
474 mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
475 }
476 else
477 {
478 // newly added attribute
479 mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
480 }
482 emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
483}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Contains configuration settings for an editor form.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
Definition: qgsfeature.cpp:262
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:122
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:53
QString name
Definition: qgsfield.h:62
Container of fields for a vector layer.
Definition: qgsfields.h:45
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfields.h:51
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Definition: qgsfields.cpp:189
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
Definition: qgsfields.cpp:197
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
Q_GADGET bool isNull
Definition: qgsgeometry.h:164
void attributeRenamed(int idx, const QString &newName)
Emitted when an attribute has been renamed.
QgsFeatureMap mAddedFeatures
New features which are not committed.
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geom)
Emitted when a feature's geometry is changed.
void handleAttributeDeleted(int index)
Update added and changed features after removal of an attribute.
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
void featureDeleted(QgsFeatureId fid)
void attributeAdded(int idx)
void attributeDeleted(int idx)
void featureAdded(QgsFeatureId fid)
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
void handleAttributeAdded(int index)
Update added and changed features after addition of an attribute.
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
QgsVectorLayerUndoCommandAddAttribute(QgsVectorLayerEditBuffer *buffer, const QgsField &field)
Constructor for QgsVectorLayerUndoCommandAddAttribute.
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
Constructor for QgsVectorLayerUndoCommandAddFeature.
QgsVectorLayerUndoCommandChangeAttribute(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue)
Constructor for QgsVectorLayerUndoCommandChangeAttribute.
Undo command for modifying the geometry of a feature from a vector layer.
QgsVectorLayerUndoCommandChangeGeometry(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, const QgsGeometry &newGeom)
Constructor for QgsVectorLayerUndoCommandChangeGeometry.
bool mergeWith(const QUndoCommand *other) override
QgsVectorLayerUndoCommandDeleteAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex)
Constructor for QgsVectorLayerUndoCommandDeleteAttribute.
QgsVectorLayerUndoCommandDeleteFeature(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid)
Constructor for QgsVectorLayerUndoCommandDeleteFeature.
QgsVectorLayerUndoCommandRenameAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex, const QString &newName)
Constructor for QgsVectorLayerUndoCommandRenameAttribute.
Base class for undo commands within a QgsVectorLayerEditBuffer.
QgsVectorLayer * layer()
Returns the layer associated with the undo command.
QgsVectorLayerEditBuffer * mBuffer
Associated edit buffer.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
QgsEditFormConfig editFormConfig
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:42
#define FID_IS_NEW(fid)
Definition: qgsfeatureid.h:31
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:27
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39