QGIS API Documentation  2.8.2-Wien
 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 
107 
108 
109 
111 {
113  {
114  return false;
115  }
116  if ( L->mUpdatedFields.count() != f.attributes().count() )
117  return false;
118 
119  // TODO: check correct geometry type
120 
121  L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
122  return true;
123 }
124 
125 
127 {
129  return false;
130 
131  for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
132  {
133  addFeature( *iter );
134  }
135 
136  L->updateExtents();
137  return true;
138 }
139 
140 
141 
143 {
145  return false;
146 
147  if ( FID_IS_NEW( fid ) )
148  {
149  if ( !mAddedFeatures.contains( fid ) )
150  return false;
151  }
152  else // existing feature
153  {
154  if ( mDeletedFeatureIds.contains( fid ) )
155  return false;
156  }
157 
158  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
159  return true;
160 }
161 
162 
164 {
166  return false;
167 
168  if ( !L->hasGeometryType() )
169  {
170  return false;
171  }
172 
173  if ( FID_IS_NEW( fid ) )
174  {
175  if ( !mAddedFeatures.contains( fid ) )
176  return false;
177  }
178 
179  // TODO: check compatible geometry
180 
181  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
182  return true;
183 }
184 
185 
186 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
187 {
189  return false;
190 
191  if ( FID_IS_NEW( fid ) )
192  {
193  if ( !mAddedFeatures.contains( fid ) )
194  return false;
195  }
196 
197  if ( field < 0 || field >= L->pendingFields().count() ||
200  return false;
201 
202  L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, newValue, oldValue ) );
203  return true;
204 }
205 
206 
208 {
210  return false;
211 
212  if ( field.name().isEmpty() )
213  return false;
214 
215  const QgsFields& updatedFields = L->pendingFields();
216  for ( int idx = 0; idx < updatedFields.count(); ++idx )
217  {
218  if ( updatedFields[idx].name() == field.name() )
219  return false;
220  }
221 
222  if ( !L->dataProvider()->supportedType( field ) )
223  return false;
224 
225  L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
226  return true;
227 }
228 
229 
231 {
233  return false;
234 
235  if ( index < 0 || index >= L->pendingFields().count() )
236  return false;
237 
238  // find out source of the field
239  QgsFields::FieldOrigin origin = L->pendingFields().fieldOrigin( index );
240  int originIndex = L->pendingFields().fieldOriginIndex( index );
241 
242  if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
243  return false;
244 
245  if ( origin == QgsFields::OriginJoin )
246  return false;
247 
248  L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
249  return true;
250 }
251 
252 
253 bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
254 {
255  QgsVectorDataProvider* provider = L->dataProvider();
256  commitErrors.clear();
257 
258  int cap = provider->capabilities();
259  bool success = true;
260 
261  QgsFields oldFields = L->pendingFields();
262 
263  //
264  // delete attributes
265  //
266  bool attributesChanged = false;
267  if ( !mDeletedAttributeIds.isEmpty() )
268  {
270  {
271  commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
272 
274 
275  mDeletedAttributeIds.clear();
276  attributesChanged = true;
277  }
278  else
279  {
280  commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
281 #if 0
282  QString list = "ERROR: Pending attribute deletes:";
283  foreach ( int idx, mDeletedAttributeIds )
284  {
285  list.append( " " + L->pendingFields()[idx].name() );
286  }
287  commitErrors << list;
288 #endif
289  success = false;
290  }
291  }
292 
293  //
294  // add attributes
295  //
296  if ( !mAddedAttributes.isEmpty() )
297  {
299  {
300  commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
301 
303 
304  mAddedAttributes.clear();
305  attributesChanged = true;
306  }
307  else
308  {
309  commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
310 #if 0
311  QString list = "ERROR: Pending adds:";
312  foreach ( QgsField f, mAddedAttributes )
313  {
314  list.append( " " + f.name() );
315  }
316  commitErrors << list;
317 #endif
318  success = false;
319  }
320  }
321 
322  //
323  // check that addition/removal went as expected
324  //
325  bool attributeChangesOk = true;
326  if ( attributesChanged )
327  {
328  L->updateFields();
329  QgsFields newFields = L->pendingFields();
330 
331  if ( oldFields.count() != newFields.count() )
332  {
333  commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
334  attributeChangesOk = false; // don't try attribute updates - they'll fail.
335  }
336 
337  for ( int i = 0; i < qMin( oldFields.count(), newFields.count() ); ++i )
338  {
339  const QgsField& oldField = oldFields[i];
340  const QgsField& newField = newFields[i];
341  if ( attributeChangesOk && oldField != newField )
342  {
343  commitErrors
344  << tr( "ERROR: field with index %1 is not the same!" ).arg( i )
345  << tr( "Provider: %1" ).arg( L->providerType() )
346  << tr( "Storage: %1" ).arg( L->storageType() )
347  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
348  .arg( tr( "expected field" ) )
349  .arg( oldField.name() )
350  .arg( QVariant::typeToName( oldField.type() ) )
351  .arg( oldField.typeName() )
352  .arg( oldField.length() )
353  .arg( oldField.precision() )
354  << QString( "%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
355  .arg( tr( "retrieved field" ) )
356  .arg( newField.name() )
357  .arg( QVariant::typeToName( newField.type() ) )
358  .arg( newField.typeName() )
359  .arg( newField.length() )
360  .arg( newField.precision() );
361  attributeChangesOk = false; // don't try attribute updates - they'll fail.
362  }
363  }
364  }
365 
366  if ( attributeChangesOk )
367  {
368  //
369  // change attributes
370  //
371  if ( !mChangedAttributeValues.isEmpty() )
372  {
374  {
375  commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
376 
378 
379  mChangedAttributeValues.clear();
380  }
381  else
382  {
383  commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
384 #if 0
385  QString list = "ERROR: pending changes:";
386  foreach ( QgsFeatureId id, mChangedAttributeValues.keys() )
387  {
388  list.append( "\n " + FID_TO_STRING( id ) + "[" );
389  foreach ( int idx, mChangedAttributeValues[ id ].keys() )
390  {
391  list.append( QString( " %1:%2" ).arg( L->pendingFields()[idx].name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
392  }
393  list.append( " ]" );
394  }
395  commitErrors << list;
396 #endif
397  success = false;
398  }
399  }
400 
401  //
402  // delete features
403  //
404  if ( success && !mDeletedFeatureIds.isEmpty() )
405  {
407  {
408  commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
409  // TODO[MD]: we should not need this here
410  for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); ++it )
411  {
412  mChangedAttributeValues.remove( *it );
413  mChangedGeometries.remove( *it );
414  }
415 
417 
418  mDeletedFeatureIds.clear();
419  }
420  else
421  {
422  commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
423 #if 0
424  QString list = "ERROR: pending deletes:";
425  foreach ( QgsFeatureId id, mDeletedFeatureIds )
426  {
427  list.append( " " + FID_TO_STRING( id ) );
428  }
429  commitErrors << list;
430 #endif
431  success = false;
432  }
433  }
434 
435  //
436  // add features
437  //
438  if ( success && !mAddedFeatures.isEmpty() )
439  {
441  {
442  QList<QgsFeatureId> ids;
443  QgsFeatureList featuresToAdd;
444  // get the list of added features in reversed order
445  // 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)
446  mapToReversedLists( mAddedFeatures, ids, featuresToAdd );
447 
448  if ( provider->addFeatures( featuresToAdd ) )
449  {
450  commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
451 
452  emit committedFeaturesAdded( L->id(), featuresToAdd );
453 
454  // notify everyone that the features with temporary ids were updated with permanent ids
455  for ( int i = 0; i < featuresToAdd.count(); ++i )
456  {
457  if ( featuresToAdd[i].id() != ids[i] )
458  {
459  //update selection
460  if ( L->mSelectedFeatureIds.contains( ids[i] ) )
461  {
462  L->mSelectedFeatureIds.remove( ids[i] );
463  L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
464  }
465  emit featureDeleted( ids[i] );
466  emit featureAdded( featuresToAdd[i].id() );
467  }
468  }
469 
470  mAddedFeatures.clear();
471  }
472  else
473  {
474  commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
475 #if 0
476  QString list = "ERROR: pending adds:";
477  foreach ( QgsFeature f, mAddedFeatures )
478  {
479  list.append( " " + FID_TO_STRING( f.id() ) + "[" );
480  for ( int i = 0; i < L->pendingFields().size(); i++ )
481  {
482  list.append( QString( " %1:%2" ).arg( L->pendingFields()[i].name() ).arg( f.attributes()[i].toString() ) );
483  }
484  list.append( " ]" );
485  }
486  commitErrors << list;
487 #endif
488  success = false;
489  }
490  }
491  else
492  {
493  commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
494  success = false;
495  }
496  }
497  }
498  else
499  {
500  success = false;
501  }
502 
503  //
504  // update geometries
505  //
506  if ( success && !mChangedGeometries.isEmpty() )
507  {
509  {
510  commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
511 
513 
514  mChangedGeometries.clear();
515  }
516  else
517  {
518  commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
519  success = false;
520  }
521  }
522 
523  if ( !success && provider->hasErrors() )
524  {
525  commitErrors << tr( "\n Provider errors:" );
526  foreach ( QString e, provider->errors() )
527  {
528  commitErrors << " " + e.replace( "\n", "\n " );
529  }
530  provider->clearErrors();
531  }
532 
533  return success;
534 }
535 
536 
538 {
539  if ( !isModified() )
540  return;
541 
542  // limit canvas redraws to one by jumping to beginning of stack
543  // see QgsUndoWidget::indexChanged
544  L->undoStack()->setIndex( 0 );
545 
546  Q_ASSERT( mAddedAttributes.isEmpty() );
547  Q_ASSERT( mDeletedAttributeIds.isEmpty() );
548  Q_ASSERT( mChangedAttributeValues.isEmpty() );
549  Q_ASSERT( mChangedGeometries.isEmpty() );
550  Q_ASSERT( mAddedFeatures.isEmpty() );
551 }
552 
553 #if 0
554 QString QgsVectorLayerEditBuffer::dumpEditBuffer()
555 {
556  QString msg;
557  if ( !mChangedGeometries.isEmpty() )
558  {
559  msg += "CHANGED GEOMETRIES:\n";
560  for ( QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it )
561  {
562  // QgsFeatureId, QgsGeometry
563  msg += QString( "- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
564  }
565  }
566  return msg;
567 }
568 #endif
569 
571 {
572  // go through the changed attributes map and adapt indices
573  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
574  {
576  }
577 
578  // go through added features and adapt attributes
579  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
580  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
581  {
582  QgsAttributes& attrs = featureIt->attributes();
583  attrs.insert( index, QVariant() );
584  }
585 }
586 
588 {
589  // go through the changed attributes map and adapt indices
590  for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
591  {
593  // remove the attribute
594  if ( attrMap.contains( index ) )
595  attrMap.remove( index );
596 
597  // update attribute indices
598  updateAttributeMapIndex( attrMap, index, -1 );
599  }
600 
601  // go through added features and adapt attributes
602  QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
603  for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
604  {
605  QgsAttributes& attrs = featureIt->attributes();
606  attrs.remove( index );
607  }
608 }
609 
610 
611 
613 {
614  QgsAttributeMap updatedMap;
615  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
616  {
617  int attrIndex = it.key();
618  updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
619  }
620  map = updatedMap;
621 }
622 
623 
624 
626 {
627  L->updateFields();
628 }