QGIS API Documentation  master-6164ace
src/core/qgsvectorlayerimport.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsvectorlayerimport.cpp
00003                           vector layer importer
00004                              -------------------
00005     begin                : Thu Aug 25 2011
00006     copyright            : (C) 2011 by Giuseppe Sucameli
00007     email                : brush.tyler at gmail.com
00008  ***************************************************************************/
00009 
00010 /***************************************************************************
00011  *                                                                         *
00012  *   This program is free software; you can redistribute it and/or modify  *
00013  *   it under the terms of the GNU General Public License as published by  *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 
00019 #include "qgsfield.h"
00020 #include "qgsfeature.h"
00021 #include "qgsgeometry.h"
00022 #include "qgslogger.h"
00023 #include "qgsmessagelog.h"
00024 #include "qgscoordinatereferencesystem.h"
00025 #include "qgsvectorlayerimport.h"
00026 #include "qgsproviderregistry.h"
00027 #include "qgsdatasourceuri.h"
00028 
00029 #include <QProgressDialog>
00030 
00031 #define FEATURE_BUFFER_SIZE 200
00032 
00033 typedef QgsVectorLayerImport::ImportError createEmptyLayer_t(
00034   const QString &uri,
00035   const QgsFields &fields,
00036   QGis::WkbType geometryType,
00037   const QgsCoordinateReferenceSystem *destCRS,
00038   bool overwrite,
00039   QMap<int, int> *oldToNewAttrIdx,
00040   QString *errorMessage,
00041   const QMap<QString, QVariant> *options
00042 );
00043 
00044 
00045 QgsVectorLayerImport::QgsVectorLayerImport( const QString &uri,
00046     const QString &providerKey,
00047     const QgsFields& fields,
00048     QGis::WkbType geometryType,
00049     const QgsCoordinateReferenceSystem* crs,
00050     bool overwrite,
00051     const QMap<QString, QVariant> *options,
00052     QProgressDialog *progress )
00053     : mErrorCount( 0 )
00054     , mProgress( progress )
00055 {
00056   mProvider = NULL;
00057 
00058   QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
00059 
00060   QLibrary *myLib = pReg->providerLibrary( providerKey );
00061   if ( !myLib )
00062   {
00063     mError = ErrInvalidProvider;
00064     mErrorMessage = QObject::tr( "Unable to load %1 provider" ).arg( providerKey );
00065     return;
00066   }
00067 
00068   createEmptyLayer_t * pCreateEmpty = ( createEmptyLayer_t * ) cast_to_fptr( myLib->resolve( "createEmptyLayer" ) );
00069   if ( !pCreateEmpty )
00070   {
00071     delete myLib;
00072     mError = ErrProviderUnsupportedFeature;
00073     mErrorMessage = QObject::tr( "Provider %1 has no %2 method" ).arg( providerKey ).arg( "createEmptyLayer" );
00074     return;
00075   }
00076 
00077   delete myLib;
00078 
00079   // create an empty layer
00080   QString errMsg;
00081   mError = pCreateEmpty( uri, fields, geometryType, crs, overwrite, &mOldToNewAttrIdx, &errMsg, options );
00082   if ( hasError() )
00083   {
00084     mErrorMessage = errMsg;
00085     return;
00086   }
00087 
00088   mAttributeCount = -1;
00089 
00090   foreach ( int idx, mOldToNewAttrIdx.values() )
00091   {
00092     if ( idx > mAttributeCount )
00093       mAttributeCount = idx;
00094   }
00095 
00096   mAttributeCount++;
00097 
00098   QgsDebugMsg( "Created empty layer" );
00099 
00100   QgsVectorDataProvider *vectorProvider = ( QgsVectorDataProvider* ) pReg->provider( providerKey, uri );
00101   if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
00102   {
00103     mError = ErrInvalidLayer;
00104     mErrorMessage = QObject::tr( "Loading of layer failed" );
00105 
00106     if ( vectorProvider )
00107       delete vectorProvider;
00108 
00109     return;
00110   }
00111 
00112   mProvider = vectorProvider;
00113   mError = NoError;
00114 }
00115 
00116 QgsVectorLayerImport::~QgsVectorLayerImport()
00117 {
00118   flushBuffer();
00119 
00120   if ( mProvider )
00121     delete mProvider;
00122 }
00123 
00124 QgsVectorLayerImport::ImportError QgsVectorLayerImport::hasError()
00125 {
00126   return mError;
00127 }
00128 
00129 QString QgsVectorLayerImport::errorMessage()
00130 {
00131   return mErrorMessage;
00132 }
00133 
00134 bool QgsVectorLayerImport::addFeature( QgsFeature& feat )
00135 {
00136   const QgsAttributes &attrs = feat.attributes();
00137 
00138   QgsFeature newFeat;
00139   if ( feat.geometry() )
00140     newFeat.setGeometry( *feat.geometry() );
00141 
00142   newFeat.initAttributes( mAttributeCount );
00143 
00144   for ( int i = 0; i < attrs.count(); ++i )
00145   {
00146     // add only mapped attributes (un-mapped ones will not be present in the
00147     // destination layer)
00148     int dstIdx = mOldToNewAttrIdx.value( i, -1 );
00149     if ( dstIdx < 0 )
00150       continue;
00151 
00152     QgsDebugMsgLevel( QString( "moving field from pos %1 to %2" ).arg( i ).arg( dstIdx ), 3 );
00153     newFeat.setAttribute( dstIdx, attrs[i] );
00154   }
00155 
00156   mFeatureBuffer.append( newFeat );
00157 
00158   if ( mFeatureBuffer.count() >= FEATURE_BUFFER_SIZE )
00159   {
00160     return flushBuffer();
00161   }
00162 
00163   return true;
00164 }
00165 
00166 bool QgsVectorLayerImport::flushBuffer()
00167 {
00168   if ( mFeatureBuffer.count() <= 0 )
00169     return true;
00170 
00171   if ( !mProvider->addFeatures( mFeatureBuffer ) )
00172   {
00173     QStringList errors = mProvider->errors();
00174     mProvider->clearErrors();
00175 
00176     mErrorMessage = QObject::tr( "Creation error for features from #%1 to #%2. Provider errors was: \n%3" )
00177                     .arg( mFeatureBuffer.first().id() )
00178                     .arg( mFeatureBuffer.last().id() )
00179                     .arg( errors.join( "\n" ) );
00180 
00181     mError = ErrFeatureWriteFailed;
00182     mErrorCount += mFeatureBuffer.count();
00183 
00184     mFeatureBuffer.clear();
00185     QgsDebugMsg( mErrorMessage );
00186     return false;
00187   }
00188 
00189   mFeatureBuffer.clear();
00190   return true;
00191 }
00192 
00193 bool QgsVectorLayerImport::createSpatialIndex()
00194 {
00195   if ( mProvider && ( mProvider->capabilities() & QgsVectorDataProvider::CreateSpatialIndex ) != 0 )
00196   {
00197     return mProvider->createSpatialIndex();
00198   }
00199   else
00200   {
00201     return true;
00202   }
00203 }
00204 
00205 QgsVectorLayerImport::ImportError
00206 QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
00207                                    const QString& uri,
00208                                    const QString& providerKey,
00209                                    const QgsCoordinateReferenceSystem *destCRS,
00210                                    bool onlySelected,
00211                                    QString *errorMessage,
00212                                    bool skipAttributeCreation,
00213                                    QMap<QString, QVariant> *options,
00214                                    QProgressDialog *progress )
00215 {
00216   const QgsCoordinateReferenceSystem* outputCRS;
00217   QgsCoordinateTransform* ct = 0;
00218   int shallTransform = false;
00219 
00220   if ( layer == NULL )
00221   {
00222     return ErrInvalidLayer;
00223   }
00224 
00225   if ( destCRS && destCRS->isValid() )
00226   {
00227     // This means we should transform
00228     outputCRS = destCRS;
00229     shallTransform = true;
00230   }
00231   else
00232   {
00233     // This means we shouldn't transform, use source CRS as output (if defined)
00234     outputCRS = &layer->crs();
00235   }
00236 
00237 
00238   bool overwrite = false;
00239   bool forceSinglePartGeom = false;
00240   if ( options )
00241   {
00242     overwrite = options->take( "overwrite" ).toBool();
00243     forceSinglePartGeom = options->take( "forceSinglePartGeometryType" ).toBool();
00244   }
00245 
00246   QgsFields fields = skipAttributeCreation ? QgsFields() : layer->pendingFields();
00247   QGis::WkbType wkbType = layer->wkbType();
00248 
00249   // Special handling for Shapefiles
00250   if ( layer->providerType() == "ogr" && layer->storageType() == "ESRI Shapefile" )
00251   {
00252     // convert field names to lowercase
00253     for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
00254     {
00255       fields[fldIdx].setName( fields[fldIdx].name().toLower() );
00256     }
00257 
00258     if ( !forceSinglePartGeom )
00259     {
00260       // convert wkbtype to multipart (see #5547)
00261       switch ( wkbType )
00262       {
00263         case QGis::WKBPoint:
00264           wkbType = QGis::WKBMultiPoint;
00265           break;
00266         case QGis::WKBLineString:
00267           wkbType = QGis::WKBMultiLineString;
00268           break;
00269         case QGis::WKBPolygon:
00270           wkbType = QGis::WKBMultiPolygon;
00271           break;
00272         case QGis::WKBPoint25D:
00273           wkbType = QGis::WKBMultiPoint25D;
00274           break;
00275         case QGis::WKBLineString25D:
00276           wkbType = QGis::WKBMultiLineString25D;
00277           break;
00278         case QGis::WKBPolygon25D:
00279           wkbType = QGis::WKBMultiPolygon25D;
00280           break;
00281         default:
00282           break;
00283       }
00284     }
00285   }
00286 
00287   QgsVectorLayerImport * writer =
00288     new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options, progress );
00289 
00290   // check whether file creation was successful
00291   ImportError err = writer->hasError();
00292   if ( err != NoError )
00293   {
00294     if ( errorMessage )
00295       *errorMessage = writer->errorMessage();
00296     delete writer;
00297     return err;
00298   }
00299 
00300   if ( errorMessage )
00301   {
00302     errorMessage->clear();
00303   }
00304 
00305   QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
00306   QgsFeature fet;
00307 
00308   QgsFeatureRequest req;
00309   if ( wkbType == QGis::WKBNoGeometry )
00310     req.setFlags( QgsFeatureRequest::NoGeometry );
00311   if ( skipAttributeCreation )
00312     req.setSubsetOfAttributes( QgsAttributeList() );
00313 
00314   QgsFeatureIterator fit = layer->getFeatures( req );
00315 
00316   const QgsFeatureIds& ids = layer->selectedFeaturesIds();
00317 
00318   // Create our transform
00319   if ( destCRS )
00320   {
00321     ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
00322   }
00323 
00324   // Check for failure
00325   if ( ct == NULL )
00326   {
00327     shallTransform = false;
00328   }
00329 
00330   int n = 0;
00331 
00332   if ( errorMessage )
00333   {
00334     *errorMessage = QObject::tr( "Feature write errors:" );
00335   }
00336 
00337   if ( progress )
00338   {
00339     progress->setRange( 0, layer->featureCount() );
00340   }
00341 
00342   // write all features
00343   while ( fit.nextFeature( fet ) )
00344   {
00345     if ( progress && progress->wasCanceled() )
00346     {
00347       if ( errorMessage )
00348       {
00349         *errorMessage += "\n" + QObject::tr( "Import was canceled at %1 of %2" ).arg( progress->value() ).arg( progress->maximum() );
00350       }
00351       break;
00352     }
00353 
00354     if ( writer->errorCount() > 1000 )
00355     {
00356       if ( errorMessage )
00357       {
00358         *errorMessage += "\n" + QObject::tr( "Stopping after %1 errors" ).arg( writer->errorCount() );
00359       }
00360       break;
00361     }
00362 
00363     if ( onlySelected && !ids.contains( fet.id() ) )
00364       continue;
00365 
00366     if ( shallTransform )
00367     {
00368       try
00369       {
00370         if ( fet.geometry() )
00371         {
00372           fet.geometry()->transform( *ct );
00373         }
00374       }
00375       catch ( QgsCsException &e )
00376       {
00377         delete ct;
00378         delete writer;
00379 
00380         QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
00381                       .arg( fet.id() ).arg( e.what() );
00382         QgsMessageLog::logMessage( msg, QObject::tr( "Vector import" ) );
00383         if ( errorMessage )
00384           *errorMessage += "\n" + msg;
00385 
00386         return ErrProjection;
00387       }
00388     }
00389     if ( skipAttributeCreation )
00390     {
00391       fet.initAttributes( 0 );
00392     }
00393     if ( !writer->addFeature( fet ) )
00394     {
00395       if ( writer->hasError() && errorMessage )
00396       {
00397         *errorMessage += "\n" + writer->errorMessage();
00398       }
00399     }
00400     n++;
00401 
00402     if ( progress )
00403     {
00404       progress->setValue( n );
00405     }
00406   }
00407 
00408   // flush the buffer to be sure that all features are written
00409   if ( !writer->flushBuffer() )
00410   {
00411     if ( writer->hasError() && errorMessage )
00412     {
00413       *errorMessage += "\n" + writer->errorMessage();
00414     }
00415   }
00416   int errors = writer->errorCount();
00417 
00418   if ( !writer->createSpatialIndex() )
00419   {
00420     if ( writer->hasError() && errorMessage )
00421     {
00422       *errorMessage += "\n" + writer->errorMessage();
00423     }
00424   }
00425 
00426   delete writer;
00427 
00428   if ( shallTransform )
00429   {
00430     delete ct;
00431   }
00432 
00433   if ( errorMessage )
00434   {
00435     if ( errors > 0 )
00436     {
00437       *errorMessage += "\n" + QObject::tr( "Only %1 of %2 features written." ).arg( n - errors ).arg( n );
00438     }
00439     else
00440     {
00441       errorMessage->clear();
00442     }
00443   }
00444 
00445   return errors == 0 ? NoError : ErrFeatureWriteFailed;
00446 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines