QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsvectorlayereditbuffer.cpp
Go to the documentation of this file.
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  ***************************************************************************/
16 
17 #include "qgsgeometry.h"
18 #include "qgslogger.h"
20 #include "qgsvectordataprovider.h"
21 #include "qgsvectorlayer.h"
22 
23 
25 template <class Key, class T> void mapToReversedLists( const QMap< Key, T >& map, QList<Key>& ks, QList<T>& vs )
26 {
27  ks.reserve( map.size() );
28  vs.reserve( map.size() );
29  typename QMap<Key, T>::const_iterator i = map.constEnd();
30  while ( i-- != map.constBegin() )
31  {
32  ks.append( i.key() );
33  vs.append( i.value() );
34  }
35 }
36 
37 
39  : L( layer )
40 {
41  connect( L->undoStack(), SIGNAL( indexChanged( int ) ), this, SLOT( undoIndexChanged( int ) ) ); // TODO[MD]: queued?
42 }
43 
45 {
46 }
47 
48 
50 {
51  return !L->undoStack()->isClean();
52 }
53 
54 
56 {
57  QgsDebugMsg( QString( "undo index changed %1" ).arg( index ) );
58  Q_UNUSED( index );
59  emit layerModified();
60 }
61 
62 
64 {
65  // delete attributes from the higher indices to lower indices
66  for ( int i = mDeletedAttributeIds.count() - 1; i >= 0; --i )
67  {
68  fields.remove( mDeletedAttributeIds[i] );
69  }
70  // add new fields
71  for ( int i = 0; i < mAddedAttributes.count(); ++i )
72  {
74  }
75 }
76 
77 
79 {
80  if ( mChangedGeometries.contains( f.id() ) )
82 }
83 
84 
86 {
87  QgsAttributes attrs = f.attributes();
88 
89  // remove all attributes that will disappear - from higher indices to lower
90  for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
91  {
92  attrs.remove( mDeletedAttributeIds[idx] );
93  }
94 
95  // adjust size to accommodate added attributes
96  attrs.resize( attrs.count() + mAddedAttributes.count() );
97 
98  // update changed attributes
99  if ( mChangedAttributeValues.contains( f.id() ) )
100  {
101  const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
102  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
103  attrs[it.key()] = it.value();
104  }
105 
106  f.setAttributes( attrs );
107 }
108 
109 
110 
111 
113 {
115  {
116  return false;
117  }
118  if ( L->mUpdatedFields.count() != f.attributes().count() )
119  return false;
120 
121  // TODO: check correct geometry type
122 
123  L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
124  return true;
125 }
126 
127 
129 {
131  return false;
132 
133  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
134  {
135  addFeature( *iter );
136  }
137 
138  L->updateExtents();
139  return true;
140 }
141 
142 
143 
145 {
147  return false;
148 
149  if ( FID_IS_NEW( fid ) )
150  {
151  if ( !mAddedFeatures.contains( fid ) )
152  return false;
153  }
154  else // existing feature
155  {
156  if ( mDeletedFeatureIds.contains( fid ) )
157  return false;
158  }
159 
160  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
161  return true;
162 }
163 
164 
166 {
168  return false;
169 
170  if ( !L->hasGeometryType() )
171  {
172  return false;
173  }
174 
175  if ( FID_IS_NEW( fid ) )
176  {
177  if ( !mAddedFeatures.contains( fid ) )
178  return false;
179  }
180 
181  // TODO: check compatible geometry
182 
183  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
184  return true;
185 }
186 
187 
188 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
189 {
191  return false;
192 
193  if ( FID_IS_NEW( fid ) )
194  {
195  if ( !mAddedFeatures.contains( fid ) )
196  return false;
197  }
198 
199  if ( field < 0 || field >= L->pendingFields().count() ||
202  return false;
203 
204  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
205  return true;
206 }
207 
208 
210 {
212  return false;
213 
214  if ( field.name().isEmpty() )
215  return false;
216 
217  const QgsFields& updatedFields = L->pendingFields();
218  for ( int idx = 0; idx < updatedFields.count(); ++idx )
219  {
220  if ( updatedFields[idx].name() == field.name() )
221  return false;
222  }
223 
224  if ( !L->dataProvider()->supportedType( field ) )
225  return false;
226 
227  L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
228  return true;
229 }
230 
231 
233 {
235  return false;
236 
237  if ( index < 0 || index >= L->pendingFields().count() )
238  return false;
239 
240  // find out source of the field
241  QgsFields::FieldOrigin origin = L->pendingFields().fieldOrigin( index );
242  int originIndex = L->pendingFields().fieldOriginIndex( index );
243 
244  if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
245  return false;
246 
247  if ( origin == QgsFields::OriginJoin )
248  return false;
249 
250  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
251  return true;
252 }
253 
254 
255 bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
256 {
257  QgsVectorDataProvider* provider = L->dataProvider();
258  commitErrors.clear();
259 
260  int cap = provider->capabilities();
261  bool success = true;
262 
263  QgsFields oldFields = L->pendingFields();
264 
265  //
266  // delete attributes
267  //
268  bool attributesChanged = false;
269  if ( !mDeletedAttributeIds.isEmpty() )
270  {
272  {
273  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
274 
276 
277  mDeletedAttributeIds.clear();
278  attributesChanged = true;
279  }
280  else
281  {
282  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
283 #if 0
284  QString list = "ERROR: Pending attribute deletes:";
285  foreach ( int idx, mDeletedAttributeIds )
286  {
287  list.append( " " + L->pendingFields()[idx].name() );
288  }
289  commitErrors << list;
290 #endif
291  success = false;
292  }
293  }
294 
295  //
296  // add attributes
297  //
298  if ( !mAddedAttributes.isEmpty() )
299  {
301  {
302  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
303 
305 
306  mAddedAttributes.clear();
307  attributesChanged = true;
308  }
309  else
310  {
311  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
312 #if 0
313  QString list = "ERROR: Pending adds:";
314  foreach ( QgsField f, mAddedAttributes )
315  {
316  list.append( " " + f.name() );
317  }
318  commitErrors << list;
319 #endif
320  success = false;
321  }
322  }
323 
324  //
325  // check that addition/removal went as expected
326  //
327  bool attributeChangesOk = true;
328  if ( attributesChanged )
329  {
330  L->updateFields();
331  QgsFields newFields = L->pendingFields();
332 
333  if ( oldFields.count() != newFields.count() )
334  {
335  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
336  attributeChangesOk = false; // don't try attribute updates - they'll fail.
337  }
338 
339  for ( int i = 0; i < qMin( oldFields.count(), newFields.count() ); ++i )
340  {
341  const QgsField& oldField = oldFields[i];
342  const QgsField& newField = newFields[i];
343  if ( attributeChangesOk && oldField != newField )
344  {
345  commitErrors
346  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
347  << tr( "Provider: %1" ).arg( L->providerType() )
348  << tr( "Storage: %1" ).arg( L->storageType() )
349  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
350  .arg( tr( "expected field" ) )
351  .arg( oldField.name() )
352  .arg( QVariant::typeToName( oldField.type() ) )
353  .arg( oldField.typeName() )
354  .arg( oldField.length() )
355  .arg( oldField.precision() )
356  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
357  .arg( tr( "retrieved field" ) )
358  .arg( newField.name() )
359  .arg( QVariant::typeToName( newField.type() ) )
360  .arg( newField.typeName() )
361  .arg( newField.length() )
362  .arg( newField.precision() );
363  attributeChangesOk = false; // don't try attribute updates - they'll fail.
364  }
365  }
366  }
367 
368  if ( attributeChangesOk )
369  {
370  //
371  // change attributes
372  //
373  if ( !mChangedAttributeValues.isEmpty() )
374  {
376  {
377  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
378 
380 
381  mChangedAttributeValues.clear();
382  }
383  else
384  {
385  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
386 #if 0
387  QString list = "ERROR: pending changes:";
388  foreach ( QgsFeatureId id, mChangedAttributeValues.keys() )
389  {
390  list.append( "\n " + FID_TO_STRING( id ) + "[" );
391  foreach ( int idx, mChangedAttributeValues[ id ].keys() )
392  {
393  list.append( QString( " %1:%2" ).arg( L->pendingFields()[idx].name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
394  }
395  list.append( " ]" );
396  }
397  commitErrors << list;
398 #endif
399  success = false;
400  }
401  }
402 
403  //
404  // delete features
405  //
406  if ( success && !mDeletedFeatureIds.isEmpty() )
407  {
409  {
410  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
411  // TODO[MD]: we should not need this here
412  for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); ++it )
413  {
414  mChangedAttributeValues.remove( *it );
415  mChangedGeometries.remove( *it );
416  }
417 
419 
420  mDeletedFeatureIds.clear();
421  }
422  else
423  {
424  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
425 #if 0
426  QString list = "ERROR: pending deletes:";
427  foreach ( QgsFeatureId id, mDeletedFeatureIds )
428  {
429  list.append( " " + FID_TO_STRING( id ) );
430  }
431  commitErrors << list;
432 #endif
433  success = false;
434  }
435  }
436 
437  //
438  // add features
439  //
440  if ( success && !mAddedFeatures.isEmpty() )
441  {
443  {
444  QList<QgsFeatureId> ids;
445  QgsFeatureList featuresToAdd;
446  // get the list of added features in reversed order
447  // 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)
448  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
449 
450  if ( provider->addFeatures( featuresToAdd ) )
451  {
452  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
453 
454  emit committedFeaturesAdded( L->id(), featuresToAdd );
455 
456  // notify everyone that the features with temporary ids were updated with permanent ids
457  for ( int i = 0; i < featuresToAdd.count(); ++i )
458  {
459  if ( featuresToAdd[i].id() != ids[i] )
460  {
461  //update selection
462  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
463  {
464  L->mSelectedFeatureIds.remove( ids[i] );
465  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
466  }
467  emit featureDeleted( ids[i] );
468  emit featureAdded( featuresToAdd[i].id() );
469  }
470  }
471 
472  mAddedFeatures.clear();
473  }
474  else
475  {
476  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
477 #if 0
478  QString list = "ERROR: pending adds:";
479  foreach ( QgsFeature f, mAddedFeatures )
480  {
481  list.append( " " + FID_TO_STRING( f.id() ) + "[" );
482  for ( int i = 0; i < L->pendingFields().size(); i++ )
483  {
484  list.append( QString( " %1:%2" ).arg( L->pendingFields()[i].name() ).arg( f.attributes()[i].toString() ) );
485  }
486  list.append( " ]" );
487  }
488  commitErrors << list;
489 #endif
490  success = false;
491  }
492  }
493  else
494  {
495  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
496  success = false;
497  }
498  }
499  }
500  else
501  {
502  success = false;
503  }
504 
505  //
506  // update geometries
507  //
508  if ( success && !mChangedGeometries.isEmpty() )
509  {
511  {
512  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
513 
515 
516  mChangedGeometries.clear();
517  }
518  else
519  {
520  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
521  success = false;
522  }
523  }
524 
525  if ( !success && provider->hasErrors() )
526  {
527  commitErrors << tr( "\n Provider errors:" );
528  foreach ( QString e, provider->errors() )
529  {
530  commitErrors << " " + e.replace( "\n", "\n " );
531  }
532  provider->clearErrors();
533  }
534 
535  return success;
536 }
537 
538 
540 {
541  if ( !isModified() )
542  return;
543 
544  // limit canvas redraws to one by jumping to beginning of stack
545  // see QgsUndoWidget::indexChanged
546  L->undoStack()->setIndex( 0 );
547 
548  Q_ASSERT( mAddedAttributes.isEmpty() );
549  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
550  Q_ASSERT( mChangedAttributeValues.isEmpty() );
551  Q_ASSERT( mChangedGeometries.isEmpty() );
552  Q_ASSERT( mAddedFeatures.isEmpty() );
553 }
554 
555 #if 0
556 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
557 {
558  QString msg;
559  if ( !mChangedGeometries.isEmpty() )
560  {
561  msg += "CHANGED GEOMETRIES:\n";
562  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
563  {
564  // QgsFeatureId, QgsGeometry
565  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
566  }
567  }
568  return msg;
569 }
570 #endif
571 
573 {
574  // go through the changed attributes map and adapt indices
575  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
576  {
578  }
579 
580  // go through added features and adapt attributes
581  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
582  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
583  {
584  QgsAttributes attrs = featureIt->attributes();
585  attrs.insert( index, QVariant() );
586  featureIt->setAttributes( attrs );
587  }
588 }
589 
591 {
592  // go through the changed attributes map and adapt indices
593  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
594  {
596  // remove the attribute
597  if ( attrMap.contains( index ) )
598  attrMap.remove( index );
599 
600  // update attribute indices
601  updateAttributeMapIndex( attrMap, index, -1 );
602  }
603 
604  // go through added features and adapt attributes
605  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
606  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
607  {
608  QgsAttributes attrs = featureIt->attributes();
609  attrs.remove( index );
610  featureIt->setAttributes( attrs );
611  }
612 }
613 
614 
615 
617 {
618  QgsAttributeMap updatedMap;
619  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
620  {
621  int attrIndex = it.key();
622  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
623  }
624  map = updatedMap;
625 }
626 
627 
628 
630 {
631  L->updateFields();
632 }