QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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 "qgsfeature.h"
19#include "qgsfeatureiterator.h"
20#include "qgsgeometry.h"
21#include "qgslogger.h"
22#include "qgsvectorlayer.h"
24
27{
28 static int sAddedIdLowWaterMark = -1;
29
30 //assign a temporary id to the feature (use negative numbers)
31 sAddedIdLowWaterMark--;
32
33 QgsDebugMsgLevel( "Assigned feature id " + QString::number( sAddedIdLowWaterMark ), 4 );
34
35 // Force a feature ID (to keep other functions in QGIS happy,
36 // providers will use their own new feature ID when we commit the new feature)
37 // and add to the known added features.
38 f.setId( sAddedIdLowWaterMark );
39
40 mFeature = f;
41}
42
44{
45#ifndef QT_NO_DEBUG
46 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFeature.id() );
47 Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
48#endif
49 mBuffer->mAddedFeatures.remove( mFeature.id() );
50
51 emit mBuffer->featureDeleted( mFeature.id() );
52}
53
55{
56 mBuffer->mAddedFeatures.insert( mFeature.id(), mFeature );
57
58 emit mBuffer->featureAdded( mFeature.id() );
59}
60
61
62
65{
66 mFid = fid;
67
68 if ( FID_IS_NEW( mFid ) )
69 {
70 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
71 Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
72 mOldAddedFeature = it.value();
73 }
74}
75
77{
78 if ( FID_IS_NEW( mFid ) )
79 {
80 mBuffer->mAddedFeatures.insert( mOldAddedFeature.id(), mOldAddedFeature );
81 }
82 else
83 {
84 mBuffer->mDeletedFeatureIds.remove( mFid );
85 }
86
87 emit mBuffer->featureAdded( mFid );
88}
89
91{
92 if ( FID_IS_NEW( mFid ) )
93 {
94 mBuffer->mAddedFeatures.remove( mFid );
95 }
96 else
97 {
98 mBuffer->mDeletedFeatureIds.insert( mFid );
99 }
100
101 emit mBuffer->featureDeleted( mFid );
102}
103
104
105
107 : QgsVectorLayerUndoCommand( buffer )
108 , mFid( fid )
109 , mNewGeom( newGeom )
110{
111 if ( FID_IS_NEW( mFid ) )
112 {
113 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
114 Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
115 mOldGeom = ( it.value().geometry() );
116 }
117 else
118 {
119 mOldGeom = mBuffer->mChangedGeometries.value( mFid, QgsGeometry() );
120 }
121}
122
123
124
126{
127 if ( other->id() != id() )
128 return false;
129
130 const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
131 if ( !merge )
132 return false;
133
134 if ( merge->mFid != mFid )
135 return false;
136
137 mNewGeom = merge->mNewGeom;
138 merge->mNewGeom = QgsGeometry();
139
140 return true;
141}
142
144{
145 if ( FID_IS_NEW( mFid ) )
146 {
147 // modify added features
148 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
149 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
150 it.value().setGeometry( mOldGeom );
151
152 emit mBuffer->geometryChanged( mFid, mOldGeom );
153 }
154 else
155 {
156 // existing feature
157
158 if ( mOldGeom.isNull() )
159 {
160 mBuffer->mChangedGeometries.remove( mFid );
161
162 QgsFeature f;
163 if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setNoAttributes() ).nextFeature( f ) && f.hasGeometry() )
164 {
165 emit mBuffer->geometryChanged( mFid, f.geometry() );
166 }
167 }
168 else
169 {
170 mBuffer->mChangedGeometries[mFid] = mOldGeom;
171 emit mBuffer->geometryChanged( mFid, mOldGeom );
172 }
173 }
174
175}
176
178{
179 if ( FID_IS_NEW( mFid ) )
180 {
181 // modify added features
182 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
183 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
184 it.value().setGeometry( mNewGeom );
185 }
186 else
187 {
188 mBuffer->mChangedGeometries[ mFid ] = mNewGeom;
189 }
190 emit mBuffer->geometryChanged( mFid, mNewGeom );
191}
192
193
194QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
195 : QgsVectorLayerUndoCommand( buffer )
196 , mFid( fid )
197 , mFieldIndex( fieldIndex )
198 , mOldValue( oldValue )
199 , mNewValue( newValue )
200{
201 if ( FID_IS_NEW( mFid ) )
202 {
203 // work with added feature
204 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
205 if ( it != mBuffer->mAddedFeatures.constEnd() )
206 {
207 if ( it.value().attribute( mFieldIndex ).isValid() )
208 {
209 mOldValue = it.value().attribute( mFieldIndex );
210 mFirstChange = false;
211 }
212 }
213 else
214 {
215 // TODO: report a programmatic error ?
216 }
217 }
218 else
219 {
220 // work with existing feature
221 const QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constFind( mFid );
222 if ( it != mBuffer->mChangedAttributeValues.constEnd() )
223 {
224 if ( it->contains( mFieldIndex ) )
225 {
226 mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
227 mFirstChange = false;
228 }
229 }
230 else
231 {
232 // TODO: report a programmatic error ?
233 }
234 }
235
236}
237
239{
240 QVariant original = mOldValue;
241
242 if ( FID_IS_NEW( mFid ) )
243 {
244 // added feature
245 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
246 if ( it == mBuffer->mAddedFeatures.end() )
247 {
248 // the feature must have been removed, nothing to undo here
249 // See https://github.com/qgis/QGIS/issues/23243
250 }
251 else
252 {
253 //Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
254 it.value().setAttribute( mFieldIndex, mOldValue );
255 }
256 }
257 else if ( mFirstChange )
258 {
259 // existing feature
260 mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
261 if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
262 mBuffer->mChangedAttributeValues.remove( mFid );
263
264 if ( !mOldValue.isValid() )
265 {
266 // get old value from provider
267 QgsFeature tmp;
268 QgsFeatureRequest request;
269 request.setFilterFid( mFid );
271 request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
272 QgsFeatureIterator fi = layer()->getFeatures( request );
273 if ( fi.nextFeature( tmp ) )
274 original = tmp.attribute( mFieldIndex );
275 }
276 }
277 else
278 {
279 mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
280 }
281
282 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
283}
284
286{
287 if ( FID_IS_NEW( mFid ) )
288 {
289 // updated added feature
290 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
291 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
292 it.value().setAttribute( mFieldIndex, mNewValue );
293 }
294 else
295 {
296 // changed attribute of existing feature
297 if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
298 {
299 mBuffer->mChangedAttributeValues.insert( mFid, QgsAttributeMap() );
300 }
301
302 mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
303 }
304
305 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
306}
307
308
310 : QgsVectorLayerUndoCommand( buffer )
311 , mField( field )
312{
313 const QgsFields &fields = layer()->fields();
314 int i;
315 for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != Qgis::FieldOrigin::Join; i++ )
316 ;
317 mFieldIndex = i;
318}
319
321{
322 const int index = layer()->fields().fieldOriginIndex( mFieldIndex );
323
324 mBuffer->mAddedAttributes.removeAt( index );
325 mBuffer->handleAttributeDeleted( mFieldIndex );
326 mBuffer->updateLayerFields();
327
328 emit mBuffer->attributeDeleted( mFieldIndex );
329}
330
332{
333 mBuffer->mAddedAttributes.append( mField );
334 mBuffer->handleAttributeAdded( mFieldIndex, mField );
335 mBuffer->updateLayerFields();
336
337 emit mBuffer->attributeAdded( mFieldIndex );
338}
339
340
342 : QgsVectorLayerUndoCommand( buffer )
343 , mFieldIndex( fieldIndex )
344{
345 const QgsFields &fields = layer()->fields();
346 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
347 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
348 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
349 mFieldName = fields.field( mFieldIndex ).name();
350
351 if ( !mProviderField )
352 {
353 // need to store the field definition
354 mOldField = mBuffer->mAddedAttributes[mOriginIndex];
355 }
356
357 if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
358 {
359 mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
360 }
361
362 // save values of new features
363 for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
364 {
365 const QgsFeature &f = it.value();
366 mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
367 }
368
369 // save changed values
370 for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
371 {
372 const QgsAttributeMap &attrs = it.value();
373 if ( attrs.contains( mFieldIndex ) )
374 mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
375 }
376}
377
379{
380 if ( mProviderField )
381 {
382 mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
383 }
384 else
385 {
386 // newly added attribute
387 mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
388 }
389
390 mBuffer->updateLayerFields();
391 mBuffer->handleAttributeAdded( mFieldIndex, mOldField ); // update changed attributes + new features
392
393 if ( !mOldName.isEmpty() )
394 {
395 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
396 mBuffer->updateLayerFields();
397 }
398
399 // set previously used attributes of new features
400 for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
401 {
402 QgsFeature &f = it.value();
403 f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
404 }
405 // set previously used changed attributes
406 for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
407 {
408 if ( !FID_IS_NEW( it.key() ) )
409 {
410 QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
411 attrs.insert( mFieldIndex, it.value() );
412 }
413 }
414
415 const QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
416 mBuffer->L->setEditFormConfig( formConfig );
417
418 emit mBuffer->attributeAdded( mFieldIndex );
419}
420
422{
423 if ( mProviderField )
424 {
425 mBuffer->mDeletedAttributeIds.append( mOriginIndex );
426 std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
427 }
428 else
429 {
430 // newly added attribute
431 mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
432 }
433
434 mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
435 mBuffer->updateLayerFields();
436 emit mBuffer->attributeDeleted( mFieldIndex );
437}
438
439
441 : QgsVectorLayerUndoCommand( buffer )
442 , mFieldIndex( fieldIndex )
443 , mOldName( layer()->fields().at( fieldIndex ).name() )
444 , mNewName( newName )
445{
446 const QgsFields &fields = layer()->fields();
447 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
448 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
449 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
450}
451
453{
454 if ( mProviderField )
455 {
456 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
457 }
458 else
459 {
460 // newly added attribute
461 mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
462 }
463 mBuffer->updateLayerFields();
464 emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
465}
466
468{
469 if ( mProviderField )
470 {
471 mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
472 }
473 else
474 {
475 // newly added attribute
476 mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
477 }
478 mBuffer->updateLayerFields();
479 emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
480}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2196
FieldOrigin
Field origin.
Definition qgis.h:1704
@ Provider
Field originates from the underlying data provider of the vector layer.
Definition qgis.h:1706
@ Join
Field originates from a joined layer.
Definition qgis.h:1707
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.
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:58
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsFeatureId id
Definition qgsfeature.h:66
void setId(QgsFeatureId id)
Sets the feature id for this feature.
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:54
QString name
Definition qgsfield.h:63
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
A geometry is the spatial representation of a feature.
Stores queued vector layer edit operations prior to committing changes to the layer's data provider.
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.
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.
QgsVectorLayer * layer()
Returns the layer associated with the undo command.
QgsVectorLayerUndoCommand(QgsVectorLayerEditBuffer *buffer)
Constructor for QgsVectorLayerUndoCommand.
QgsVectorLayerEditBuffer * mBuffer
Associated edit buffer.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
QMap< int, QVariant > QgsAttributeMap
#define FID_IS_NEW(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:28
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61