Quantum GIS API Documentation  1.7.4
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 /* $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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines