QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
64{
65 mFid = fid;
66
67 if ( FID_IS_NEW( mFid ) )
68 {
69 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
70 Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
71 mOldAddedFeature = it.value();
72 }
73}
74
76{
77 if ( FID_IS_NEW( mFid ) )
78 {
79 mBuffer->mAddedFeatures.insert( mOldAddedFeature.id(), mOldAddedFeature );
80 }
81 else
82 {
83 mBuffer->mDeletedFeatureIds.remove( mFid );
84 }
85
86 emit mBuffer->featureAdded( mFid );
87}
88
90{
91 if ( FID_IS_NEW( mFid ) )
92 {
93 mBuffer->mAddedFeatures.remove( mFid );
94 }
95 else
96 {
97 mBuffer->mDeletedFeatureIds.insert( mFid );
98 }
99
100 emit mBuffer->featureDeleted( mFid );
101}
102
103
105 : QgsVectorLayerUndoCommand( buffer )
106 , mFid( fid )
107 , mNewGeom( newGeom )
108{
109 if ( FID_IS_NEW( mFid ) )
110 {
111 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
112 Q_ASSERT( it != mBuffer->mAddedFeatures.constEnd() );
113 mOldGeom = ( it.value().geometry() );
114 }
115 else
116 {
117 mOldGeom = mBuffer->mChangedGeometries.value( mFid, QgsGeometry() );
118 }
119}
120
121
123{
124 if ( other->id() != id() )
125 return false;
126
127 const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
128 if ( !merge )
129 return false;
130
131 if ( merge->mFid != mFid )
132 return false;
133
134 mNewGeom = merge->mNewGeom;
135 merge->mNewGeom = QgsGeometry();
136
137 return true;
138}
139
141{
142 if ( FID_IS_NEW( mFid ) )
143 {
144 // modify added features
145 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
146 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
147 it.value().setGeometry( mOldGeom );
148
149 emit mBuffer->geometryChanged( mFid, mOldGeom );
150 }
151 else
152 {
153 // existing feature
154
155 if ( mOldGeom.isNull() )
156 {
157 mBuffer->mChangedGeometries.remove( mFid );
158
159 QgsFeature f;
160 if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setNoAttributes() ).nextFeature( f ) && f.hasGeometry() )
161 {
162 emit mBuffer->geometryChanged( mFid, f.geometry() );
163 }
164 }
165 else
166 {
167 mBuffer->mChangedGeometries[mFid] = mOldGeom;
168 emit mBuffer->geometryChanged( mFid, mOldGeom );
169 }
170 }
171}
172
174{
175 if ( FID_IS_NEW( mFid ) )
176 {
177 // modify added features
178 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
179 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
180 it.value().setGeometry( mNewGeom );
181 }
182 else
183 {
184 mBuffer->mChangedGeometries[mFid] = mNewGeom;
185 }
186 emit mBuffer->geometryChanged( mFid, mNewGeom );
187}
188
189
190QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
191 : QgsVectorLayerUndoCommand( buffer )
192 , mFid( fid )
193 , mFieldIndex( fieldIndex )
194 , mOldValue( oldValue )
195 , mNewValue( newValue )
196{
197 if ( FID_IS_NEW( mFid ) )
198 {
199 // work with added feature
200 const QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constFind( mFid );
201 if ( it != mBuffer->mAddedFeatures.constEnd() )
202 {
203 if ( it.value().attribute( mFieldIndex ).isValid() )
204 {
205 mOldValue = it.value().attribute( mFieldIndex );
206 mFirstChange = false;
207 }
208 }
209 else
210 {
211 // TODO: report a programmatic error ?
212 }
213 }
214 else
215 {
216 // work with existing feature
217 const QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constFind( mFid );
218 if ( it != mBuffer->mChangedAttributeValues.constEnd() )
219 {
220 if ( it->contains( mFieldIndex ) )
221 {
222 mOldValue = mBuffer->mChangedAttributeValues[mFid][mFieldIndex];
223 mFirstChange = false;
224 }
225 }
226 else
227 {
228 // TODO: report a programmatic error ?
229 }
230 }
231}
232
234{
235 QVariant original = mOldValue;
236
237 if ( FID_IS_NEW( mFid ) )
238 {
239 // added feature
240 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
241 if ( it == mBuffer->mAddedFeatures.end() )
242 {
243 // the feature must have been removed, nothing to undo here
244 // See https://github.com/qgis/QGIS/issues/23243
245 }
246 else
247 {
248 //Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
249 it.value().setAttribute( mFieldIndex, mOldValue );
250 }
251 }
252 else if ( mFirstChange )
253 {
254 // existing feature
255 mBuffer->mChangedAttributeValues[mFid].remove( mFieldIndex );
256 if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
257 mBuffer->mChangedAttributeValues.remove( mFid );
258
259 if ( !mOldValue.isValid() )
260 {
261 // get old value from provider
262 QgsFeature tmp;
263 QgsFeatureRequest request;
264 request.setFilterFid( mFid );
266 request.setSubsetOfAttributes( QgsAttributeList() << mFieldIndex );
267 QgsFeatureIterator fi = layer()->getFeatures( request );
268 if ( fi.nextFeature( tmp ) )
269 original = tmp.attribute( mFieldIndex );
270 }
271 }
272 else
273 {
274 mBuffer->mChangedAttributeValues[mFid][mFieldIndex] = mOldValue;
275 }
276
277 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
278}
279
281{
282 if ( FID_IS_NEW( mFid ) )
283 {
284 // updated added feature
285 const QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
286 Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
287 it.value().setAttribute( mFieldIndex, mNewValue );
288 }
289 else
290 {
291 // changed attribute of existing feature
292 if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
293 {
294 mBuffer->mChangedAttributeValues.insert( mFid, QgsAttributeMap() );
295 }
296
297 mBuffer->mChangedAttributeValues[mFid].insert( mFieldIndex, mNewValue );
298 }
299
300 emit mBuffer->attributeValueChanged( mFid, mFieldIndex, mNewValue );
301}
302
303
305 : QgsVectorLayerUndoCommand( buffer )
306 , mField( field )
307{
308 const QgsFields &fields = layer()->fields();
309 int i;
310 for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != Qgis::FieldOrigin::Join; i++ )
311 ;
312 mFieldIndex = i;
313}
314
316{
317 const int index = layer()->fields().fieldOriginIndex( mFieldIndex );
318
319 mBuffer->mAddedAttributes.removeAt( index );
320 mBuffer->handleAttributeDeleted( mFieldIndex );
321 mBuffer->updateLayerFields();
322
323 emit mBuffer->attributeDeleted( mFieldIndex );
324}
325
327{
328 mBuffer->mAddedAttributes.append( mField );
329 mBuffer->handleAttributeAdded( mFieldIndex, mField );
330 mBuffer->updateLayerFields();
331
332 emit mBuffer->attributeAdded( mFieldIndex );
333}
334
335
337 : QgsVectorLayerUndoCommand( buffer )
338 , mFieldIndex( fieldIndex )
339{
340 const QgsFields &fields = layer()->fields();
341 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
342 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
343 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
344 mFieldName = fields.field( mFieldIndex ).name();
345
346 if ( !mProviderField )
347 {
348 // need to store the field definition
349 mOldField = mBuffer->mAddedAttributes[mOriginIndex];
350 }
351
352 if ( mBuffer->mRenamedAttributes.contains( fieldIndex ) )
353 {
354 mOldName = mBuffer->mRenamedAttributes.value( fieldIndex );
355 }
356
357 // save values of new features
358 for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.constBegin(); it != mBuffer->mAddedFeatures.constEnd(); ++it )
359 {
360 const QgsFeature &f = it.value();
361 mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
362 }
363
364 // save changed values
365 for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.constBegin(); it != mBuffer->mChangedAttributeValues.constEnd(); ++it )
366 {
367 const QgsAttributeMap &attrs = it.value();
368 if ( attrs.contains( mFieldIndex ) )
369 mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
370 }
371}
372
374{
375 if ( mProviderField )
376 {
377 mBuffer->mDeletedAttributeIds.removeOne( mOriginIndex );
378 }
379 else
380 {
381 // newly added attribute
382 mBuffer->mAddedAttributes.insert( mOriginIndex, mOldField );
383 }
384
385 mBuffer->updateLayerFields();
386 mBuffer->handleAttributeAdded( mFieldIndex, mOldField ); // update changed attributes + new features
387
388 if ( !mOldName.isEmpty() )
389 {
390 mBuffer->mRenamedAttributes[mFieldIndex] = mOldName;
391 mBuffer->updateLayerFields();
392 }
393
394 // set previously used attributes of new features
395 for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
396 {
397 QgsFeature &f = it.value();
398 f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
399 }
400 // set previously used changed attributes
401 for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.constBegin(); it != mDeletedValues.constEnd(); ++it )
402 {
403 if ( !FID_IS_NEW( it.key() ) )
404 {
405 QgsAttributeMap &attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistent
406 attrs.insert( mFieldIndex, it.value() );
407 }
408 }
409
410 const QgsEditFormConfig formConfig = mBuffer->L->editFormConfig();
411 mBuffer->L->setEditFormConfig( formConfig );
412
413 emit mBuffer->attributeAdded( mFieldIndex );
414}
415
417{
418 if ( mProviderField )
419 {
420 mBuffer->mDeletedAttributeIds.append( mOriginIndex );
421 std::sort( mBuffer->mDeletedAttributeIds.begin(), mBuffer->mDeletedAttributeIds.end() ); // keep it sorted
422 }
423 else
424 {
425 // newly added attribute
426 mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
427 }
428
429 mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
430 mBuffer->updateLayerFields();
431 emit mBuffer->attributeDeleted( mFieldIndex );
432}
433
434
436 : QgsVectorLayerUndoCommand( buffer )
437 , mFieldIndex( fieldIndex )
438 , mOldName( layer()->fields().at( fieldIndex ).name() )
439 , mNewName( newName )
440{
441 const QgsFields &fields = layer()->fields();
442 const Qgis::FieldOrigin origin = fields.fieldOrigin( mFieldIndex );
443 mOriginIndex = fields.fieldOriginIndex( mFieldIndex );
444 mProviderField = ( origin == Qgis::FieldOrigin::Provider );
445}
446
448{
449 if ( mProviderField )
450 {
451 mBuffer->mRenamedAttributes[mFieldIndex] = mOldName;
452 }
453 else
454 {
455 // newly added attribute
456 mBuffer->mAddedAttributes[mOriginIndex].setName( mOldName );
457 }
458 mBuffer->updateLayerFields();
459 emit mBuffer->attributeRenamed( mFieldIndex, mOldName );
460}
461
463{
464 if ( mProviderField )
465 {
466 mBuffer->mRenamedAttributes[mFieldIndex] = mNewName;
467 }
468 else
469 {
470 // newly added attribute
471 mBuffer->mAddedAttributes[mOriginIndex].setName( mNewName );
472 }
473 mBuffer->updateLayerFields();
474 emit mBuffer->attributeRenamed( mFieldIndex, mNewName );
475}
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2276
FieldOrigin
Field origin.
Definition qgis.h:1783
@ Provider
Field originates from the underlying data provider of the vector layer.
Definition qgis.h:1785
@ Join
Field originates from a joined layer.
Definition qgis.h:1786
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:60
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
QgsFeatureId id
Definition qgsfeature.h:68
void setId(QgsFeatureId id)
Sets the feature id for this feature.
QgsGeometry geometry
Definition qgsfeature.h:71
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:56
QString name
Definition qgsfield.h:65
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:30
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63