|
QGIS API Documentation
master-6227475
|
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 }