QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 , mFirstChange( true )
201{
202 if ( FID_IS_NEW( mFid ) )
203 {
204 // work with added feature
205 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
206 if ( it != mBuffer->mAddedFeatures.constEnd() )
207 {
208 if ( it.value().attribute( mFieldIndex ).isValid() )
209 {
210 mOldValue = it.value().attribute( mFieldIndex );
211 mFirstChange = false;
212 }
213 }
214 else
215 {
216 // TODO: report a programmatic error ?
217 }
218 }
219 else
220 {
221 // work with existing feature
222 const QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constFind( mFid );
223 if ( it != mBuffer->mChangedAttributeValues.constEnd() )
224 {
225 if ( it->contains( mFieldIndex ) )
226 {
227 mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
228 mFirstChange = false;
229 }
230 }
231 else
232 {
233 // TODO: report a programmatic error ?
234 }
235 }
236
237}
238
240{
241 QVariant original = mOldValue;
242
243 if ( FID_IS_NEW( mFid ) )
244 {
245 // added feature
246 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
247 if ( it == mBuffer->mAddedFeatures.end() )
248 {
249 // the feature must have been removed, nothing to undo here
250 // See https://github.com/qgis/QGIS/issues/23243
251 }
252 else
253 {
254 //Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
255 it.value().setAttribute( mFieldIndex, mOldValue );
256 }
257 }
258 else if ( mFirstChange )
259 {
260 // existing feature
261 mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
262 if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
263 mBuffer->mChangedAttributeValues.remove( mFid );
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 const 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 {
300 mBuffer->mChangedAttributeValues.insert( mFid, QgsAttributeMap() );
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 ) != Qgis::FieldOrigin::Join; i++ )
317 ;
318 mFieldIndex = i;
319}
320
322{
323 const int index = layer()->fields().fieldOriginIndex( mFieldIndex );
324
325 mBuffer->mAddedAttributes.removeAt( index );
326 mBuffer->handleAttributeDeleted( mFieldIndex );
327 mBuffer->updateLayerFields();
328
329 emit mBuffer->attributeDeleted( mFieldIndex );
330}
331
333{
334 mBuffer->mAddedAttributes.append( mField );
335 mBuffer->handleAttributeAdded( mFieldIndex, mField );
336 mBuffer->updateLayerFields();
337
338 emit mBuffer->attributeAdded( mFieldIndex );
339}
340
341
343 : QgsVectorLayerUndoCommand( buffer )
344 , mFieldIndex( fieldIndex )
345{
346 const QgsFields &fields = layer()->fields();
347 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
348 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
349 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
350 mFieldName = fields.field( mFieldIndex ).name();
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
391 mBuffer->updateLayerFields();
392 mBuffer->handleAttributeAdded( mFieldIndex, mOldField ); // update changed attributes + new features
393
394 if ( !mOldName.isEmpty() )
395 {
396 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
397 mBuffer->updateLayerFields();
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 nonexistent
412 attrs.insert( mFieldIndex, it.value() );
413 }
414 }
415
416 const QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
417 mBuffer->L->setEditFormConfig( formConfig );
418
419 emit mBuffer->attributeAdded( mFieldIndex );
420}
421
423{
424 if ( mProviderField )
425 {
426 mBuffer->mDeletedAttributeIds.append( mOriginIndex );
427 std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
428 }
429 else
430 {
431 // newly added attribute
432 mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
433 }
434
435 mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
436 mBuffer->updateLayerFields();
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 const QgsFields &fields = layer()->fields();
448 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
449 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
450 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
451}
452
454{
455 if ( mProviderField )
456 {
457 mBuffer->mRenamedAttributes[ mFieldIndex ] = mOldName;
458 }
459 else
460 {
461 // newly added attribute
462 mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
463 }
464 mBuffer->updateLayerFields();
465 emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
466}
467
469{
470 if ( mProviderField )
471 {
472 mBuffer->mRenamedAttributes[ mFieldIndex ] = mNewName;
473 }
474 else
475 {
476 // newly added attribute
477 mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
478 }
479 mBuffer->updateLayerFields();
480 emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
481}
@ 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