Quantum GIS API Documentation
1.7.4
|
00001 /*************************************************************************** 00002 qgsvectorfilewriter.cpp 00003 generic vector file writer 00004 ------------------- 00005 begin : Sat Jun 16 2004 00006 copyright : (C) 2004 by Tim Sutton 00007 email : tim at linfiniti.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 /* $Id$ */ 00019 00020 #include "qgsapplication.h" 00021 #include "qgsfield.h" 00022 #include "qgsfeature.h" 00023 #include "qgsgeometry.h" 00024 #include "qgslogger.h" 00025 #include "qgscoordinatereferencesystem.h" 00026 #include "qgsvectorfilewriter.h" 00027 00028 #include <QFile> 00029 #include <QSettings> 00030 #include <QFileInfo> 00031 #include <QDir> 00032 #include <QTextCodec> 00033 #include <QTextStream> 00034 #include <QSet> 00035 #include <QMetaType> 00036 00037 #include <cassert> 00038 #include <cstdlib> // size_t 00039 00040 #include <ogr_api.h> 00041 #include <ogr_srs_api.h> 00042 #include <cpl_error.h> 00043 #include <cpl_conv.h> 00044 00045 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 00046 #define TO8(x) (x).toUtf8().constData() 00047 #define TO8F(x) (x).toUtf8().constData() 00048 #else 00049 #define TO8(x) (x).toLocal8Bit().constData() 00050 #define TO8F(x) QFile::encodeName( x ).constData() 00051 #endif 00052 00053 00054 QgsVectorFileWriter::QgsVectorFileWriter( 00055 const QString &theVectorFileName, 00056 const QString &theFileEncoding, 00057 const QgsFieldMap& fields, 00058 QGis::WkbType geometryType, 00059 const QgsCoordinateReferenceSystem* srs, 00060 const QString& driverName, 00061 const QStringList &datasourceOptions, 00062 const QStringList &layerOptions 00063 ) 00064 : mDS( NULL ) 00065 , mLayer( NULL ) 00066 , mGeom( NULL ) 00067 , mError( NoError ) 00068 { 00069 QString vectorFileName = theVectorFileName; 00070 QString fileEncoding = theFileEncoding; 00071 00072 // find driver in OGR 00073 OGRSFDriverH poDriver; 00074 QgsApplication::registerOgrDrivers(); 00075 poDriver = OGRGetDriverByName( driverName.toLocal8Bit().data() ); 00076 00077 if ( poDriver == NULL ) 00078 { 00079 mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" ) 00080 .arg( driverName ) 00081 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00082 mError = ErrDriverNotFound; 00083 return; 00084 } 00085 00086 if ( driverName == "ESRI Shapefile" ) 00087 { 00088 if ( !vectorFileName.endsWith( ".shp", Qt::CaseInsensitive ) && 00089 !vectorFileName.endsWith( ".dbf", Qt::CaseInsensitive ) ) 00090 { 00091 vectorFileName += ".shp"; 00092 } 00093 00094 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700 00095 // check for unique fieldnames 00096 QSet<QString> fieldNames; 00097 QgsFieldMap::const_iterator fldIt; 00098 for ( fldIt = fields.begin(); fldIt != fields.end(); ++fldIt ) 00099 { 00100 QString name = fldIt.value().name().left( 10 ); 00101 if ( fieldNames.contains( name ) ) 00102 { 00103 mErrorMessage = QObject::tr( "trimming attribute name '%1' to ten significant characters produces duplicate column name." ) 00104 .arg( fldIt.value().name() ); 00105 mError = ErrAttributeCreationFailed; 00106 return; 00107 } 00108 fieldNames << name; 00109 } 00110 #endif 00111 00112 deleteShapeFile( vectorFileName ); 00113 } 00114 else if ( driverName == "KML" ) 00115 { 00116 if ( !vectorFileName.endsWith( ".kml", Qt::CaseInsensitive ) ) 00117 { 00118 vectorFileName += ".kml"; 00119 } 00120 00121 if ( fileEncoding.compare( "UTF-8", Qt::CaseInsensitive ) != 0 ) 00122 { 00123 QgsDebugMsg( "forced UTF-8 encoding for KML" ); 00124 fileEncoding = "UTF-8"; 00125 } 00126 00127 QFile::remove( vectorFileName ); 00128 } 00129 else 00130 { 00131 QString longName; 00132 QString trLongName; 00133 QString glob; 00134 QString exts; 00135 if ( QgsVectorFileWriter::driverMetadata( driverName, longName, trLongName, glob, exts ) ) 00136 { 00137 QStringList allExts = exts.split( " ", QString::SkipEmptyParts ); 00138 bool found = false; 00139 foreach( QString ext, allExts ) 00140 { 00141 if ( vectorFileName.endsWith( "." + ext, Qt::CaseInsensitive ) ) 00142 { 00143 found = true; 00144 break; 00145 } 00146 } 00147 00148 if ( !found ) 00149 { 00150 vectorFileName += "." + allExts[0]; 00151 } 00152 } 00153 00154 QFile::remove( vectorFileName ); 00155 } 00156 00157 char **options = NULL; 00158 if ( !datasourceOptions.isEmpty() ) 00159 { 00160 options = new char *[ datasourceOptions.size()+1 ]; 00161 for ( int i = 0; i < datasourceOptions.size(); i++ ) 00162 { 00163 options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().data() ); 00164 } 00165 options[ datasourceOptions.size()] = NULL; 00166 } 00167 00168 // create the data source 00169 mDS = OGR_Dr_CreateDataSource( poDriver, TO8( vectorFileName ), options ); 00170 00171 if ( options ) 00172 { 00173 for ( int i = 0; i < datasourceOptions.size(); i++ ) 00174 CPLFree( options[i] ); 00175 delete [] options; 00176 options = NULL; 00177 } 00178 00179 if ( mDS == NULL ) 00180 { 00181 mError = ErrCreateDataSource; 00182 mErrorMessage = QObject::tr( "creation of data source failed (OGR error:%1)" ) 00183 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00184 return; 00185 } 00186 00187 QgsDebugMsg( "Created data source" ); 00188 00189 // use appropriate codec 00190 mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().data() ); 00191 if ( !mCodec ) 00192 { 00193 QSettings settings; 00194 QString enc = settings.value( "/UI/encoding", QString( "System" ) ).toString(); 00195 QgsDebugMsg( "error finding QTextCodec for " + fileEncoding ); 00196 mCodec = QTextCodec::codecForName( enc.toLocal8Bit().data() ); 00197 if ( !mCodec ) 00198 { 00199 QgsDebugMsg( "error finding QTextCodec for " + enc ); 00200 mCodec = QTextCodec::codecForLocale(); 00201 } 00202 } 00203 00204 // consider spatial reference system of the layer 00205 OGRSpatialReferenceH ogrRef = NULL; 00206 if ( srs ) 00207 { 00208 QString srsWkt = srs->toWkt(); 00209 QgsDebugMsg( "WKT to save as is " + srsWkt ); 00210 ogrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() ); 00211 } 00212 00213 // datasource created, now create the output layer 00214 QString layerName = QFileInfo( vectorFileName ).baseName(); 00215 OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType ); 00216 00217 if ( !layerOptions.isEmpty() ) 00218 { 00219 options = new char *[ layerOptions.size()+1 ]; 00220 for ( int i = 0; i < layerOptions.size(); i++ ) 00221 { 00222 options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().data() ); 00223 } 00224 options[ layerOptions.size()] = NULL; 00225 } 00226 00227 mLayer = OGR_DS_CreateLayer( mDS, TO8F( layerName ), ogrRef, wkbType, options ); 00228 00229 if ( options ) 00230 { 00231 for ( int i = 0; i < layerOptions.size(); i++ ) 00232 CPLFree( options[i] ); 00233 delete [] options; 00234 options = NULL; 00235 } 00236 00237 if ( srs ) 00238 { 00239 if ( driverName == "ESRI Shapefile" ) 00240 { 00241 QString layerName = vectorFileName.left( vectorFileName.indexOf( ".shp", Qt::CaseInsensitive ) ); 00242 QFile prjFile( layerName + ".qpj" ); 00243 if ( prjFile.open( QIODevice::WriteOnly ) ) 00244 { 00245 QTextStream prjStream( &prjFile ); 00246 prjStream << srs->toWkt().toLocal8Bit().data() << endl; 00247 prjFile.close(); 00248 } 00249 else 00250 { 00251 QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" ); 00252 } 00253 } 00254 00255 OSRDestroySpatialReference( ogrRef ); 00256 } 00257 00258 if ( mLayer == NULL ) 00259 { 00260 mErrorMessage = QObject::tr( "creation of layer failed (OGR error:%1)" ) 00261 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00262 mError = ErrCreateLayer; 00263 return; 00264 } 00265 00266 OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer ); 00267 00268 QgsDebugMsg( "created layer" ); 00269 00270 // create the fields 00271 QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" ); 00272 00273 mFields = fields; 00274 mAttrIdxToOgrIdx.clear(); 00275 00276 QgsFieldMap::const_iterator fldIt; 00277 for ( fldIt = fields.begin(); fldIt != fields.end(); ++fldIt ) 00278 { 00279 const QgsField& attrField = fldIt.value(); 00280 00281 OGRFieldType ogrType = OFTString; //default to string 00282 int ogrWidth = fldIt->length(); 00283 int ogrPrecision = fldIt->precision(); 00284 switch ( attrField.type() ) 00285 { 00286 case QVariant::LongLong: 00287 ogrType = OFTString; 00288 ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21; 00289 ogrPrecision = -1; 00290 break; 00291 00292 case QVariant::String: 00293 ogrType = OFTString; 00294 if ( ogrWidth < 0 || ogrWidth > 255 ) 00295 ogrWidth = 255; 00296 break; 00297 00298 case QVariant::Int: 00299 ogrType = OFTInteger; 00300 ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10; 00301 ogrPrecision = 0; 00302 break; 00303 00304 case QVariant::Double: 00305 ogrType = OFTReal; 00306 break; 00307 00308 default: 00309 //assert(0 && "invalid variant type!"); 00310 mErrorMessage = QObject::tr( "unsupported type for field %1" ) 00311 .arg( attrField.name() ); 00312 mError = ErrAttributeTypeUnsupported; 00313 return; 00314 } 00315 00316 // create field definition 00317 OGRFieldDefnH fld = OGR_Fld_Create( mCodec->fromUnicode( attrField.name() ), ogrType ); 00318 if ( ogrWidth > 0 ) 00319 { 00320 OGR_Fld_SetWidth( fld, ogrWidth ); 00321 } 00322 00323 if ( ogrPrecision >= 0 ) 00324 { 00325 OGR_Fld_SetPrecision( fld, ogrPrecision ); 00326 } 00327 00328 // create the field 00329 QgsDebugMsg( "creating field " + attrField.name() + 00330 " type " + QString( QVariant::typeToName( attrField.type() ) ) + 00331 " width " + QString::number( ogrWidth ) + 00332 " precision " + QString::number( ogrPrecision ) ); 00333 if ( OGR_L_CreateField( mLayer, fld, true ) != OGRERR_NONE ) 00334 { 00335 QgsDebugMsg( "error creating field " + attrField.name() ); 00336 mErrorMessage = QObject::tr( "creation of field %1 failed (OGR error: %2)" ) 00337 .arg( attrField.name() ) 00338 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00339 mError = ErrAttributeCreationFailed; 00340 return; 00341 } 00342 00343 int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) ); 00344 if ( ogrIdx < 0 ) 00345 { 00346 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700 00347 // if we didn't find our new column, assume it's name was truncated and 00348 // it was the last one added (like for shape files) 00349 int fieldCount = OGR_FD_GetFieldCount( defn ); 00350 00351 OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 ); 00352 if ( fdefn ) 00353 { 00354 const char *fieldName = OGR_Fld_GetNameRef( fdefn ); 00355 00356 if ( attrField.name().left( strlen( fieldName ) ) == fieldName ) 00357 { 00358 ogrIdx = fieldCount - 1; 00359 } 00360 } 00361 #else 00362 // GDAL 1.7 not just truncates, but launders more aggressivly. 00363 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1; 00364 #endif 00365 00366 if ( ogrIdx < 0 ) 00367 { 00368 QgsDebugMsg( "error creating field " + attrField.name() ); 00369 mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" ) 00370 .arg( attrField.name() ) 00371 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00372 mError = ErrAttributeCreationFailed; 00373 return; 00374 } 00375 } 00376 00377 mAttrIdxToOgrIdx.insert( fldIt.key(), ogrIdx ); 00378 } 00379 00380 QgsDebugMsg( "Done creating fields" ); 00381 00382 mWkbType = geometryType; 00383 if ( mWkbType != QGis::WKBNoGeometry ) 00384 { 00385 // create geometry which will be used for import 00386 mGeom = createEmptyGeometry( mWkbType ); 00387 } 00388 } 00389 00390 OGRGeometryH QgsVectorFileWriter::createEmptyGeometry( QGis::WkbType wkbType ) 00391 { 00392 return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType ); 00393 } 00394 00395 00396 QgsVectorFileWriter::WriterError QgsVectorFileWriter::hasError() 00397 { 00398 return mError; 00399 } 00400 00401 QString QgsVectorFileWriter::errorMessage() 00402 { 00403 return mErrorMessage; 00404 } 00405 00406 bool QgsVectorFileWriter::addFeature( QgsFeature& feature ) 00407 { 00408 QgsAttributeMap::const_iterator it; 00409 00410 // create the feature 00411 OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) ); 00412 00413 OGRErr err = OGR_F_SetFID( poFeature, feature.id() ); 00414 if ( err != OGRERR_NONE ) 00415 { 00416 QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" ) 00417 .arg( feature.id() ) 00418 .arg( err ).arg( CPLGetLastErrorMsg() ) 00419 ); 00420 } 00421 00422 // attribute handling 00423 QgsFieldMap::const_iterator fldIt; 00424 for ( fldIt = mFields.begin(); fldIt != mFields.end(); ++fldIt ) 00425 { 00426 if ( !feature.attributeMap().contains( fldIt.key() ) ) 00427 { 00428 QgsDebugMsg( QString( "no attribute for field %1" ).arg( fldIt.key() ) ); 00429 continue; 00430 } 00431 00432 if ( !mAttrIdxToOgrIdx.contains( fldIt.key() ) ) 00433 { 00434 QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIt.key() ) ); 00435 continue; 00436 } 00437 00438 const QVariant& attrValue = feature.attributeMap()[ fldIt.key()]; 00439 int ogrField = mAttrIdxToOgrIdx[ fldIt.key()]; 00440 00441 switch ( attrValue.type() ) 00442 { 00443 case QVariant::Int: 00444 OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() ); 00445 break; 00446 case QVariant::Double: 00447 OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() ); 00448 break; 00449 case QVariant::LongLong: 00450 case QVariant::String: 00451 OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() ); 00452 break; 00453 case QVariant::Invalid: 00454 break; 00455 default: 00456 mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" ) 00457 .arg( fldIt.value().name() ) 00458 .arg( ogrField ) 00459 .arg( QMetaType::typeName( attrValue.type() ) ) 00460 .arg( attrValue.toString() ); 00461 QgsDebugMsg( mErrorMessage ); 00462 mError = ErrFeatureWriteFailed; 00463 return false; 00464 } 00465 } 00466 00467 if ( mWkbType != QGis::WKBNoGeometry ) 00468 { 00469 // build geometry from WKB 00470 QgsGeometry *geom = feature.geometry(); 00471 if ( geom && geom->wkbType() != mWkbType ) 00472 { 00473 // there's a problem when layer type is set as wkbtype Polygon 00474 // although there are also features of type MultiPolygon 00475 // (at least in OGR provider) 00476 // If the feature's wkbtype is different from the layer's wkbtype, 00477 // try to export it too. 00478 // 00479 // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive 00480 // i.e. Polygons can't be imported to OGRMultiPolygon 00481 00482 OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() ); 00483 00484 if ( !mGeom2 ) 00485 { 00486 QgsDebugMsg( QString( "Failed to create empty geometry for type %1 (OGR error: %2)" ).arg( geom->wkbType() ).arg( CPLGetLastErrorMsg() ) ); 00487 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00488 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00489 mError = ErrFeatureWriteFailed; 00490 OGR_F_Destroy( poFeature ); 00491 return false; 00492 } 00493 00494 OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() ); 00495 if ( err != OGRERR_NONE ) 00496 { 00497 QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) ); 00498 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00499 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00500 mError = ErrFeatureWriteFailed; 00501 OGR_F_Destroy( poFeature ); 00502 return false; 00503 } 00504 00505 // pass ownership to geometry 00506 OGR_F_SetGeometryDirectly( poFeature, mGeom2 ); 00507 } 00508 else if ( geom ) 00509 { 00510 OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() ); 00511 if ( err != OGRERR_NONE ) 00512 { 00513 QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) ); 00514 mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" ) 00515 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00516 mError = ErrFeatureWriteFailed; 00517 OGR_F_Destroy( poFeature ); 00518 return false; 00519 } 00520 00521 // set geometry (ownership is not passed to OGR) 00522 OGR_F_SetGeometry( poFeature, mGeom ); 00523 } 00524 } 00525 00526 // put the created feature to layer 00527 if ( OGR_L_CreateFeature( mLayer, poFeature ) != OGRERR_NONE ) 00528 { 00529 mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); 00530 mError = ErrFeatureWriteFailed; 00531 00532 QgsDebugMsg( mErrorMessage ); 00533 OGR_F_Destroy( poFeature ); 00534 return false; 00535 } 00536 00537 OGR_F_Destroy( poFeature ); 00538 00539 return true; 00540 } 00541 00542 QgsVectorFileWriter::~QgsVectorFileWriter() 00543 { 00544 if ( mGeom ) 00545 { 00546 OGR_G_DestroyGeometry( mGeom ); 00547 } 00548 00549 if ( mDS ) 00550 { 00551 OGR_DS_Destroy( mDS ); 00552 } 00553 } 00554 00555 00556 00557 00558 QgsVectorFileWriter::WriterError 00559 QgsVectorFileWriter::writeAsShapefile( QgsVectorLayer* layer, 00560 const QString& shapefileName, 00561 const QString& fileEncoding, 00562 const QgsCoordinateReferenceSystem* destCRS, 00563 bool onlySelected, 00564 QString *errorMessage, 00565 const QStringList &datasourceOptions, 00566 const QStringList &layerOptions ) 00567 { 00568 return writeAsVectorFormat( layer, shapefileName, fileEncoding, destCRS, "ESRI Shapefile", onlySelected, errorMessage, datasourceOptions, layerOptions ); 00569 } 00570 00571 QgsVectorFileWriter::WriterError 00572 QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer, 00573 const QString& fileName, 00574 const QString& fileEncoding, 00575 const QgsCoordinateReferenceSystem *destCRS, 00576 const QString& driverName, 00577 bool onlySelected, 00578 QString *errorMessage, 00579 const QStringList &datasourceOptions, 00580 const QStringList &layerOptions, 00581 bool skipAttributeCreation ) 00582 { 00583 const QgsCoordinateReferenceSystem* outputCRS; 00584 QgsCoordinateTransform* ct = 0; 00585 int shallTransform = false; 00586 00587 if ( destCRS && destCRS->isValid() ) 00588 { 00589 // This means we should transform 00590 outputCRS = destCRS; 00591 shallTransform = true; 00592 } 00593 else 00594 { 00595 // This means we shouldn't transform, use source CRS as output (if defined) 00596 outputCRS = &layer->crs(); 00597 } 00598 QgsVectorFileWriter* writer = 00599 new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFieldMap() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions ); 00600 00601 // check whether file creation was successful 00602 WriterError err = writer->hasError(); 00603 if ( err != NoError ) 00604 { 00605 if ( errorMessage ) 00606 *errorMessage = writer->errorMessage(); 00607 delete writer; 00608 return err; 00609 } 00610 00611 if ( errorMessage ) 00612 { 00613 errorMessage->clear(); 00614 } 00615 00616 QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList(); 00617 QgsFeature fet; 00618 00619 layer->select( allAttr, QgsRectangle(), layer->wkbType() != QGis::WKBNoGeometry ); 00620 00621 const QgsFeatureIds& ids = layer->selectedFeaturesIds(); 00622 00623 // Create our transform 00624 if ( destCRS ) 00625 { 00626 ct = new QgsCoordinateTransform( layer->crs(), *destCRS ); 00627 } 00628 00629 // Check for failure 00630 if ( ct == NULL ) 00631 { 00632 shallTransform = false; 00633 } 00634 00635 int n = 0, errors = 0; 00636 00637 // write all features 00638 while ( layer->nextFeature( fet ) ) 00639 { 00640 if ( onlySelected && !ids.contains( fet.id() ) ) 00641 continue; 00642 00643 if ( shallTransform ) 00644 { 00645 try 00646 { 00647 if ( fet.geometry() ) 00648 { 00649 fet.geometry()->transform( *ct ); 00650 } 00651 } 00652 catch ( QgsCsException &e ) 00653 { 00654 delete ct; 00655 delete writer; 00656 00657 QString msg = QObject::tr( "Failed to transform a point while drawing a feature of type '%1'. Writing stopped. (Exception: %2)" ) 00658 .arg( fet.typeName() ).arg( e.what() ); 00659 QgsLogger::warning( msg ); 00660 if ( errorMessage ) 00661 *errorMessage = msg; 00662 00663 return ErrProjection; 00664 } 00665 } 00666 if ( skipAttributeCreation ) 00667 { 00668 fet.clearAttributeMap(); 00669 } 00670 if ( !writer->addFeature( fet ) ) 00671 { 00672 WriterError err = writer->hasError(); 00673 if ( err != NoError && errorMessage ) 00674 { 00675 if ( errorMessage->isEmpty() ) 00676 { 00677 *errorMessage = QObject::tr( "Feature write errors:" ); 00678 } 00679 *errorMessage += "\n" + writer->errorMessage(); 00680 } 00681 errors++; 00682 00683 if ( errors > 1000 ) 00684 { 00685 if ( errorMessage ) 00686 { 00687 *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors ); 00688 } 00689 00690 n = -1; 00691 break; 00692 } 00693 } 00694 n++; 00695 } 00696 00697 delete writer; 00698 00699 if ( shallTransform ) 00700 { 00701 delete ct; 00702 } 00703 00704 if ( errors > 0 && errorMessage && n > 0 ) 00705 { 00706 *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n ); 00707 } 00708 00709 return errors == 0 ? NoError : ErrFeatureWriteFailed; 00710 } 00711 00712 00713 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName ) 00714 { 00715 QFileInfo fi( theFileName ); 00716 QDir dir = fi.dir(); 00717 00718 QStringList filter; 00719 const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" }; 00720 for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ ) 00721 { 00722 filter << fi.completeBaseName() + suffixes[i]; 00723 } 00724 00725 bool ok = true; 00726 foreach( QString file, dir.entryList( filter ) ) 00727 { 00728 if ( !QFile::remove( dir.canonicalPath() + "/" + file ) ) 00729 { 00730 QgsDebugMsg( "Removing file failed : " + file ); 00731 ok = false; 00732 } 00733 } 00734 00735 return ok; 00736 } 00737 00738 QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats() 00739 { 00740 QMap<QString, QString> resultMap; 00741 00742 QgsApplication::registerOgrDrivers(); 00743 int const drvCount = OGRGetDriverCount(); 00744 00745 for ( int i = 0; i < drvCount; ++i ) 00746 { 00747 OGRSFDriverH drv = OGRGetDriver( i ); 00748 if ( drv ) 00749 { 00750 QString drvName = OGR_Dr_GetName( drv ); 00751 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00752 { 00753 QString filterString = filterForDriver( drvName ); 00754 if ( filterString.isEmpty() ) 00755 continue; 00756 00757 resultMap.insert( filterString, drvName ); 00758 } 00759 } 00760 } 00761 00762 return resultMap; 00763 } 00764 00765 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList() 00766 { 00767 QMap<QString, QString> resultMap; 00768 00769 QgsApplication::registerOgrDrivers(); 00770 int const drvCount = OGRGetDriverCount(); 00771 00772 for ( int i = 0; i < drvCount; ++i ) 00773 { 00774 OGRSFDriverH drv = OGRGetDriver( i ); 00775 if ( drv ) 00776 { 00777 QString drvName = OGR_Dr_GetName( drv ); 00778 if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 ) 00779 { 00780 QString longName; 00781 QString trLongName; 00782 QString glob; 00783 QString exts; 00784 if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() ) 00785 { 00786 resultMap.insert( trLongName, drvName ); 00787 } 00788 } 00789 } 00790 } 00791 00792 return resultMap; 00793 } 00794 00795 QString QgsVectorFileWriter::fileFilterString() 00796 { 00797 QString filterString; 00798 QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats(); 00799 QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin(); 00800 for ( ; it != driverFormatMap.constEnd(); ++it ) 00801 { 00802 if ( filterString.isEmpty() ) 00803 filterString += ";;"; 00804 00805 filterString += it.key(); 00806 } 00807 return filterString; 00808 } 00809 00810 QString QgsVectorFileWriter::filterForDriver( const QString& driverName ) 00811 { 00812 QString longName; 00813 QString trLongName; 00814 QString glob; 00815 QString exts; 00816 if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() ) 00817 return ""; 00818 00819 return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")"; 00820 } 00821 00822 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext ) 00823 { 00824 if ( driverName.startsWith( "AVCE00" ) ) 00825 { 00826 longName = "Arc/Info ASCII Coverage"; 00827 trLongName = QObject::tr( "Arc/Info ASCII Coverage" ); 00828 glob = "*.e00"; 00829 ext = "e00"; 00830 } 00831 else if ( driverName.startsWith( "BNA" ) ) 00832 { 00833 longName = "Atlas BNA"; 00834 trLongName = QObject::tr( "Atlas BNA" ); 00835 glob = "*.bna"; 00836 ext = "bna"; 00837 } 00838 else if ( driverName.startsWith( "CSV" ) ) 00839 { 00840 longName = "Comma Separated Value"; 00841 trLongName = QObject::tr( "Comma Separated Value" ); 00842 glob = "*.csv"; 00843 ext = "csv"; 00844 } 00845 else if ( driverName.startsWith( "ESRI" ) ) 00846 { 00847 longName = "ESRI Shapefile"; 00848 trLongName = QObject::tr( "ESRI Shapefile" ); 00849 glob = "*.shp"; 00850 ext = "shp"; 00851 } 00852 else if ( driverName.startsWith( "FMEObjects Gateway" ) ) 00853 { 00854 longName = "FMEObjects Gateway"; 00855 trLongName = QObject::tr( "FMEObjects Gateway" ); 00856 glob = "*.fdd"; 00857 ext = "fdd"; 00858 } 00859 else if ( driverName.startsWith( "GeoJSON" ) ) 00860 { 00861 longName = "GeoJSON"; 00862 trLongName = QObject::tr( "GeoJSON" ); 00863 glob = "*.geojson"; 00864 ext = "geojson"; 00865 } 00866 else if ( driverName.startsWith( "GeoRSS" ) ) 00867 { 00868 longName = "GeoRSS"; 00869 trLongName = QObject::tr( "GeoRSS" ); 00870 glob = "*.xml"; 00871 ext = "xml"; 00872 } 00873 else if ( driverName.startsWith( "GML" ) ) 00874 { 00875 longName = "Geography Markup Language [GML]"; 00876 trLongName = QObject::tr( "Geography Markup Language [GML]" ); 00877 glob = "*.gml"; 00878 ext = "gml"; 00879 } 00880 else if ( driverName.startsWith( "GMT" ) ) 00881 { 00882 longName = "Generic Mapping Tools [GMT]"; 00883 trLongName = QObject::tr( "Generic Mapping Tools [GMT]" ); 00884 glob = "*.gmt"; 00885 ext = "gmt"; 00886 } 00887 else if ( driverName.startsWith( "GPX" ) ) 00888 { 00889 longName = "GPS eXchange Format [GPX]"; 00890 trLongName = QObject::tr( "GPS eXchange Format [GPX]" ); 00891 glob = "*.gpx"; 00892 ext = "gpx"; 00893 } 00894 else if ( driverName.startsWith( "Interlis 1" ) ) 00895 { 00896 longName = "INTERLIS 1"; 00897 trLongName = QObject::tr( "INTERLIS 1" ); 00898 glob = "*.itf *.xml *.ili"; 00899 ext = "ili"; 00900 } 00901 else if ( driverName.startsWith( "Interlis 2" ) ) 00902 { 00903 longName = "INTERLIS 2"; 00904 trLongName = QObject::tr( "INTERLIS 2" ); 00905 glob = "*.itf *.xml *.ili"; 00906 ext = "ili"; 00907 } 00908 else if ( driverName.startsWith( "KML" ) ) 00909 { 00910 longName = "Keyhole Markup Language [KML]"; 00911 trLongName = QObject::tr( "Keyhole Markup Language [KML]" ); 00912 glob = "*.kml" ; 00913 ext = "kml" ; 00914 } 00915 else if ( driverName.startsWith( "MapInfo File" ) ) 00916 { 00917 longName = "Mapinfo File"; 00918 trLongName = QObject::tr( "Mapinfo File" ); 00919 glob = "*.mif *.tab"; 00920 ext = "mif tab"; 00921 } 00922 else if ( driverName.startsWith( "DGN" ) ) 00923 { 00924 longName = "Microstation DGN"; 00925 trLongName = QObject::tr( "Microstation DGN" ); 00926 glob = "*.dgn"; 00927 ext = "dgn"; 00928 } 00929 else if ( driverName.startsWith( "S57" ) ) 00930 { 00931 longName = "S-57 Base file"; 00932 trLongName = QObject::tr( "S-57 Base file" ); 00933 glob = "*.000"; 00934 ext = "000"; 00935 } 00936 else if ( driverName.startsWith( "SDTS" ) ) 00937 { 00938 longName = "Spatial Data Transfer Standard [SDTS]"; 00939 trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" ); 00940 glob = "*catd.ddf"; 00941 ext = "ddf"; 00942 } 00943 else if ( driverName.startsWith( "SQLite" ) ) 00944 { 00945 longName = "SQLite"; 00946 trLongName = QObject::tr( "SQLite" ); 00947 glob = "*.sqlite"; 00948 ext = "sqlite"; 00949 } 00950 else if ( driverName.startsWith( "DXF" ) ) 00951 { 00952 longName = "AutoCAD DXF"; 00953 trLongName = QObject::tr( "AutoCAD DXF" ); 00954 glob = "*.dxf"; 00955 ext = "dxf"; 00956 } 00957 else if ( driverName.startsWith( "Geoconcept" ) ) 00958 { 00959 longName = "Geoconcept"; 00960 trLongName = QObject::tr( "Geoconcept" ); 00961 glob = "*.gxt *.txt"; 00962 ext = "gxt"; 00963 } 00964 else 00965 { 00966 return false; 00967 } 00968 00969 return true; 00970 }