LCOV - code coverage report
Current view: top level - core/vector - qgsvectorlayerexporter.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 316 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                           qgsvectorlayerexporter.cpp
       3                 :            :                              -------------------
       4                 :            :     begin                : Thu Aug 25 2011
       5                 :            :     copyright            : (C) 2011 by Giuseppe Sucameli
       6                 :            :     email                : brush.tyler at gmail.com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : 
      19                 :            : #include "qgsfields.h"
      20                 :            : #include "qgsfeature.h"
      21                 :            : #include "qgsfeatureiterator.h"
      22                 :            : #include "qgsgeometry.h"
      23                 :            : #include "qgslogger.h"
      24                 :            : #include "qgsmessagelog.h"
      25                 :            : #include "qgsgeometrycollection.h"
      26                 :            : #include "qgscoordinatereferencesystem.h"
      27                 :            : #include "qgsvectorlayerexporter.h"
      28                 :            : #include "qgsproviderregistry.h"
      29                 :            : #include "qgsdatasourceuri.h"
      30                 :            : #include "qgsexception.h"
      31                 :            : #include "qgsvectordataprovider.h"
      32                 :            : #include "qgsvectorlayer.h"
      33                 :            : #include "qgsabstractgeometry.h"
      34                 :            : 
      35                 :            : #include <QProgressDialog>
      36                 :            : 
      37                 :            : typedef QgsVectorLayerExporter::ExportError createEmptyLayer_t(
      38                 :            :   const QString &uri,
      39                 :            :   const QgsFields &fields,
      40                 :            :   QgsWkbTypes::Type geometryType,
      41                 :            :   const QgsCoordinateReferenceSystem &destCRS,
      42                 :            :   bool overwrite,
      43                 :            :   QMap<int, int> *oldToNewAttrIdx,
      44                 :            :   QString *errorMessage,
      45                 :            :   const QMap<QString, QVariant> *options
      46                 :            : );
      47                 :            : 
      48                 :            : 
      49                 :          0 : QgsVectorLayerExporter::QgsVectorLayerExporter( const QString &uri,
      50                 :            :     const QString &providerKey,
      51                 :            :     const QgsFields &fields,
      52                 :            :     QgsWkbTypes::Type geometryType,
      53                 :            :     const QgsCoordinateReferenceSystem &crs,
      54                 :            :     bool overwrite,
      55                 :            :     const QMap<QString, QVariant> &options,
      56                 :            :     QgsFeatureSink::SinkFlags sinkFlags )
      57                 :          0 :   : mErrorCount( 0 )
      58                 :          0 :   , mAttributeCount( -1 )
      59                 :            : 
      60                 :          0 : {
      61                 :          0 :   mProvider = nullptr;
      62                 :            : 
      63                 :          0 :   QMap<QString, QVariant> modifiedOptions( options );
      64                 :            : 
      65                 :          0 :   if ( providerKey == QLatin1String( "ogr" ) &&
      66                 :          0 :        options.contains( QStringLiteral( "driverName" ) ) &&
      67                 :          0 :        ( options[ QStringLiteral( "driverName" ) ].toString().compare( QLatin1String( "GPKG" ), Qt::CaseInsensitive ) == 0 ||
      68                 :          0 :          options[ QStringLiteral( "driverName" ) ].toString().compare( QLatin1String( "SQLite" ), Qt::CaseInsensitive ) == 0 ) )
      69                 :            :   {
      70                 :          0 :     if ( geometryType != QgsWkbTypes::NoGeometry )
      71                 :            :     {
      72                 :            :       // For GPKG/Spatialite, we explicitly ask not to create a spatial index at
      73                 :            :       // layer creation since this would slow down inserts. Defer its creation
      74                 :            :       // to end of exportLayer() or destruction of this object.
      75                 :          0 :       QStringList modifiedLayerOptions;
      76                 :          0 :       if ( options.contains( QStringLiteral( "layerOptions" ) ) )
      77                 :            :       {
      78                 :          0 :         QStringList layerOptions = options.value( QStringLiteral( "layerOptions" ) ).toStringList();
      79                 :          0 :         for ( const QString &layerOption : layerOptions )
      80                 :            :         {
      81                 :          0 :           if ( layerOption.compare( QLatin1String( "SPATIAL_INDEX=YES" ), Qt::CaseInsensitive ) == 0 ||
      82                 :          0 :                layerOption.compare( QLatin1String( "SPATIAL_INDEX=ON" ), Qt::CaseInsensitive ) == 0 ||
      83                 :          0 :                layerOption.compare( QLatin1String( "SPATIAL_INDEX=TRUE" ), Qt::CaseInsensitive ) == 0 ||
      84                 :          0 :                layerOption.compare( QLatin1String( "SPATIAL_INDEX=1" ), Qt::CaseInsensitive ) == 0 )
      85                 :            :           {
      86                 :            :             // do nothing
      87                 :          0 :           }
      88                 :          0 :           else if ( layerOption.compare( QLatin1String( "SPATIAL_INDEX=NO" ), Qt::CaseInsensitive ) == 0 ||
      89                 :          0 :                     layerOption.compare( QLatin1String( "SPATIAL_INDEX=OFF" ), Qt::CaseInsensitive ) == 0 ||
      90                 :          0 :                     layerOption.compare( QLatin1String( "SPATIAL_INDEX=FALSE" ), Qt::CaseInsensitive ) == 0 ||
      91                 :          0 :                     layerOption.compare( QLatin1String( "SPATIAL_INDEX=0" ), Qt::CaseInsensitive ) == 0 )
      92                 :            :           {
      93                 :          0 :             mCreateSpatialIndex = false;
      94                 :          0 :           }
      95                 :            :           else
      96                 :            :           {
      97                 :          0 :             modifiedLayerOptions << layerOption;
      98                 :            :           }
      99                 :            :         }
     100                 :          0 :       }
     101                 :          0 :       modifiedLayerOptions << QStringLiteral( "SPATIAL_INDEX=FALSE" );
     102                 :          0 :       modifiedOptions[ QStringLiteral( "layerOptions" ) ] = modifiedLayerOptions;
     103                 :          0 :     }
     104                 :          0 :   }
     105                 :            : 
     106                 :            :   // create an empty layer
     107                 :          0 :   QString errMsg;
     108                 :          0 :   QgsProviderRegistry *pReg = QgsProviderRegistry::instance();
     109                 :          0 :   mError = pReg->createEmptyLayer( providerKey, uri, fields, geometryType, crs, overwrite, mOldToNewAttrIdx,
     110                 :          0 :                                    errMsg, !modifiedOptions.isEmpty() ? &modifiedOptions : nullptr );
     111                 :          0 :   if ( errorCode() )
     112                 :            :   {
     113                 :          0 :     mErrorMessage = errMsg;
     114                 :          0 :     return;
     115                 :            :   }
     116                 :            : 
     117                 :          0 :   const auto constMOldToNewAttrIdx = mOldToNewAttrIdx;
     118                 :          0 :   for ( int idx : constMOldToNewAttrIdx )
     119                 :            :   {
     120                 :          0 :     if ( idx > mAttributeCount )
     121                 :          0 :       mAttributeCount = idx;
     122                 :            :   }
     123                 :            : 
     124                 :          0 :   mAttributeCount++;
     125                 :            : 
     126                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Created empty layer" ), 2 );
     127                 :            : 
     128                 :          0 :   QString uriUpdated( uri );
     129                 :            :   // HACK sorry...
     130                 :          0 :   if ( providerKey == QLatin1String( "ogr" ) )
     131                 :            :   {
     132                 :          0 :     QString layerName;
     133                 :          0 :     if ( options.contains( QStringLiteral( "layerName" ) ) )
     134                 :          0 :       layerName = options.value( QStringLiteral( "layerName" ) ).toString();
     135                 :          0 :     if ( !layerName.isEmpty() )
     136                 :            :     {
     137                 :          0 :       uriUpdated += QLatin1String( "|layername=" );
     138                 :          0 :       uriUpdated += layerName;
     139                 :          0 :     }
     140                 :          0 :   }
     141                 :            : 
     142                 :            :   // Oracle specific HACK: we cannot guess the geometry type when there is no rows, so we need
     143                 :            :   // to force it in the uri
     144                 :          0 :   if ( providerKey == QLatin1String( "oracle" ) )
     145                 :            :   {
     146                 :          0 :     uriUpdated += QStringLiteral( " type=%1" ).arg( QgsWkbTypes::displayString( geometryType ) );
     147                 :          0 :   }
     148                 :            : 
     149                 :          0 :   QgsDataProvider::ProviderOptions providerOptions;
     150                 :          0 :   QgsVectorDataProvider *vectorProvider = qobject_cast< QgsVectorDataProvider * >( pReg->createProvider( providerKey, uriUpdated, providerOptions ) );
     151                 :          0 :   if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
     152                 :            :   {
     153                 :          0 :     mError = ErrInvalidLayer;
     154                 :          0 :     mErrorMessage = QObject::tr( "Loading of layer failed" );
     155                 :            : 
     156                 :          0 :     delete vectorProvider;
     157                 :          0 :     return;
     158                 :            :   }
     159                 :            : 
     160                 :            :   // If the result is a geopackage layer and there is already a field name FID requested which
     161                 :          0 :   // might contain duplicates, make sure to generate a new field with a unique name instead
     162                 :            :   // that will be filled by ogr with unique values.
     163                 :            : 
     164                 :            :   // HACK sorry
     165                 :          0 :   const QString path = QgsProviderRegistry::instance()->decodeUri( QStringLiteral( "ogr" ), uri ).value( QStringLiteral( "path" ) ).toString();
     166                 :          0 :   if ( sinkFlags.testFlag( QgsFeatureSink::SinkFlag::RegeneratePrimaryKey ) && path.endsWith( QLatin1String( ".gpkg" ), Qt::CaseInsensitive ) )
     167                 :            :   {
     168                 :          0 :     QString fidName = options.value( QStringLiteral( "FID" ), QStringLiteral( "FID" ) ).toString();
     169                 :          0 :     int fidIdx = fields.lookupField( fidName );
     170                 :          0 :     if ( fidIdx != -1 )
     171                 :            :     {
     172                 :          0 :       mOldToNewAttrIdx.remove( fidIdx );
     173                 :          0 :     }
     174                 :          0 :   }
     175                 :            : 
     176                 :          0 :   mProvider = vectorProvider;
     177                 :          0 :   mError = NoError;
     178                 :          0 : }
     179                 :            : 
     180                 :          0 : QgsVectorLayerExporter::~QgsVectorLayerExporter()
     181                 :          0 : {
     182                 :          0 :   flushBuffer();
     183                 :            : 
     184                 :          0 :   if ( mCreateSpatialIndex )
     185                 :            :   {
     186                 :          0 :     createSpatialIndex();
     187                 :          0 :   }
     188                 :            : 
     189                 :          0 :   delete mProvider;
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : QgsVectorLayerExporter::ExportError QgsVectorLayerExporter::errorCode() const
     193                 :            : {
     194                 :          0 :   return mError;
     195                 :            : }
     196                 :            : 
     197                 :          0 : QString QgsVectorLayerExporter::errorMessage() const
     198                 :            : {
     199                 :          0 :   return mErrorMessage;
     200                 :            : }
     201                 :            : 
     202                 :          0 : bool QgsVectorLayerExporter::addFeatures( QgsFeatureList &features, Flags flags )
     203                 :            : {
     204                 :          0 :   QgsFeatureList::iterator fIt = features.begin();
     205                 :          0 :   bool result = true;
     206                 :          0 :   for ( ; fIt != features.end(); ++fIt )
     207                 :            :   {
     208                 :          0 :     result = result && addFeature( *fIt, flags );
     209                 :          0 :   }
     210                 :          0 :   return result;
     211                 :            : }
     212                 :            : 
     213                 :          0 : bool QgsVectorLayerExporter::addFeature( QgsFeature &feat, Flags )
     214                 :            : {
     215                 :          0 :   QgsAttributes attrs = feat.attributes();
     216                 :            : 
     217                 :          0 :   QgsFeature newFeat;
     218                 :          0 :   if ( feat.hasGeometry() )
     219                 :          0 :     newFeat.setGeometry( feat.geometry() );
     220                 :            : 
     221                 :          0 :   newFeat.initAttributes( mAttributeCount );
     222                 :            : 
     223                 :          0 :   for ( int i = 0; i < attrs.count(); ++i )
     224                 :            :   {
     225                 :            :     // add only mapped attributes (un-mapped ones will not be present in the
     226                 :            :     // destination layer)
     227                 :          0 :     int dstIdx = mOldToNewAttrIdx.value( i, -1 );
     228                 :          0 :     if ( dstIdx < 0 )
     229                 :          0 :       continue;
     230                 :            : 
     231                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "moving field from pos %1 to %2" ).arg( i ).arg( dstIdx ), 3 );
     232                 :          0 :     newFeat.setAttribute( dstIdx, attrs.at( i ) );
     233                 :          0 :   }
     234                 :            : 
     235                 :          0 :   mFeatureBuffer.append( newFeat );
     236                 :          0 :   mFeatureBufferMemoryUsage += newFeat.approximateMemoryUsage();
     237                 :            : 
     238                 :          0 :   if ( mFeatureBufferMemoryUsage >= 100 * 1000 * 1000 )
     239                 :            :   {
     240                 :          0 :     return flushBuffer();
     241                 :            :   }
     242                 :            : 
     243                 :          0 :   return true;
     244                 :          0 : }
     245                 :            : 
     246                 :          0 : QString QgsVectorLayerExporter::lastError() const
     247                 :            : {
     248                 :          0 :   return mErrorMessage;
     249                 :            : }
     250                 :            : 
     251                 :          0 : bool QgsVectorLayerExporter::flushBuffer()
     252                 :          0 : {
     253                 :          0 :   mFeatureBufferMemoryUsage = 0;
     254                 :          0 :   if ( mFeatureBuffer.count() <= 0 )
     255                 :          0 :     return true;
     256                 :            : 
     257                 :          0 :   if ( !mProvider->addFeatures( mFeatureBuffer, QgsFeatureSink::FastInsert ) )
     258                 :            :   {
     259                 :          0 :     QStringList errors = mProvider->errors();
     260                 :          0 :     mProvider->clearErrors();
     261                 :            : 
     262                 :          0 :     mErrorMessage = QObject::tr( "Creation error for features from #%1 to #%2. Provider errors was: \n%3" )
     263                 :          0 :                     .arg( mFeatureBuffer.first().id() )
     264                 :          0 :                     .arg( mFeatureBuffer.last().id() )
     265                 :          0 :                     .arg( errors.join( QLatin1Char( '\n' ) ) );
     266                 :            : 
     267                 :          0 :     mError = ErrFeatureWriteFailed;
     268                 :          0 :     mErrorCount += mFeatureBuffer.count();
     269                 :            : 
     270                 :          0 :     mFeatureBuffer.clear();
     271                 :          0 :     QgsDebugMsg( mErrorMessage );
     272                 :          0 :     return false;
     273                 :          0 :   }
     274                 :            : 
     275                 :          0 :   mFeatureBuffer.clear();
     276                 :          0 :   return true;
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : bool QgsVectorLayerExporter::createSpatialIndex()
     280                 :            : {
     281                 :          0 :   mCreateSpatialIndex = false;
     282                 :          0 :   if ( mProvider && ( mProvider->capabilities() & QgsVectorDataProvider::CreateSpatialIndex ) != 0 )
     283                 :            :   {
     284                 :          0 :     return mProvider->createSpatialIndex();
     285                 :            :   }
     286                 :            :   else
     287                 :            :   {
     288                 :          0 :     return true;
     289                 :            :   }
     290                 :          0 : }
     291                 :            : 
     292                 :            : QgsVectorLayerExporter::ExportError
     293                 :          0 : QgsVectorLayerExporter::exportLayer( QgsVectorLayer *layer,
     294                 :            :                                      const QString &uri,
     295                 :            :                                      const QString &providerKey,
     296                 :            :                                      const QgsCoordinateReferenceSystem &destCRS,
     297                 :            :                                      bool onlySelected,
     298                 :            :                                      QString *errorMessage,
     299                 :            :                                      const QMap<QString, QVariant> &options,
     300                 :            :                                      QgsFeedback *feedback )
     301                 :            : {
     302                 :          0 :   QgsCoordinateReferenceSystem outputCRS;
     303                 :          0 :   QgsCoordinateTransform ct;
     304                 :          0 :   bool shallTransform = false;
     305                 :            : 
     306                 :          0 :   if ( !layer )
     307                 :          0 :     return ErrInvalidLayer;
     308                 :            : 
     309                 :          0 :   if ( destCRS.isValid() )
     310                 :            :   {
     311                 :            :     // This means we should transform
     312                 :          0 :     outputCRS = destCRS;
     313                 :          0 :     shallTransform = true;
     314                 :          0 :   }
     315                 :            :   else
     316                 :            :   {
     317                 :            :     // This means we shouldn't transform, use source CRS as output (if defined)
     318                 :          0 :     outputCRS = layer->crs();
     319                 :            :   }
     320                 :            : 
     321                 :            : 
     322                 :          0 :   bool overwrite = false;
     323                 :          0 :   bool forceSinglePartGeom = false;
     324                 :          0 :   QMap<QString, QVariant> providerOptions = options;
     325                 :          0 :   if ( !options.isEmpty() )
     326                 :            :   {
     327                 :          0 :     overwrite = providerOptions.take( QStringLiteral( "overwrite" ) ).toBool();
     328                 :          0 :     forceSinglePartGeom = providerOptions.take( QStringLiteral( "forceSinglePartGeometryType" ) ).toBool();
     329                 :          0 :   }
     330                 :            : 
     331                 :          0 :   QgsFields fields = layer->fields();
     332                 :            : 
     333                 :          0 :   QgsWkbTypes::Type wkbType = layer->wkbType();
     334                 :            : 
     335                 :            :   // Special handling for Shapefiles
     336                 :          0 :   if ( layer->providerType() == QLatin1String( "ogr" ) && layer->storageType() == QLatin1String( "ESRI Shapefile" ) )
     337                 :            :   {
     338                 :            :     // convert field names to lowercase
     339                 :          0 :     for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
     340                 :            :     {
     341                 :          0 :       fields.rename( fldIdx, fields.at( fldIdx ).name().toLower() );
     342                 :          0 :     }
     343                 :          0 :   }
     344                 :            : 
     345                 :          0 :   bool convertGeometryToSinglePart = false;
     346                 :          0 :   if ( forceSinglePartGeom && QgsWkbTypes::isMultiType( wkbType ) )
     347                 :            :   {
     348                 :          0 :     wkbType = QgsWkbTypes::singleType( wkbType );
     349                 :          0 :     convertGeometryToSinglePart = true;
     350                 :          0 :   }
     351                 :            : 
     352                 :          0 :   QgsVectorLayerExporter *writer =
     353                 :          0 :     new QgsVectorLayerExporter( uri, providerKey, fields, wkbType, outputCRS, overwrite, providerOptions );
     354                 :            : 
     355                 :            :   // check whether file creation was successful
     356                 :          0 :   ExportError err = writer->errorCode();
     357                 :          0 :   if ( err != NoError )
     358                 :            :   {
     359                 :          0 :     if ( errorMessage )
     360                 :          0 :       *errorMessage = writer->errorMessage();
     361                 :          0 :     delete writer;
     362                 :          0 :     return err;
     363                 :            :   }
     364                 :            : 
     365                 :          0 :   if ( errorMessage )
     366                 :            :   {
     367                 :          0 :     errorMessage->clear();
     368                 :          0 :   }
     369                 :            : 
     370                 :          0 :   QgsFeature fet;
     371                 :            : 
     372                 :          0 :   QgsFeatureRequest req;
     373                 :          0 :   if ( wkbType == QgsWkbTypes::NoGeometry )
     374                 :          0 :     req.setFlags( QgsFeatureRequest::NoGeometry );
     375                 :          0 :   if ( onlySelected )
     376                 :          0 :     req.setFilterFids( layer->selectedFeatureIds() );
     377                 :            : 
     378                 :          0 :   QgsFeatureIterator fit = layer->getFeatures( req );
     379                 :            : 
     380                 :            :   // Create our transform
     381                 :          0 :   if ( destCRS.isValid() )
     382                 :            :   {
     383                 :          0 :     ct = QgsCoordinateTransform( layer->crs(), destCRS, layer->transformContext() );
     384                 :          0 :   }
     385                 :            : 
     386                 :            :   // Check for failure
     387                 :          0 :   if ( !ct.isValid() )
     388                 :          0 :     shallTransform = false;
     389                 :            : 
     390                 :          0 :   long n = 0;
     391                 :          0 :   long approxTotal = onlySelected ? layer->selectedFeatureCount() : layer->featureCount();
     392                 :            : 
     393                 :          0 :   if ( errorMessage )
     394                 :            :   {
     395                 :          0 :     *errorMessage = QObject::tr( "Feature write errors:" );
     396                 :          0 :   }
     397                 :            : 
     398                 :          0 :   bool canceled = false;
     399                 :            : 
     400                 :            :   // write all features
     401                 :          0 :   while ( fit.nextFeature( fet ) )
     402                 :            :   {
     403                 :          0 :     if ( feedback && feedback->isCanceled() )
     404                 :            :     {
     405                 :          0 :       canceled = true;
     406                 :          0 :       if ( errorMessage )
     407                 :            :       {
     408                 :          0 :         *errorMessage += '\n' + QObject::tr( "Import was canceled at %1 of %2" ).arg( n ).arg( approxTotal );
     409                 :          0 :       }
     410                 :          0 :       break;
     411                 :            :     }
     412                 :            : 
     413                 :          0 :     if ( writer->errorCount() > 1000 )
     414                 :            :     {
     415                 :          0 :       if ( errorMessage )
     416                 :            :       {
     417                 :          0 :         *errorMessage += '\n' + QObject::tr( "Stopping after %1 errors" ).arg( writer->errorCount() );
     418                 :          0 :       }
     419                 :          0 :       break;
     420                 :            :     }
     421                 :            : 
     422                 :          0 :     if ( shallTransform )
     423                 :            :     {
     424                 :            :       try
     425                 :            :       {
     426                 :          0 :         if ( fet.hasGeometry() )
     427                 :            :         {
     428                 :          0 :           QgsGeometry g = fet.geometry();
     429                 :          0 :           g.transform( ct );
     430                 :          0 :           fet.setGeometry( g );
     431                 :          0 :         }
     432                 :          0 :       }
     433                 :            :       catch ( QgsCsException &e )
     434                 :            :       {
     435                 :          0 :         delete writer;
     436                 :            : 
     437                 :          0 :         QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
     438                 :          0 :                       .arg( fet.id() ).arg( e.what() );
     439                 :          0 :         QgsMessageLog::logMessage( msg, QObject::tr( "Vector import" ) );
     440                 :          0 :         if ( errorMessage )
     441                 :          0 :           *errorMessage += '\n' + msg;
     442                 :            : 
     443                 :          0 :         return ErrProjection;
     444                 :          0 :       }
     445                 :          0 :     }
     446                 :            : 
     447                 :            :     // Handles conversion to single-part
     448                 :          0 :     if ( convertGeometryToSinglePart && fet.geometry().isMultipart() )
     449                 :            :     {
     450                 :          0 :       QgsGeometry singlePartGeometry { fet.geometry() };
     451                 :            :       // We want a failure if the geometry cannot be converted to single-part without data loss!
     452                 :            :       // check if there are more than one part
     453                 :          0 :       const QgsGeometryCollection *c = qgsgeometry_cast<const QgsGeometryCollection *>( singlePartGeometry.constGet() );
     454                 :          0 :       if ( ( c && c->partCount() > 1 ) || ! singlePartGeometry.convertToSingleType() )
     455                 :            :       {
     456                 :          0 :         delete writer;
     457                 :          0 :         QString msg = QObject::tr( "Failed to transform a feature with ID '%1' to single part. Writing stopped." )
     458                 :          0 :                       .arg( fet.id() );
     459                 :          0 :         QgsMessageLog::logMessage( msg, QObject::tr( "Vector import" ) );
     460                 :          0 :         if ( errorMessage )
     461                 :          0 :           *errorMessage += '\n' + msg;
     462                 :          0 :         return ErrFeatureWriteFailed;
     463                 :          0 :       }
     464                 :          0 :       fet.setGeometry( singlePartGeometry );
     465                 :          0 :     }
     466                 :            : 
     467                 :          0 :     if ( !writer->addFeature( fet ) )
     468                 :            :     {
     469                 :          0 :       if ( writer->errorCode() && errorMessage )
     470                 :            :       {
     471                 :          0 :         *errorMessage += '\n' + writer->errorMessage();
     472                 :          0 :       }
     473                 :          0 :     }
     474                 :          0 :     n++;
     475                 :            : 
     476                 :          0 :     if ( feedback )
     477                 :            :     {
     478                 :          0 :       feedback->setProgress( 100.0 * static_cast< double >( n ) / approxTotal );
     479                 :          0 :     }
     480                 :            : 
     481                 :            :   }
     482                 :            : 
     483                 :            :   // flush the buffer to be sure that all features are written
     484                 :          0 :   if ( !writer->flushBuffer() )
     485                 :            :   {
     486                 :          0 :     if ( writer->errorCode() && errorMessage )
     487                 :            :     {
     488                 :          0 :       *errorMessage += '\n' + writer->errorMessage();
     489                 :          0 :     }
     490                 :          0 :   }
     491                 :          0 :   int errors = writer->errorCount();
     492                 :            : 
     493                 :          0 :   if ( writer->mCreateSpatialIndex && !writer->createSpatialIndex() )
     494                 :            :   {
     495                 :          0 :     if ( writer->errorCode() && errorMessage )
     496                 :            :     {
     497                 :          0 :       *errorMessage += '\n' + writer->errorMessage();
     498                 :          0 :     }
     499                 :          0 :   }
     500                 :            : 
     501                 :          0 :   delete writer;
     502                 :            : 
     503                 :          0 :   if ( errorMessage )
     504                 :            :   {
     505                 :          0 :     if ( errors > 0 )
     506                 :            :     {
     507                 :          0 :       *errorMessage += '\n' + QObject::tr( "Only %1 of %2 features written." ).arg( n - errors ).arg( n );
     508                 :          0 :     }
     509                 :            :     else
     510                 :            :     {
     511                 :          0 :       errorMessage->clear();
     512                 :            :     }
     513                 :          0 :   }
     514                 :            : 
     515                 :          0 :   if ( canceled )
     516                 :          0 :     return ErrUserCanceled;
     517                 :          0 :   else if ( errors > 0 )
     518                 :          0 :     return ErrFeatureWriteFailed;
     519                 :            : 
     520                 :          0 :   return NoError;
     521                 :          0 : }
     522                 :            : 
     523                 :            : 
     524                 :            : //
     525                 :            : // QgsVectorLayerExporterTask
     526                 :            : //
     527                 :            : 
     528                 :          0 : QgsVectorLayerExporterTask::QgsVectorLayerExporterTask( QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, const QMap<QString, QVariant> &options, bool ownsLayer )
     529                 :          0 :   : QgsTask( tr( "Exporting %1" ).arg( layer->name() ), QgsTask::CanCancel )
     530                 :          0 :   , mLayer( layer )
     531                 :          0 :   , mOwnsLayer( ownsLayer )
     532                 :          0 :   , mDestUri( uri )
     533                 :          0 :   , mDestProviderKey( providerKey )
     534                 :          0 :   , mDestCrs( destinationCrs )
     535                 :          0 :   , mOptions( options )
     536                 :          0 :   , mOwnedFeedback( new QgsFeedback() )
     537                 :          0 : {
     538                 :          0 :   if ( mLayer )
     539                 :          0 :     setDependentLayers( QList< QgsMapLayer * >() << mLayer );
     540                 :          0 : }
     541                 :            : 
     542                 :          0 : QgsVectorLayerExporterTask *QgsVectorLayerExporterTask::withLayerOwnership( QgsVectorLayer *layer, const QString &uri, const QString &providerKey, const QgsCoordinateReferenceSystem &destinationCrs, const QMap<QString, QVariant> &options )
     543                 :            : {
     544                 :          0 :   std::unique_ptr< QgsVectorLayerExporterTask > newTask( new QgsVectorLayerExporterTask( layer, uri, providerKey, destinationCrs, options ) );
     545                 :          0 :   newTask->mOwnsLayer = true;
     546                 :          0 :   return newTask.release();
     547                 :          0 : }
     548                 :            : 
     549                 :          0 : void QgsVectorLayerExporterTask::cancel()
     550                 :            : {
     551                 :          0 :   mOwnedFeedback->cancel();
     552                 :          0 :   QgsTask::cancel();
     553                 :          0 : }
     554                 :            : 
     555                 :          0 : bool QgsVectorLayerExporterTask::run()
     556                 :            : {
     557                 :          0 :   if ( !mLayer )
     558                 :          0 :     return false;
     559                 :            : 
     560                 :          0 :   connect( mOwnedFeedback.get(), &QgsFeedback::progressChanged, this, &QgsVectorLayerExporterTask::setProgress );
     561                 :            : 
     562                 :            : 
     563                 :          0 :   mError = QgsVectorLayerExporter::exportLayer(
     564                 :          0 :              mLayer.data(), mDestUri, mDestProviderKey, mDestCrs, false, &mErrorMessage,
     565                 :          0 :              mOptions, mOwnedFeedback.get() );
     566                 :            : 
     567                 :          0 :   return mError == QgsVectorLayerExporter::NoError;
     568                 :          0 : }
     569                 :            : 
     570                 :          0 : void QgsVectorLayerExporterTask::finished( bool result )
     571                 :            : {
     572                 :            :   // QgsMapLayer has QTimer member, which must not be destroyed from another thread
     573                 :          0 :   if ( mOwnsLayer )
     574                 :          0 :     delete mLayer;
     575                 :            : 
     576                 :          0 :   if ( result )
     577                 :          0 :     emit exportComplete();
     578                 :            :   else
     579                 :          0 :     emit errorOccurred( mError, mErrorMessage );
     580                 :          0 : }

Generated by: LCOV version 1.14