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