Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsvectorlayereditbuffer.cpp
3 : : ---------------------
4 : : begin : Dezember 2012
5 : : copyright : (C) 2012 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 : : #include "qgsvectorlayereditbuffer.h"
16 : :
17 : : #include "qgsgeometry.h"
18 : : #include "qgslogger.h"
19 : : #include "qgsvectorlayerundocommand.h"
20 : : #include "qgsvectordataprovider.h"
21 : : #include "qgsvectorlayer.h"
22 : : #include "qgsvectorlayerutils.h"
23 : : #include "qgsmessagelog.h"
24 : :
25 : :
26 : : //! populate two lists (ks, vs) from map - in reverse order
27 : 0 : template <class Key, class T> void mapToReversedLists( const QMap< Key, T > &map, QList<Key> &ks, QList<T> &vs )
28 : : {
29 : 0 : ks.reserve( map.size() );
30 : 0 : vs.reserve( map.size() );
31 : 0 : typename QMap<Key, T>::const_iterator i = map.constEnd();
32 : 0 : while ( i-- != map.constBegin() )
33 : : {
34 : 0 : ks.append( i.key() );
35 : 0 : vs.append( i.value() );
36 : : }
37 : 0 : }
38 : :
39 : :
40 : 1 : QgsVectorLayerEditBuffer::QgsVectorLayerEditBuffer( QgsVectorLayer *layer )
41 : 1 : : L( layer )
42 : 2 : {
43 : 1 : connect( L->undoStack(), &QUndoStack::indexChanged, this, &QgsVectorLayerEditBuffer::undoIndexChanged ); // TODO[MD]: queued?
44 : 1 : }
45 : :
46 : 0 : bool QgsVectorLayerEditBuffer::isModified() const
47 : : {
48 : 0 : return !L->undoStack()->isClean();
49 : : }
50 : :
51 : :
52 : 2 : void QgsVectorLayerEditBuffer::undoIndexChanged( int index )
53 : : {
54 : 2 : QgsDebugMsgLevel( QStringLiteral( "undo index changed %1" ).arg( index ), 4 );
55 : : Q_UNUSED( index )
56 : 2 : emit layerModified();
57 : 2 : }
58 : :
59 : :
60 : 1 : void QgsVectorLayerEditBuffer::updateFields( QgsFields &fields )
61 : : {
62 : : // delete attributes from the higher indices to lower indices
63 : 1 : for ( int i = mDeletedAttributeIds.count() - 1; i >= 0; --i )
64 : : {
65 : 0 : fields.remove( mDeletedAttributeIds.at( i ) );
66 : 0 : }
67 : :
68 : : // rename fields
69 : 1 : QgsFieldNameMap::const_iterator renameIt = mRenamedAttributes.constBegin();
70 : 1 : for ( ; renameIt != mRenamedAttributes.constEnd(); ++renameIt )
71 : : {
72 : 0 : fields.rename( renameIt.key(), renameIt.value() );
73 : 0 : }
74 : :
75 : : // add new fields
76 : 1 : for ( int i = 0; i < mAddedAttributes.count(); ++i )
77 : : {
78 : 0 : fields.append( mAddedAttributes.at( i ), QgsFields::OriginEdit, i );
79 : 0 : }
80 : 1 : }
81 : :
82 : :
83 : 0 : void QgsVectorLayerEditBuffer::updateFeatureGeometry( QgsFeature &f )
84 : : {
85 : 0 : if ( mChangedGeometries.contains( f.id() ) )
86 : 0 : f.setGeometry( mChangedGeometries[f.id()] );
87 : 0 : }
88 : :
89 : :
90 : 0 : void QgsVectorLayerEditBuffer::updateChangedAttributes( QgsFeature &f )
91 : : {
92 : 0 : QgsAttributes attrs = f.attributes();
93 : :
94 : : // remove all attributes that will disappear - from higher indices to lower
95 : 0 : for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
96 : : {
97 : 0 : attrs.remove( mDeletedAttributeIds[idx] );
98 : 0 : }
99 : :
100 : : // adjust size to accommodate added attributes
101 : 0 : attrs.resize( attrs.count() + mAddedAttributes.count() );
102 : :
103 : : // update changed attributes
104 : 0 : if ( mChangedAttributeValues.contains( f.id() ) )
105 : : {
106 : 0 : const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
107 : 0 : for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
108 : 0 : attrs[it.key()] = it.value();
109 : 0 : }
110 : :
111 : 0 : f.setAttributes( attrs );
112 : 0 : }
113 : :
114 : :
115 : :
116 : :
117 : 1 : bool QgsVectorLayerEditBuffer::addFeature( QgsFeature &f )
118 : : {
119 : 1 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) )
120 : : {
121 : 0 : return false;
122 : : }
123 : 1 : if ( L->mFields.count() != f.attributes().count() )
124 : : {
125 : 0 : QgsMessageLog::logMessage( tr( "cannot add feature, wrong field count: layer: %1 feature: %2:" ).arg( L->mFields.count() ).arg( f.attributes().count() ) );
126 : 0 : return false;
127 : : }
128 : :
129 : : // TODO: check correct geometry type
130 : :
131 : 1 : L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
132 : 1 : return true;
133 : 1 : }
134 : :
135 : :
136 : 1 : bool QgsVectorLayerEditBuffer::addFeatures( QgsFeatureList &features )
137 : : {
138 : 1 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) )
139 : 0 : return false;
140 : :
141 : 1 : bool result = true;
142 : 2 : for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
143 : : {
144 : 1 : result = result && addFeature( *iter );
145 : 1 : }
146 : :
147 : 1 : L->updateExtents();
148 : 1 : return result;
149 : 1 : }
150 : :
151 : :
152 : :
153 : 0 : bool QgsVectorLayerEditBuffer::deleteFeature( QgsFeatureId fid )
154 : : {
155 : 0 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
156 : : {
157 : 0 : QgsDebugMsg( QStringLiteral( "Cannot delete features (missing DeleteFeature capability)" ) );
158 : 0 : return false;
159 : : }
160 : :
161 : 0 : if ( FID_IS_NEW( fid ) )
162 : : {
163 : 0 : if ( !mAddedFeatures.contains( fid ) )
164 : : {
165 : 0 : QgsDebugMsg( QStringLiteral( "Cannot delete features (in the list of added features)" ) );
166 : 0 : return false;
167 : : }
168 : 0 : }
169 : : else // existing feature
170 : : {
171 : 0 : if ( mDeletedFeatureIds.contains( fid ) )
172 : : {
173 : 0 : QgsDebugMsg( QStringLiteral( "Cannot delete features (in the list of deleted features)" ) );
174 : 0 : return false;
175 : : }
176 : : }
177 : :
178 : 0 : L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
179 : 0 : return true;
180 : 0 : }
181 : :
182 : 0 : bool QgsVectorLayerEditBuffer::deleteFeatures( const QgsFeatureIds &fids )
183 : : {
184 : 0 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
185 : : {
186 : 0 : QgsDebugMsg( QStringLiteral( "Cannot delete features (missing DeleteFeatures capability)" ) );
187 : 0 : return false;
188 : : }
189 : :
190 : 0 : bool ok = true;
191 : 0 : const auto constFids = fids;
192 : 0 : for ( QgsFeatureId fid : constFids )
193 : 0 : ok = deleteFeature( fid ) && ok;
194 : :
195 : 0 : return ok;
196 : 0 : }
197 : :
198 : :
199 : 1 : bool QgsVectorLayerEditBuffer::changeGeometry( QgsFeatureId fid, const QgsGeometry &geom )
200 : : {
201 : 1 : if ( !L->isSpatial() )
202 : : {
203 : 0 : return false;
204 : : }
205 : :
206 : 1 : if ( FID_IS_NEW( fid ) )
207 : : {
208 : 1 : if ( !mAddedFeatures.contains( fid ) )
209 : 0 : return false;
210 : 1 : }
211 : 0 : else if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeGeometries ) )
212 : 0 : return false;
213 : :
214 : : // TODO: check compatible geometry
215 : :
216 : 1 : L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
217 : 1 : return true;
218 : 1 : }
219 : :
220 : 0 : bool QgsVectorLayerEditBuffer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
221 : : {
222 : 0 : bool success = true;
223 : 0 : for ( auto it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
224 : : {
225 : 0 : const int field = it.key();
226 : 0 : const QVariant newValue = it.value();
227 : 0 : QVariant oldValue;
228 : :
229 : 0 : if ( oldValues.contains( field ) )
230 : 0 : oldValue = oldValues[field];
231 : :
232 : 0 : success &= changeAttributeValue( fid, field, newValue, oldValue );
233 : 0 : }
234 : :
235 : 0 : return success;
236 : 0 : }
237 : :
238 : 0 : bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
239 : : {
240 : 0 : if ( FID_IS_NEW( fid ) )
241 : : {
242 : 0 : if ( !mAddedFeatures.contains( fid ) )
243 : 0 : return false;
244 : 0 : }
245 : 0 : else if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) )
246 : : {
247 : 0 : return false;
248 : : }
249 : :
250 : 0 : if ( field < 0 || field >= L->fields().count() ||
251 : 0 : L->fields().fieldOrigin( field ) == QgsFields::OriginJoin ||
252 : 0 : L->fields().fieldOrigin( field ) == QgsFields::OriginExpression )
253 : 0 : return false;
254 : :
255 : 0 : L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
256 : 0 : return true;
257 : 0 : }
258 : :
259 : :
260 : 0 : bool QgsVectorLayerEditBuffer::addAttribute( const QgsField &field )
261 : : {
262 : 0 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes ) )
263 : 0 : return false;
264 : :
265 : 0 : if ( field.name().isEmpty() )
266 : 0 : return false;
267 : :
268 : 0 : const QgsFields fields = L->fields();
269 : 0 : for ( const QgsField &updatedField : fields )
270 : : {
271 : 0 : if ( updatedField.name() == field.name() )
272 : 0 : return false;
273 : : }
274 : :
275 : 0 : if ( !L->dataProvider()->supportedType( field ) )
276 : 0 : return false;
277 : :
278 : 0 : L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
279 : 0 : return true;
280 : 0 : }
281 : :
282 : :
283 : 0 : bool QgsVectorLayerEditBuffer::deleteAttribute( int index )
284 : : {
285 : 0 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes ) )
286 : 0 : return false;
287 : :
288 : 0 : if ( index < 0 || index >= L->fields().count() )
289 : 0 : return false;
290 : :
291 : : // find out source of the field
292 : 0 : QgsFields::FieldOrigin origin = L->fields().fieldOrigin( index );
293 : 0 : int originIndex = L->fields().fieldOriginIndex( index );
294 : :
295 : 0 : if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
296 : 0 : return false;
297 : :
298 : 0 : if ( origin == QgsFields::OriginJoin )
299 : 0 : return false;
300 : :
301 : 0 : L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
302 : 0 : return true;
303 : 0 : }
304 : :
305 : 0 : bool QgsVectorLayerEditBuffer::renameAttribute( int index, const QString &newName )
306 : : {
307 : 0 : if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::RenameAttributes ) )
308 : 0 : return false;
309 : :
310 : 0 : if ( newName.isEmpty() )
311 : 0 : return false;
312 : :
313 : 0 : if ( index < 0 || index >= L->fields().count() )
314 : 0 : return false;
315 : :
316 : 0 : const QgsFields fields = L->fields();
317 : 0 : for ( const QgsField &updatedField : fields )
318 : : {
319 : 0 : if ( updatedField.name() == newName )
320 : 0 : return false;
321 : : }
322 : :
323 : 0 : L->undoStack()->push( new QgsVectorLayerUndoCommandRenameAttribute( this, index, newName ) );
324 : 0 : return true;
325 : 0 : }
326 : :
327 : :
328 : 0 : bool QgsVectorLayerEditBuffer::commitChanges( QStringList &commitErrors )
329 : : {
330 : 0 : QgsVectorDataProvider *provider = L->dataProvider();
331 : 0 : commitErrors.clear();
332 : :
333 : 0 : int cap = provider->capabilities();
334 : 0 : bool success = true;
335 : :
336 : : // geometry updates attribute updates
337 : : // yes no => changeGeometryValues
338 : : // no yes => changeAttributeValues
339 : : // yes yes => changeFeatures
340 : :
341 : : // to fix https://github.com/qgis/QGIS/issues/23663
342 : : // first of all check if feature to add is compatible with provider type
343 : : // this check have to be done before all checks to avoid to clear internal
344 : : // buffer if some of next steps success.
345 : 0 : if ( success && !mAddedFeatures.isEmpty() )
346 : : {
347 : 0 : if ( cap & QgsVectorDataProvider::AddFeatures )
348 : : {
349 : 0 : if ( provider->doesStrictFeatureTypeCheck() )
350 : : {
351 : 0 : for ( const QgsFeature &f : std::as_const( mAddedFeatures ) )
352 : : {
353 : 0 : if ( ( ! f.hasGeometry() ) ||
354 : 0 : ( f.geometry().wkbType() == provider->wkbType() ) )
355 : 0 : continue;
356 : :
357 : 0 : if ( provider->convertToProviderType( f.geometry() ).isNull() )
358 : : {
359 : 0 : commitErrors << tr( "ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.", "not added features count", mAddedFeatures.size() );
360 : 0 : success = false;
361 : 0 : break;
362 : : }
363 : : }
364 : 0 : }
365 : 0 : }
366 : : else
367 : : {
368 : 0 : commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
369 : 0 : success = false;
370 : : }
371 : 0 : }
372 : :
373 : : //
374 : : // update geometries
375 : : //
376 : 0 : if ( !mChangedGeometries.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
377 : : {
378 : 0 : if ( provider->changeGeometryValues( mChangedGeometries ) )
379 : : {
380 : 0 : commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
381 : :
382 : 0 : emit committedGeometriesChanges( L->id(), mChangedGeometries );
383 : 0 : mChangedGeometries.clear();
384 : 0 : }
385 : : else
386 : : {
387 : 0 : commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
388 : 0 : success = false;
389 : : }
390 : 0 : }
391 : :
392 : 0 : QgsFields oldFields = L->fields();
393 : :
394 : : //
395 : : // delete attributes
396 : : //
397 : 0 : bool attributesChanged = false;
398 : 0 : if ( !mDeletedAttributeIds.isEmpty() )
399 : : {
400 : 0 : if ( ( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( qgis::listToSet( mDeletedAttributeIds ) ) )
401 : : {
402 : 0 : commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
403 : :
404 : 0 : emit committedAttributesDeleted( L->id(), mDeletedAttributeIds );
405 : :
406 : 0 : mDeletedAttributeIds.clear();
407 : 0 : attributesChanged = true;
408 : 0 : }
409 : : else
410 : : {
411 : 0 : commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
412 : : #if 0
413 : : QString list = "ERROR: Pending attribute deletes:";
414 : : const auto constMDeletedAttributeIds = mDeletedAttributeIds;
415 : : for ( int idx : constMDeletedAttributeIds )
416 : : {
417 : : list.append( ' ' + L->fields().at( idx ).name() );
418 : : }
419 : : commitErrors << list;
420 : : #endif
421 : 0 : success = false;
422 : : }
423 : 0 : }
424 : :
425 : : // rename attributes
426 : 0 : if ( !mRenamedAttributes.isEmpty() )
427 : : {
428 : 0 : if ( ( cap & QgsVectorDataProvider::RenameAttributes ) && provider->renameAttributes( mRenamedAttributes ) )
429 : : {
430 : 0 : commitErrors << tr( "SUCCESS: %n attribute(s) renamed.", "renamed attributes count", mRenamedAttributes.size() );
431 : :
432 : 0 : emit committedAttributesRenamed( L->id(), mRenamedAttributes );
433 : :
434 : 0 : mRenamedAttributes.clear();
435 : 0 : attributesChanged = true;
436 : 0 : }
437 : : else
438 : : {
439 : 0 : commitErrors << tr( "ERROR: %n attribute(s) not renamed", "not renamed attributes count", mRenamedAttributes.size() );
440 : 0 : success = false;
441 : : }
442 : 0 : }
443 : :
444 : : //
445 : : // add attributes
446 : : //
447 : 0 : if ( !mAddedAttributes.isEmpty() )
448 : : {
449 : 0 : if ( ( cap & QgsVectorDataProvider::AddAttributes ) && provider->addAttributes( mAddedAttributes ) )
450 : : {
451 : 0 : commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
452 : :
453 : 0 : emit committedAttributesAdded( L->id(), mAddedAttributes );
454 : :
455 : 0 : mAddedAttributes.clear();
456 : 0 : attributesChanged = true;
457 : 0 : }
458 : : else
459 : : {
460 : 0 : commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
461 : : #if 0
462 : : QString list = "ERROR: Pending adds:";
463 : : const auto constMAddedAttributes = mAddedAttributes;
464 : : for ( QgsField f : constMAddedAttributes )
465 : : {
466 : : list.append( ' ' + f.name() );
467 : : }
468 : : commitErrors << list;
469 : : #endif
470 : 0 : success = false;
471 : : }
472 : 0 : }
473 : :
474 : : //
475 : : // check that addition/removal went as expected
476 : : //
477 : 0 : bool attributeChangesOk = true;
478 : 0 : if ( attributesChanged )
479 : : {
480 : 0 : L->updateFields();
481 : 0 : QgsFields newFields = L->fields();
482 : :
483 : 0 : if ( oldFields.count() != newFields.count() )
484 : : {
485 : 0 : commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
486 : 0 : attributeChangesOk = false; // don't try attribute updates - they'll fail.
487 : 0 : }
488 : :
489 : 0 : for ( int i = 0; i < std::min( oldFields.count(), newFields.count() ); ++i )
490 : : {
491 : 0 : QgsField oldField = oldFields.at( i );
492 : 0 : QgsField newField = newFields.at( i );
493 : 0 : if ( attributeChangesOk && oldField != newField )
494 : : {
495 : 0 : commitErrors
496 : 0 : << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
497 : 0 : << tr( "Provider: %1" ).arg( L->providerType() )
498 : 0 : << tr( "Storage: %1" ).arg( L->storageType() )
499 : 0 : << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
500 : 0 : .arg( tr( "expected field" ),
501 : 0 : oldField.name(),
502 : 0 : QVariant::typeToName( oldField.type() ),
503 : 0 : oldField.typeName() )
504 : 0 : .arg( oldField.length() )
505 : 0 : .arg( oldField.precision() )
506 : 0 : << QStringLiteral( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
507 : 0 : .arg( tr( "retrieved field" ),
508 : 0 : newField.name(),
509 : 0 : QVariant::typeToName( newField.type() ),
510 : 0 : newField.typeName() )
511 : 0 : .arg( newField.length() )
512 : 0 : .arg( newField.precision() );
513 : 0 : attributeChangesOk = false; // don't try attribute updates - they'll fail.
514 : 0 : }
515 : 0 : }
516 : 0 : }
517 : :
518 : 0 : if ( attributeChangesOk )
519 : : {
520 : 0 : if ( cap & QgsVectorDataProvider::ChangeFeatures && !mChangedGeometries.isEmpty() && !mChangedAttributeValues.isEmpty() )
521 : : {
522 : : Q_ASSERT( ( cap & ( QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries ) ) == ( QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries ) );
523 : :
524 : 0 : if ( provider->changeFeatures( mChangedAttributeValues, mChangedGeometries ) )
525 : : {
526 : 0 : commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
527 : 0 : emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues );
528 : 0 : mChangedAttributeValues.clear();
529 : :
530 : 0 : emit committedGeometriesChanges( L->id(), mChangedGeometries );
531 : 0 : mChangedGeometries.clear();
532 : 0 : }
533 : : else
534 : : {
535 : 0 : success = false;
536 : : }
537 : 0 : }
538 : : else
539 : : {
540 : : //
541 : : // change attributes
542 : : //
543 : 0 : if ( !mChangedAttributeValues.isEmpty() && ( ( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
544 : : {
545 : 0 : if ( ( cap & QgsVectorDataProvider::ChangeAttributeValues ) && provider->changeAttributeValues( mChangedAttributeValues ) )
546 : : {
547 : 0 : commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
548 : :
549 : 0 : emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues );
550 : 0 : mChangedAttributeValues.clear();
551 : 0 : }
552 : : else
553 : : {
554 : 0 : commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
555 : : #if 0
556 : : QString list = "ERROR: pending changes:";
557 : : const auto constKeys = mChangedAttributeValues.keys();
558 : : for ( QgsFeatureId id : constKeys )
559 : : {
560 : : list.append( "\n " + FID_TO_STRING( id ) + '[' );
561 : : const auto constKeys = mChangedAttributeValues[ id ].keys();
562 : : for ( int idx : constKeys )
563 : : {
564 : : list.append( QString( " %1:%2" ).arg( L->fields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
565 : : }
566 : : list.append( " ]" );
567 : : }
568 : : commitErrors << list;
569 : : #endif
570 : 0 : success = false;
571 : : }
572 : 0 : }
573 : : }
574 : :
575 : : //
576 : : // delete features
577 : : //
578 : 0 : if ( success && !mDeletedFeatureIds.isEmpty() )
579 : : {
580 : 0 : if ( ( cap & QgsVectorDataProvider::DeleteFeatures ) && provider->deleteFeatures( mDeletedFeatureIds ) )
581 : : {
582 : 0 : commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
583 : : // TODO[MD]: we should not need this here
584 : 0 : for ( QgsFeatureId id : std::as_const( mDeletedFeatureIds ) )
585 : : {
586 : 0 : mChangedAttributeValues.remove( id );
587 : 0 : mChangedGeometries.remove( id );
588 : : }
589 : :
590 : 0 : emit committedFeaturesRemoved( L->id(), mDeletedFeatureIds );
591 : :
592 : 0 : mDeletedFeatureIds.clear();
593 : 0 : }
594 : : else
595 : : {
596 : 0 : commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
597 : : #if 0
598 : : QString list = "ERROR: pending deletes:";
599 : : const auto constMDeletedFeatureIds = mDeletedFeatureIds;
600 : : for ( QgsFeatureId id : constMDeletedFeatureIds )
601 : : {
602 : : list.append( ' ' + FID_TO_STRING( id ) );
603 : : }
604 : : commitErrors << list;
605 : : #endif
606 : 0 : success = false;
607 : : }
608 : 0 : }
609 : :
610 : : //
611 : : // add features
612 : : //
613 : 0 : if ( success && !mAddedFeatures.isEmpty() )
614 : : {
615 : 0 : if ( cap & QgsVectorDataProvider::AddFeatures )
616 : : {
617 : 0 : QList<QgsFeatureId> ids;
618 : 0 : QgsFeatureList featuresToAdd;
619 : : // get the list of added features in reversed order
620 : : // this will preserve the order how they have been added e.g. (-1, -2, -3) while in the map they are ordered (-3, -2, -1)
621 : 0 : mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
622 : :
623 : : // we need to strip any extra attributes here -- e.g. virtual fields, which should
624 : : // not be sent to the data provider. Refs #18784
625 : 0 : for ( int i = 0; i < featuresToAdd.count(); ++i )
626 : : {
627 : 0 : QgsVectorLayerUtils::matchAttributesToFields( featuresToAdd[i], provider->fields() );
628 : 0 : }
629 : :
630 : 0 : if ( provider->addFeatures( featuresToAdd, QgsFeatureSink::Flag::RollBackOnErrors ) )
631 : : {
632 : 0 : commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
633 : :
634 : 0 : emit committedFeaturesAdded( L->id(), featuresToAdd );
635 : :
636 : : // notify everyone that the features with temporary ids were updated with permanent ids
637 : 0 : for ( int i = 0; i < featuresToAdd.count(); ++i )
638 : : {
639 : 0 : if ( featuresToAdd[i].id() != ids[i] )
640 : : {
641 : : //update selection
642 : 0 : if ( L->mSelectedFeatureIds.contains( ids[i] ) )
643 : : {
644 : 0 : L->mSelectedFeatureIds.remove( ids[i] );
645 : 0 : L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
646 : 0 : }
647 : 0 : emit featureDeleted( ids[i] );
648 : 0 : emit featureAdded( featuresToAdd[i].id() );
649 : 0 : }
650 : 0 : }
651 : :
652 : 0 : mAddedFeatures.clear();
653 : 0 : }
654 : : else
655 : : {
656 : 0 : commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
657 : : #if 0
658 : : QString list = "ERROR: pending adds:";
659 : : const auto constMAddedFeatures = mAddedFeatures;
660 : : for ( QgsFeature f : constMAddedFeatures )
661 : : {
662 : : list.append( ' ' + FID_TO_STRING( f.id() ) + '[' );
663 : : for ( int i = 0; i < L->fields().size(); i++ )
664 : : {
665 : : list.append( QString( " %1:%2" ).arg( L->fields().at( i ).name() ).arg( f.attributes()[i].toString() ) );
666 : : }
667 : : list.append( " ]" );
668 : : }
669 : : commitErrors << list;
670 : : #endif
671 : 0 : success = false;
672 : : }
673 : 0 : }
674 : : else
675 : : {
676 : 0 : commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
677 : 0 : success = false;
678 : : }
679 : 0 : }
680 : 0 : }
681 : : else
682 : : {
683 : 0 : success = false;
684 : : }
685 : :
686 : 0 : if ( !success && provider->hasErrors() )
687 : : {
688 : 0 : commitErrors << tr( "\n Provider errors:" );
689 : 0 : const auto constErrors = provider->errors();
690 : 0 : for ( QString e : constErrors )
691 : : {
692 : 0 : commitErrors << " " + e.replace( '\n', QLatin1String( "\n " ) );
693 : 0 : }
694 : 0 : provider->clearErrors();
695 : 0 : }
696 : :
697 : 0 : return success;
698 : 0 : }
699 : :
700 : :
701 : 0 : void QgsVectorLayerEditBuffer::rollBack()
702 : : {
703 : 0 : if ( !isModified() )
704 : 0 : return;
705 : :
706 : : // limit canvas redraws to one by jumping to beginning of stack
707 : : // see QgsUndoWidget::indexChanged
708 : 0 : L->undoStack()->setIndex( 0 );
709 : :
710 : : Q_ASSERT( mAddedAttributes.isEmpty() );
711 : : Q_ASSERT( mDeletedAttributeIds.isEmpty() );
712 : : Q_ASSERT( mChangedAttributeValues.isEmpty() );
713 : : Q_ASSERT( mChangedGeometries.isEmpty() );
714 : : Q_ASSERT( mAddedFeatures.isEmpty() );
715 : 0 : }
716 : :
717 : : #if 0
718 : : QString QgsVectorLayerEditBuffer::dumpEditBuffer()
719 : : {
720 : : QString msg;
721 : : if ( !mChangedGeometries.isEmpty() )
722 : : {
723 : : msg += "CHANGED GEOMETRIES:\n";
724 : : for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
725 : : {
726 : : // QgsFeatureId, QgsGeometry
727 : : msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
728 : : }
729 : : }
730 : : return msg;
731 : : }
732 : : #endif
733 : :
734 : 0 : void QgsVectorLayerEditBuffer::handleAttributeAdded( int index )
735 : : {
736 : : // go through the changed attributes map and adapt indices
737 : 0 : QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
738 : 0 : for ( ; it != mChangedAttributeValues.end(); ++it )
739 : : {
740 : 0 : updateAttributeMapIndex( it.value(), index, + 1 );
741 : 0 : }
742 : :
743 : : // go through added features and adapt attributes
744 : 0 : QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
745 : 0 : for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
746 : : {
747 : 0 : QgsAttributes attrs = featureIt->attributes();
748 : 0 : attrs.insert( index, QVariant() );
749 : 0 : featureIt->setAttributes( attrs );
750 : 0 : }
751 : :
752 : : // go through renamed attributes and adapt
753 : 0 : QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
754 : : //sort keys
755 : 0 : std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
756 : 0 : const auto constSortedRenamedIndices = sortedRenamedIndices;
757 : 0 : for ( int renameIndex : constSortedRenamedIndices )
758 : : {
759 : 0 : if ( renameIndex >= index )
760 : : {
761 : 0 : mRenamedAttributes[ renameIndex + 1 ] = mRenamedAttributes.value( renameIndex );
762 : 0 : }
763 : : }
764 : : //remove last
765 : 0 : mRenamedAttributes.remove( index );
766 : 0 : }
767 : :
768 : 0 : void QgsVectorLayerEditBuffer::handleAttributeDeleted( int index )
769 : : {
770 : : // go through the changed attributes map and adapt indices
771 : 0 : QgsChangedAttributesMap::iterator it = mChangedAttributeValues.begin();
772 : 0 : for ( ; it != mChangedAttributeValues.end(); ++it )
773 : : {
774 : 0 : QgsAttributeMap &attrMap = it.value();
775 : : // remove the attribute
776 : 0 : if ( attrMap.contains( index ) )
777 : 0 : attrMap.remove( index );
778 : :
779 : : // update attribute indices
780 : 0 : updateAttributeMapIndex( attrMap, index, -1 );
781 : 0 : }
782 : :
783 : : // go through added features and adapt attributes
784 : 0 : QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
785 : 0 : for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
786 : : {
787 : 0 : QgsAttributes attrs = featureIt->attributes();
788 : 0 : attrs.remove( index );
789 : 0 : featureIt->setAttributes( attrs );
790 : 0 : }
791 : :
792 : : // go through rename attributes and adapt
793 : 0 : QList< int > sortedRenamedIndices = mRenamedAttributes.keys();
794 : : //sort keys
795 : 0 : std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
796 : 0 : int last = -1;
797 : 0 : mRenamedAttributes.remove( index );
798 : 0 : const auto constSortedRenamedIndices = sortedRenamedIndices;
799 : 0 : for ( int renameIndex : constSortedRenamedIndices )
800 : : {
801 : 0 : if ( renameIndex > index )
802 : : {
803 : 0 : mRenamedAttributes.insert( renameIndex - 1, mRenamedAttributes.value( renameIndex ) );
804 : 0 : last = renameIndex;
805 : 0 : }
806 : : }
807 : : //remove last
808 : 0 : if ( last > -1 )
809 : 0 : mRenamedAttributes.remove( last );
810 : 0 : }
811 : :
812 : :
813 : :
814 : 0 : void QgsVectorLayerEditBuffer::updateAttributeMapIndex( QgsAttributeMap &map, int index, int offset ) const
815 : : {
816 : 0 : QgsAttributeMap updatedMap;
817 : 0 : for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
818 : : {
819 : 0 : int attrIndex = it.key();
820 : 0 : updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
821 : 0 : }
822 : 0 : map = updatedMap;
823 : 0 : }
824 : :
825 : :
826 : :
827 : 0 : void QgsVectorLayerEditBuffer::updateLayerFields()
828 : : {
829 : 0 : L->updateFields();
830 : 0 : }
|