Quantum GIS API Documentation  1.8
src/core/qgsvectorfilewriter.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines