LCOV - code coverage report
Current view: top level - core/vector - qgsvectorlayereditbuffer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 38 404 9.4 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           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 : }

Generated by: LCOV version 1.14