QGIS API Documentation  master-59fd5e0
src/core/qgsvectorlayereditbuffer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsvectorlayereditbuffer.cpp
00003     ---------------------
00004     begin                : Dezember 2012
00005     copyright            : (C) 2012 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 #include "qgsvectorlayereditbuffer.h"
00016 
00017 #include "qgsgeometry.h"
00018 #include "qgslogger.h"
00019 #include "qgsvectorlayerundocommand.h"
00020 #include "qgsvectordataprovider.h"
00021 #include "qgsvectorlayer.h"
00022 
00023 
00024 QgsVectorLayerEditBuffer::QgsVectorLayerEditBuffer( QgsVectorLayer* layer )
00025     : L( layer )
00026 {
00027   connect( L->undoStack(), SIGNAL( indexChanged( int ) ), this, SLOT( undoIndexChanged( int ) ) ); // TODO[MD]: queued?
00028 }
00029 
00030 QgsVectorLayerEditBuffer::~QgsVectorLayerEditBuffer()
00031 {
00032 }
00033 
00034 
00035 bool QgsVectorLayerEditBuffer::isModified() const
00036 {
00037   return !L->undoStack()->isClean();
00038 }
00039 
00040 
00041 void QgsVectorLayerEditBuffer::undoIndexChanged( int index )
00042 {
00043   qDebug( "undo index changed %d", index );
00044   Q_UNUSED( index );
00045   emit layerModified();
00046 }
00047 
00048 
00049 void QgsVectorLayerEditBuffer::updateFields( QgsFields& fields )
00050 {
00051   // delete attributes from the higher indices to lower indices
00052   for ( int i = mDeletedAttributeIds.count() - 1; i >= 0; --i )
00053   {
00054     fields.remove( mDeletedAttributeIds[i] );
00055   }
00056   // add new fields
00057   for ( int i = 0; i < mAddedAttributes.count(); ++i )
00058   {
00059     fields.append( mAddedAttributes[i], QgsFields::OriginEdit, i );
00060   }
00061 }
00062 
00063 
00064 void QgsVectorLayerEditBuffer::updateFeatureGeometry( QgsFeature &f )
00065 {
00066   if ( mChangedGeometries.contains( f.id() ) )
00067     f.setGeometry( mChangedGeometries[f.id()] );
00068 }
00069 
00070 
00071 void QgsVectorLayerEditBuffer::updateChangedAttributes( QgsFeature &f )
00072 {
00073   QgsAttributes& attrs = f.attributes();
00074 
00075   // remove all attributes that will disappear - from higher indices to lower
00076   for ( int idx = mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
00077   {
00078     attrs.remove( mDeletedAttributeIds[idx] );
00079   }
00080 
00081   // adjust size to accommodate added attributes
00082   attrs.resize( attrs.count() + mAddedAttributes.count() );
00083 
00084   // update changed attributes
00085   if ( mChangedAttributeValues.contains( f.id() ) )
00086   {
00087     const QgsAttributeMap &map = mChangedAttributeValues[f.id()];
00088     for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); it++ )
00089       attrs[it.key()] = it.value();
00090   }
00091 }
00092 
00093 
00094 
00095 
00096 bool QgsVectorLayerEditBuffer::addFeature( QgsFeature& f )
00097 {
00098   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) )
00099   {
00100     return false;
00101   }
00102 
00103   int layerFieldCount = L->dataProvider()->fields().count() + mAddedAttributes.count() - mDeletedAttributeIds.count();
00104   if ( layerFieldCount != f.attributes().count() )
00105     return false;
00106 
00107   // TODO: check correct geometry type
00108 
00109   L->undoStack()->push( new QgsVectorLayerUndoCommandAddFeature( this, f ) );
00110   return true;
00111 }
00112 
00113 
00114 bool QgsVectorLayerEditBuffer::addFeatures( QgsFeatureList& features )
00115 {
00116   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) )
00117     return false;
00118 
00119   for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
00120   {
00121     addFeature( *iter );
00122   }
00123 
00124   L->updateExtents();
00125   return true;
00126 }
00127 
00128 
00129 
00130 bool QgsVectorLayerEditBuffer::deleteFeature( QgsFeatureId fid )
00131 {
00132   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
00133     return false;
00134 
00135   if ( FID_IS_NEW( fid ) )
00136   {
00137     if ( !mAddedFeatures.contains( fid ) )
00138       return false;
00139   }
00140   else // existing feature
00141   {
00142     if ( mDeletedFeatureIds.contains( fid ) )
00143       return false;
00144   }
00145 
00146   L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteFeature( this, fid ) );
00147   return true;
00148 }
00149 
00150 
00151 bool QgsVectorLayerEditBuffer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom )
00152 {
00153   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeGeometries ) )
00154     return false;
00155 
00156   if ( !L->hasGeometryType() )
00157   {
00158     return false;
00159   }
00160 
00161   if ( FID_IS_NEW( fid ) )
00162   {
00163     if ( !mAddedFeatures.contains( fid ) )
00164       return false;
00165   }
00166 
00167   // TODO: check compatible geometry
00168 
00169   L->undoStack()->push( new QgsVectorLayerUndoCommandChangeGeometry( this, fid, geom ) );
00170   return true;
00171 }
00172 
00173 
00174 bool QgsVectorLayerEditBuffer::changeAttributeValue( QgsFeatureId fid, int field, QVariant value )
00175 {
00176   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) )
00177     return false;
00178 
00179   if ( FID_IS_NEW( fid ) )
00180   {
00181     if ( !mAddedFeatures.contains( fid ) )
00182       return false;
00183   }
00184 
00185   if ( field < 0 || field >= L->pendingFields().count() ||
00186        L->pendingFields().fieldOrigin( field ) == QgsFields::OriginJoin )
00187     return false;
00188 
00189   L->undoStack()->push( new QgsVectorLayerUndoCommandChangeAttribute( this, fid, field, value ) );
00190   return true;
00191 }
00192 
00193 
00194 bool QgsVectorLayerEditBuffer::addAttribute( const QgsField &field )
00195 {
00196   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes ) )
00197     return false;
00198 
00199   if ( field.name().isEmpty() )
00200     return false;
00201 
00202   const QgsFields& updatedFields = L->pendingFields();
00203   for ( int idx = 0; idx < updatedFields.count(); ++idx )
00204   {
00205     if ( updatedFields[idx].name() == field.name() )
00206       return false;
00207   }
00208 
00209   if ( !L->dataProvider()->supportedType( field ) )
00210     return false;
00211 
00212   L->undoStack()->push( new QgsVectorLayerUndoCommandAddAttribute( this, field ) );
00213   return true;
00214 }
00215 
00216 
00217 bool QgsVectorLayerEditBuffer::deleteAttribute( int index )
00218 {
00219   if ( !( L->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes ) )
00220     return false;
00221 
00222   if ( index < 0 || index >= L->pendingFields().count() )
00223     return false;
00224 
00225   // find out source of the field
00226   QgsFields::FieldOrigin origin = L->pendingFields().fieldOrigin( index );
00227   int originIndex = L->pendingFields().fieldOriginIndex( index );
00228 
00229   if ( origin == QgsFields::OriginProvider && mDeletedAttributeIds.contains( originIndex ) )
00230     return false;
00231 
00232   if ( origin == QgsFields::OriginJoin )
00233     return false;
00234 
00235   L->undoStack()->push( new QgsVectorLayerUndoCommandDeleteAttribute( this, index ) );
00236   return true;
00237 }
00238 
00239 
00240 bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
00241 {
00242   QgsVectorDataProvider* provider = L->dataProvider();
00243   commitErrors.clear();
00244 
00245   int cap = provider->capabilities();
00246   bool success = true;
00247 
00248   QgsFields oldFields = L->pendingFields();
00249 
00250   //
00251   // delete attributes
00252   //
00253   bool attributesChanged = false;
00254   if ( !mDeletedAttributeIds.isEmpty() )
00255   {
00256     if (( cap & QgsVectorDataProvider::DeleteAttributes ) && provider->deleteAttributes( mDeletedAttributeIds.toSet() ) )
00257     {
00258       commitErrors << tr( "SUCCESS: %n attribute(s) deleted.", "deleted attributes count", mDeletedAttributeIds.size() );
00259 
00260       emit committedAttributesDeleted( L->id(), mDeletedAttributeIds );
00261 
00262       mDeletedAttributeIds.clear();
00263       attributesChanged = true;
00264     }
00265     else
00266     {
00267       commitErrors << tr( "ERROR: %n attribute(s) not deleted.", "not deleted attributes count", mDeletedAttributeIds.size() );
00268       success = false;
00269     }
00270   }
00271 
00272   //
00273   // add attributes
00274   //
00275   if ( !mAddedAttributes.isEmpty() )
00276   {
00277     if (( cap & QgsVectorDataProvider::AddAttributes ) && provider->addAttributes( mAddedAttributes ) )
00278     {
00279       commitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributes.size() );
00280 
00281       emit committedAttributesAdded( L->id(), mAddedAttributes );
00282 
00283       mAddedAttributes.clear();
00284       attributesChanged = true;
00285     }
00286     else
00287     {
00288       commitErrors << tr( "ERROR: %n new attribute(s) not added", "not added attributes count", mAddedAttributes.size() );
00289       success = false;
00290     }
00291   }
00292 
00293   //
00294   // check that addition/removal went as expected
00295   //
00296   bool attributeChangesOk = true;
00297   if ( attributesChanged )
00298   {
00299     L->updateFields();
00300     QgsFields newFields = L->pendingFields();
00301 
00302     if ( oldFields.count() != newFields.count() )
00303     {
00304       commitErrors << tr( "ERROR: the count of fields is incorrect after addition/removal of fields!" );
00305       attributeChangesOk = false;   // don't try attribute updates - they'll fail.
00306     }
00307 
00308     for ( int i = 0; i < oldFields.count(); ++i )
00309     {
00310       const QgsField& oldField = oldFields[i];
00311       const QgsField& newField = newFields[i];
00312       if ( attributeChangesOk && oldField != newField )
00313       {
00314         commitErrors << tr( "ERROR: field with index %1 is not the same!" ).arg( i );
00315         attributeChangesOk = false;   // don't try attribute updates - they'll fail.
00316       }
00317     }
00318   }
00319 
00320   if ( attributeChangesOk )
00321   {
00322     //
00323     // change attributes
00324     //
00325     if ( !mChangedAttributeValues.isEmpty() )
00326     {
00327       if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && provider->changeAttributeValues( mChangedAttributeValues ) )
00328       {
00329         commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
00330 
00331         emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues );
00332 
00333         mChangedAttributeValues.clear();
00334       }
00335       else
00336       {
00337         commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
00338         success = false;
00339       }
00340     }
00341 
00342     //
00343     // delete features
00344     //
00345     if ( !mDeletedFeatureIds.isEmpty() )
00346     {
00347       if (( cap & QgsVectorDataProvider::DeleteFeatures ) && provider->deleteFeatures( mDeletedFeatureIds ) )
00348       {
00349         commitErrors << tr( "SUCCESS: %n feature(s) deleted.", "deleted features count", mDeletedFeatureIds.size() );
00350         // TODO[MD]: we should not need this here
00351         for ( QgsFeatureIds::const_iterator it = mDeletedFeatureIds.begin(); it != mDeletedFeatureIds.end(); it++ )
00352         {
00353           mChangedAttributeValues.remove( *it );
00354           mChangedGeometries.remove( *it );
00355         }
00356 
00357         emit committedFeaturesRemoved( L->id(), mDeletedFeatureIds );
00358 
00359         mDeletedFeatureIds.clear();
00360       }
00361       else
00362       {
00363         commitErrors << tr( "ERROR: %n feature(s) not deleted.", "not deleted features count", mDeletedFeatureIds.size() );
00364         success = false;
00365       }
00366     }
00367 
00368     //
00369     //  add features
00370     //
00371     if ( !mAddedFeatures.isEmpty() )
00372     {
00373       if ( cap & QgsVectorDataProvider::AddFeatures )
00374       {
00375         QList<QgsFeatureId> ids = mAddedFeatures.keys();
00376         QgsFeatureList featuresToAdd = mAddedFeatures.values();
00377 
00378         if ( provider->addFeatures( featuresToAdd ) )
00379         {
00380           commitErrors << tr( "SUCCESS: %n feature(s) added.", "added features count", featuresToAdd.size() );
00381 
00382           emit committedFeaturesAdded( L->id(), featuresToAdd );
00383 
00384           // notify everyone that the features with temporary ids were updated with permanent ids
00385           for ( int i = 0; i < featuresToAdd.count(); ++i )
00386           {
00387             if ( featuresToAdd[i].id() != ids[i] )
00388             {
00389               //update selection
00390               if ( L->mSelectedFeatureIds.contains( ids[i] ) )
00391               {
00392                 L->mSelectedFeatureIds.remove( ids[i] );
00393                 L->mSelectedFeatureIds.insert( featuresToAdd[i].id() );
00394               }
00395               emit featureDeleted( ids[i] );
00396               emit featureAdded( featuresToAdd[i].id() );
00397             }
00398           }
00399 
00400           mAddedFeatures.clear();
00401         }
00402         else
00403         {
00404           commitErrors << tr( "ERROR: %n feature(s) not added.", "not added features count", mAddedFeatures.size() );
00405           success = false;
00406         }
00407       }
00408       else
00409       {
00410         commitErrors << tr( "ERROR: %n feature(s) not added - provider doesn't support adding features.", "not added features count", mAddedFeatures.size() );
00411         success = false;
00412       }
00413     }
00414   }
00415 
00416   //
00417   // update geometries
00418   //
00419   if ( !mChangedGeometries.isEmpty() )
00420   {
00421     if (( cap & QgsVectorDataProvider::ChangeGeometries ) && provider->changeGeometryValues( mChangedGeometries ) )
00422     {
00423       commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
00424 
00425       emit committedGeometriesChanges( L->id(), mChangedGeometries );
00426 
00427       mChangedGeometries.clear();
00428     }
00429     else
00430     {
00431       commitErrors << tr( "ERROR: %n geometries not changed.", "not changed geometries count", mChangedGeometries.size() );
00432       success = false;
00433     }
00434   }
00435 
00436   if ( !success )
00437   {
00438     if ( provider->hasErrors() )
00439     {
00440       commitErrors << tr( "\n  Provider errors:" ) << provider->errors();
00441       provider->clearErrors();
00442     }
00443   }
00444 
00445   return success;
00446 }
00447 
00448 
00449 void QgsVectorLayerEditBuffer::rollBack()
00450 {
00451   if ( !isModified() )
00452     return;
00453 
00454   // limit canvas redraws to one by jumping to beginning of stack
00455   // see QgsUndoWidget::indexChanged
00456   L->undoStack()->setIndex( 0 );
00457 
00458   Q_ASSERT( mAddedAttributes.isEmpty() );
00459   Q_ASSERT( mDeletedAttributeIds.isEmpty() );
00460   Q_ASSERT( mChangedAttributeValues.isEmpty() );
00461   Q_ASSERT( mChangedGeometries.isEmpty() );
00462   Q_ASSERT( mAddedFeatures.isEmpty() );
00463 }
00464 
00465 
00466 
00467 
00468 
00469 /*QString QgsVectorLayerEditBuffer::dumpEditBuffer()
00470 {
00471   QString msg;
00472   if (!mChangedGeometries.isEmpty())
00473   {
00474     msg += "CHANGED GEOMETRIES:\n";
00475     for (QgsGeometryMap::const_iterator it = mChangedGeometries.begin(); it != mChangedGeometries.end(); ++it)
00476     {
00477       // QgsFeatureId, QgsGeometry
00478       msg += QString("- FID %1: %2").arg(it.key()).arg(it.value().to)
00479     }
00480   }
00481   return msg;
00482 }*/
00483 
00484 
00485 
00486 
00487 void QgsVectorLayerEditBuffer::handleAttributeAdded( int index )
00488 {
00489   // go through the changed attributes map and adapt indices
00490   for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
00491   {
00492     updateAttributeMapIndex( mChangedAttributeValues[i], index, + 1 );
00493   }
00494 
00495   // go through added features and adapt attributes
00496   QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
00497   for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
00498   {
00499     QgsAttributes& attrs = featureIt->attributes();
00500     attrs.insert( index, QVariant() );
00501   }
00502 }
00503 
00504 void QgsVectorLayerEditBuffer::handleAttributeDeleted( int index )
00505 {
00506   // go through the changed attributes map and adapt indices
00507   for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
00508   {
00509     QgsAttributeMap& attrMap = mChangedAttributeValues[i];
00510     // remove the attribute
00511     if ( attrMap.contains( index ) )
00512       attrMap.remove( index );
00513 
00514     // update attribute indices
00515     updateAttributeMapIndex( attrMap, index, -1 );
00516   }
00517 
00518   // go through added features and adapt attributes
00519   QgsFeatureMap::iterator featureIt = mAddedFeatures.begin();
00520   for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
00521   {
00522     QgsAttributes& attrs = featureIt->attributes();
00523     attrs.remove( index );
00524   }
00525 }
00526 
00527 
00528 
00529 void QgsVectorLayerEditBuffer::updateAttributeMapIndex( QgsAttributeMap& map, int index, int offset ) const
00530 {
00531   QgsAttributeMap updatedMap;
00532   for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
00533   {
00534     int attrIndex = it.key();
00535     updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
00536   }
00537   map = updatedMap;
00538 }
00539 
00540 
00541 
00542 void QgsVectorLayerEditBuffer::updateLayerFields()
00543 {
00544   L->updateFields();
00545 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines