QGIS API Documentation  master-6227475
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 #include "qgsrendererv2.h"
00028 #include "qgssymbollayerv2.h"
00029 
00030 #include <QFile>
00031 #include <QSettings>
00032 #include <QFileInfo>
00033 #include <QDir>
00034 #include <QTextCodec>
00035 #include <QTextStream>
00036 #include <QSet>
00037 #include <QMetaType>
00038 
00039 #include <cassert>
00040 #include <cstdlib> // size_t
00041 #include <limits> // std::numeric_limits
00042 
00043 #include <ogr_srs_api.h>
00044 #include <cpl_error.h>
00045 #include <cpl_conv.h>
00046 
00047 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
00048 #define TO8(x)   (x).toUtf8().constData()
00049 #define TO8F(x)  (x).toUtf8().constData()
00050 #else
00051 #define TO8(x)   (x).toLocal8Bit().constData()
00052 #define TO8F(x)  QFile::encodeName( x ).constData()
00053 #endif
00054 
00055 
00056 QgsVectorFileWriter::QgsVectorFileWriter(
00057   const QString &theVectorFileName,
00058   const QString &theFileEncoding,
00059   const QgsFields& fields,
00060   QGis::WkbType geometryType,
00061   const QgsCoordinateReferenceSystem* srs,
00062   const QString& driverName,
00063   const QStringList &datasourceOptions,
00064   const QStringList &layerOptions,
00065   QString *newFilename,
00066   SymbologyExport symbologyExport
00067 )
00068     : mDS( NULL )
00069     , mLayer( NULL )
00070     , mGeom( NULL )
00071     , mError( NoError )
00072     , mSymbologyExport( symbologyExport )
00073 {
00074   QString vectorFileName = theVectorFileName;
00075   QString fileEncoding = theFileEncoding;
00076   QStringList layOptions = layerOptions;
00077   QStringList dsOptions = datasourceOptions;
00078 
00079   QString ogrDriverName;
00080   if ( driverName == "MapInfo MIF" )
00081   {
00082     ogrDriverName = "MapInfo File";
00083   }
00084   else if ( driverName == "SpatiaLite" )
00085   {
00086     ogrDriverName = "SQLite";
00087     if ( !dsOptions.contains( "SPATIALITE=YES" ) )
00088     {
00089       dsOptions.append( "SPATIALITE=YES" );
00090     }
00091   }
00092   else
00093   {
00094     ogrDriverName = driverName;
00095   }
00096 
00097   // find driver in OGR
00098   OGRSFDriverH poDriver;
00099   QgsApplication::registerOgrDrivers();
00100 
00101   poDriver = OGRGetDriverByName( ogrDriverName.toLocal8Bit().data() );
00102 
00103   if ( poDriver == NULL )
00104   {
00105     mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" )
00106                     .arg( driverName )
00107                     .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00108     mError = ErrDriverNotFound;
00109     return;
00110   }
00111 
00112   if ( driverName == "ESRI Shapefile" )
00113   {
00114     if ( layOptions.join( "" ).toUpper().indexOf( "ENCODING=" ) == -1 )
00115     {
00116       layOptions.append( "ENCODING=" + convertCodecNameForEncodingOption( fileEncoding ) );
00117     }
00118 
00119     CPLSetConfigOption( "SHAPE_ENCODING", "" );
00120 
00121     if ( !vectorFileName.endsWith( ".shp", Qt::CaseInsensitive ) &&
00122          !vectorFileName.endsWith( ".dbf", Qt::CaseInsensitive ) )
00123     {
00124       vectorFileName += ".shp";
00125     }
00126 
00127 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
00128     // check for unique fieldnames
00129     QSet<QString> fieldNames;
00130     for ( int i = 0; i < fields.count(); ++i )
00131     {
00132       QString name = fields[i].name().left( 10 );
00133       if ( fieldNames.contains( name ) )
00134       {
00135         mErrorMessage = QObject::tr( "trimming attribute name '%1' to ten significant characters produces duplicate column name." )
00136                         .arg( fields[i].name() );
00137         mError = ErrAttributeCreationFailed;
00138         return;
00139       }
00140       fieldNames << name;
00141     }
00142 #endif
00143 
00144     deleteShapeFile( vectorFileName );
00145   }
00146   else if ( driverName == "KML" )
00147   {
00148     if ( !vectorFileName.endsWith( ".kml", Qt::CaseInsensitive ) )
00149     {
00150       vectorFileName += ".kml";
00151     }
00152 
00153     if ( fileEncoding.compare( "UTF-8", Qt::CaseInsensitive ) != 0 )
00154     {
00155       QgsDebugMsg( "forced UTF-8 encoding for KML" );
00156       fileEncoding = "UTF-8";
00157     }
00158 
00159     QFile::remove( vectorFileName );
00160   }
00161   else
00162   {
00163     QString longName;
00164     QString trLongName;
00165     QString glob;
00166     QString exts;
00167     if ( QgsVectorFileWriter::driverMetadata( driverName, longName, trLongName, glob, exts ) )
00168     {
00169       QStringList allExts = exts.split( " ", QString::SkipEmptyParts );
00170       bool found = false;
00171       foreach ( QString ext, allExts )
00172       {
00173         if ( vectorFileName.endsWith( "." + ext, Qt::CaseInsensitive ) )
00174         {
00175           found = true;
00176           break;
00177         }
00178       }
00179 
00180       if ( !found )
00181       {
00182         vectorFileName += "." + allExts[0];
00183       }
00184     }
00185 
00186     QFile::remove( vectorFileName );
00187   }
00188 
00189   char **options = NULL;
00190   if ( !dsOptions.isEmpty() )
00191   {
00192     options = new char *[ dsOptions.size()+1 ];
00193     for ( int i = 0; i < dsOptions.size(); i++ )
00194     {
00195       options[i] = CPLStrdup( dsOptions[i].toLocal8Bit().data() );
00196     }
00197     options[ dsOptions.size()] = NULL;
00198   }
00199 
00200   // create the data source
00201   mDS = OGR_Dr_CreateDataSource( poDriver, TO8( vectorFileName ), options );
00202 
00203   if ( options )
00204   {
00205     for ( int i = 0; i < dsOptions.size(); i++ )
00206       CPLFree( options[i] );
00207     delete [] options;
00208     options = NULL;
00209   }
00210 
00211   if ( mDS == NULL )
00212   {
00213     mError = ErrCreateDataSource;
00214     mErrorMessage = QObject::tr( "creation of data source failed (OGR error:%1)" )
00215                     .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00216     return;
00217   }
00218 
00219   QgsDebugMsg( "Created data source" );
00220 
00221   // use appropriate codec
00222   mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
00223   if ( !mCodec )
00224   {
00225     QgsDebugMsg( "error finding QTextCodec for " + fileEncoding );
00226 
00227     QSettings settings;
00228     QString enc = settings.value( "/UI/encoding", "System" ).toString();
00229     mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
00230     if ( !mCodec )
00231     {
00232       QgsDebugMsg( "error finding QTextCodec for " + enc );
00233       mCodec = QTextCodec::codecForLocale();
00234       Q_ASSERT( mCodec );
00235     }
00236   }
00237 
00238   // consider spatial reference system of the layer
00239   OGRSpatialReferenceH ogrRef = NULL;
00240   if ( srs )
00241   {
00242     QString srsWkt = srs->toWkt();
00243     QgsDebugMsg( "WKT to save as is " + srsWkt );
00244     ogrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() );
00245   }
00246 
00247   // datasource created, now create the output layer
00248   QString layerName = QFileInfo( vectorFileName ).baseName();
00249   OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType );
00250 
00251   if ( !layOptions.isEmpty() )
00252   {
00253     options = new char *[ layOptions.size()+1 ];
00254     for ( int i = 0; i < layOptions.size(); i++ )
00255     {
00256       options[i] = CPLStrdup( layOptions[i].toLocal8Bit().data() );
00257     }
00258     options[ layOptions.size()] = NULL;
00259   }
00260 
00261   mLayer = OGR_DS_CreateLayer( mDS, TO8F( layerName ), ogrRef, wkbType, options );
00262 
00263   if ( options )
00264   {
00265     for ( int i = 0; i < layOptions.size(); i++ )
00266       CPLFree( options[i] );
00267     delete [] options;
00268     options = NULL;
00269   }
00270 
00271   if ( srs )
00272   {
00273     if ( driverName == "ESRI Shapefile" )
00274     {
00275       QString layerName = vectorFileName.left( vectorFileName.indexOf( ".shp", Qt::CaseInsensitive ) );
00276       QFile prjFile( layerName + ".qpj" );
00277       if ( prjFile.open( QIODevice::WriteOnly ) )
00278       {
00279         QTextStream prjStream( &prjFile );
00280         prjStream << srs->toWkt().toLocal8Bit().data() << endl;
00281         prjFile.close();
00282       }
00283       else
00284       {
00285         QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" );
00286       }
00287     }
00288 
00289     OSRDestroySpatialReference( ogrRef );
00290   }
00291 
00292   if ( mLayer == NULL )
00293   {
00294     mErrorMessage = QObject::tr( "creation of layer failed (OGR error:%1)" )
00295                     .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00296     mError = ErrCreateLayer;
00297     return;
00298   }
00299 
00300   OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer );
00301 
00302   QgsDebugMsg( "created layer" );
00303 
00304   // create the fields
00305   QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" );
00306 
00307   mFields = fields;
00308   mAttrIdxToOgrIdx.clear();
00309 
00310   for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
00311   {
00312     const QgsField& attrField = fields[fldIdx];
00313 
00314     OGRFieldType ogrType = OFTString; //default to string
00315     int ogrWidth = attrField.length();
00316     int ogrPrecision = attrField.precision();
00317     switch ( attrField.type() )
00318     {
00319       case QVariant::LongLong:
00320         ogrType = OFTString;
00321         ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21;
00322         ogrPrecision = -1;
00323         break;
00324 
00325       case QVariant::String:
00326         ogrType = OFTString;
00327         if ( ogrWidth <= 0 || ogrWidth > 255 )
00328           ogrWidth = 255;
00329         break;
00330 
00331       case QVariant::Int:
00332         ogrType = OFTInteger;
00333         ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
00334         ogrPrecision = 0;
00335         break;
00336 
00337       case QVariant::Double:
00338         ogrType = OFTReal;
00339         break;
00340 
00341       case QVariant::Date:
00342         ogrType = OFTDate;
00343         break;
00344 
00345       case QVariant::DateTime:
00346         ogrType = OFTDateTime;
00347         break;
00348 
00349       default:
00350         //assert(0 && "invalid variant type!");
00351         mErrorMessage = QObject::tr( "unsupported type for field %1" )
00352                         .arg( attrField.name() );
00353         mError = ErrAttributeTypeUnsupported;
00354         return;
00355     }
00356 
00357     // create field definition
00358     OGRFieldDefnH fld = OGR_Fld_Create( mCodec->fromUnicode( attrField.name() ), ogrType );
00359     if ( ogrWidth > 0 )
00360     {
00361       OGR_Fld_SetWidth( fld, ogrWidth );
00362     }
00363 
00364     if ( ogrPrecision >= 0 )
00365     {
00366       OGR_Fld_SetPrecision( fld, ogrPrecision );
00367     }
00368 
00369     // create the field
00370     QgsDebugMsg( "creating field " + attrField.name() +
00371                  " type " + QString( QVariant::typeToName( attrField.type() ) ) +
00372                  " width " + QString::number( ogrWidth ) +
00373                  " precision " + QString::number( ogrPrecision ) );
00374     if ( OGR_L_CreateField( mLayer, fld, true ) != OGRERR_NONE )
00375     {
00376       QgsDebugMsg( "error creating field " + attrField.name() );
00377       mErrorMessage = QObject::tr( "creation of field %1 failed (OGR error: %2)" )
00378                       .arg( attrField.name() )
00379                       .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00380       mError = ErrAttributeCreationFailed;
00381       return;
00382     }
00383 
00384     int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) );
00385     if ( ogrIdx < 0 )
00386     {
00387 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
00388       // if we didn't find our new column, assume it's name was truncated and
00389       // it was the last one added (like for shape files)
00390       int fieldCount = OGR_FD_GetFieldCount( defn );
00391 
00392       OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 );
00393       if ( fdefn )
00394       {
00395         const char *fieldName = OGR_Fld_GetNameRef( fdefn );
00396 
00397         if ( attrField.name().left( strlen( fieldName ) ) == fieldName )
00398         {
00399           ogrIdx = fieldCount - 1;
00400         }
00401       }
00402 #else
00403       // GDAL 1.7 not just truncates, but launders more aggressivly.
00404       ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
00405 #endif
00406 
00407       if ( ogrIdx < 0 )
00408       {
00409         QgsDebugMsg( "error creating field " + attrField.name() );
00410         mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" )
00411                         .arg( attrField.name() )
00412                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00413         mError = ErrAttributeCreationFailed;
00414         return;
00415       }
00416     }
00417 
00418     mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
00419   }
00420 
00421   QgsDebugMsg( "Done creating fields" );
00422 
00423   mWkbType = geometryType;
00424   if ( mWkbType != QGis::WKBNoGeometry )
00425   {
00426     // create geometry which will be used for import
00427     mGeom = createEmptyGeometry( mWkbType );
00428   }
00429 
00430   if ( newFilename )
00431     *newFilename = vectorFileName;
00432 }
00433 
00434 OGRGeometryH QgsVectorFileWriter::createEmptyGeometry( QGis::WkbType wkbType )
00435 {
00436   return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType );
00437 }
00438 
00439 
00440 QgsVectorFileWriter::WriterError QgsVectorFileWriter::hasError()
00441 {
00442   return mError;
00443 }
00444 
00445 QString QgsVectorFileWriter::errorMessage()
00446 {
00447   return mErrorMessage;
00448 }
00449 
00450 bool QgsVectorFileWriter::addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer, QGis::UnitType outputUnit )
00451 {
00452   // create the feature
00453   OGRFeatureH poFeature = createFeature( feature );
00454 
00455   //add OGR feature style type
00456   if ( mSymbologyExport != NoSymbology && renderer )
00457   {
00458     //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
00459     QgsSymbolV2List symbols = renderer->symbolsForFeature( feature );
00460     QString styleString;
00461     QString currentStyle;
00462 
00463     QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin();
00464     for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
00465     {
00466       int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
00467       for ( int i = 0; i < nSymbolLayers; ++i )
00468       {
00469 #if 0
00470         QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) );
00471         if ( it == mSymbolLayerTable.constEnd() )
00472         {
00473           continue;
00474         }
00475 #endif
00476         double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
00477         double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
00478 
00479         currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
00480 
00481         if ( mSymbologyExport == FeatureSymbology )
00482         {
00483           if ( symbolIt != symbols.constBegin() || i != 0 )
00484           {
00485             styleString.append( ";" );
00486           }
00487           styleString.append( currentStyle );
00488         }
00489         else if ( mSymbologyExport == SymbolLayerSymbology )
00490         {
00491           OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() );
00492           if ( !writeFeature( mLayer, poFeature ) )
00493           {
00494             return false;
00495           }
00496         }
00497       }
00498     }
00499     OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() );
00500   }
00501 
00502   if ( mSymbologyExport == NoSymbology || mSymbologyExport == FeatureSymbology )
00503   {
00504     if ( !writeFeature( mLayer, poFeature ) )
00505     {
00506       return false;
00507     }
00508   }
00509 
00510   OGR_F_Destroy( poFeature );
00511   return true;
00512 }
00513 
00514 OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
00515 {
00516   OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) );
00517 
00518   qint64 fid = FID_TO_NUMBER( feature.id() );
00519   if ( fid > std::numeric_limits<int>::max() )
00520   {
00521     QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
00522     OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
00523     if ( err != OGRERR_NONE )
00524     {
00525       QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
00526                    .arg( feature.id() )
00527                    .arg( err ).arg( CPLGetLastErrorMsg() )
00528                  );
00529     }
00530   }
00531 
00532   // attribute handling
00533   for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx )
00534   {
00535     if ( !mAttrIdxToOgrIdx.contains( fldIdx ) )
00536     {
00537       QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) );
00538       continue;
00539     }
00540 
00541     const QVariant& attrValue = feature.attribute( fldIdx );
00542     int ogrField = mAttrIdxToOgrIdx[ fldIdx ];
00543 
00544     if ( !attrValue.isValid() || attrValue.isNull() )
00545       continue;
00546 
00547     switch ( attrValue.type() )
00548     {
00549       case QVariant::Int:
00550         OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
00551         break;
00552       case QVariant::Double:
00553         OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() );
00554         break;
00555       case QVariant::LongLong:
00556       case QVariant::String:
00557         OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
00558         break;
00559       case QVariant::Date:
00560         OGR_F_SetFieldDateTime( poFeature, ogrField,
00561                                 attrValue.toDate().year(),
00562                                 attrValue.toDate().month(),
00563                                 attrValue.toDate().day(),
00564                                 0, 0, 0, 0 );
00565         break;
00566       case QVariant::DateTime:
00567         OGR_F_SetFieldDateTime( poFeature, ogrField,
00568                                 attrValue.toDateTime().date().year(),
00569                                 attrValue.toDateTime().date().month(),
00570                                 attrValue.toDateTime().date().day(),
00571                                 attrValue.toDateTime().time().hour(),
00572                                 attrValue.toDateTime().time().minute(),
00573                                 attrValue.toDateTime().time().second(),
00574                                 0 );
00575         break;
00576       case QVariant::Invalid:
00577         break;
00578       default:
00579         mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
00580                         .arg( mFields[fldIdx].name() )
00581                         .arg( ogrField )
00582                         .arg( QMetaType::typeName( attrValue.type() ) )
00583                         .arg( attrValue.toString() );
00584         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00585         mError = ErrFeatureWriteFailed;
00586         return 0;
00587     }
00588   }
00589 
00590   if ( mWkbType != QGis::WKBNoGeometry )
00591   {
00592     // build geometry from WKB
00593     QgsGeometry *geom = feature.geometry();
00594 
00595     // turn single geoemetry to multi geometry if needed
00596     if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) )
00597     {
00598       geom->convertToMultiType();
00599     }
00600 
00601     if ( geom && geom->wkbType() != mWkbType )
00602     {
00603       // there's a problem when layer type is set as wkbtype Polygon
00604       // although there are also features of type MultiPolygon
00605       // (at least in OGR provider)
00606       // If the feature's wkbtype is different from the layer's wkbtype,
00607       // try to export it too.
00608       //
00609       // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
00610       // i.e. Polygons can't be imported to OGRMultiPolygon
00611 
00612       OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() );
00613 
00614       if ( !mGeom2 )
00615       {
00616         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00617                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00618         mError = ErrFeatureWriteFailed;
00619         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00620         OGR_F_Destroy( poFeature );
00621         return 0;
00622       }
00623 
00624       OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() );
00625       if ( err != OGRERR_NONE )
00626       {
00627         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00628                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00629         mError = ErrFeatureWriteFailed;
00630         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00631         OGR_F_Destroy( poFeature );
00632         return 0;
00633       }
00634 
00635       // pass ownership to geometry
00636       OGR_F_SetGeometryDirectly( poFeature, mGeom2 );
00637     }
00638     else if ( geom )
00639     {
00640       OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() );
00641       if ( err != OGRERR_NONE )
00642       {
00643         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00644                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00645         mError = ErrFeatureWriteFailed;
00646         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00647         OGR_F_Destroy( poFeature );
00648         return 0;
00649       }
00650 
00651       // set geometry (ownership is not passed to OGR)
00652       OGR_F_SetGeometry( poFeature, mGeom );
00653     }
00654   }
00655   return poFeature;
00656 }
00657 
00658 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
00659 {
00660   if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
00661   {
00662     mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00663     mError = ErrFeatureWriteFailed;
00664     QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00665     OGR_F_Destroy( feature );
00666     return false;
00667   }
00668   return true;
00669 }
00670 
00671 QgsVectorFileWriter::~QgsVectorFileWriter()
00672 {
00673   if ( mGeom )
00674   {
00675     OGR_G_DestroyGeometry( mGeom );
00676   }
00677 
00678   if ( mDS )
00679   {
00680     OGR_DS_Destroy( mDS );
00681   }
00682 }
00683 
00684 QgsVectorFileWriter::WriterError
00685 QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
00686     const QString& fileName,
00687     const QString& fileEncoding,
00688     const QgsCoordinateReferenceSystem *destCRS,
00689     const QString& driverName,
00690     bool onlySelected,
00691     QString *errorMessage,
00692     const QStringList &datasourceOptions,
00693     const QStringList &layerOptions,
00694     bool skipAttributeCreation,
00695     QString *newFilename,
00696     SymbologyExport symbologyExport,
00697     double symbologyScale )
00698 {
00699   QgsDebugMsg( "fileName = " + fileName );
00700   const QgsCoordinateReferenceSystem* outputCRS;
00701   QgsCoordinateTransform* ct = 0;
00702   int shallTransform = false;
00703 
00704   if ( layer == NULL )
00705   {
00706     return ErrInvalidLayer;
00707   }
00708 
00709   if ( destCRS && destCRS->isValid() )
00710   {
00711     // This means we should transform
00712     outputCRS = destCRS;
00713     shallTransform = true;
00714   }
00715   else
00716   {
00717     // This means we shouldn't transform, use source CRS as output (if defined)
00718     outputCRS = &layer->crs();
00719   }
00720   QgsVectorFileWriter* writer =
00721     new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
00722   writer->setSymbologyScaleDenominator( symbologyScale );
00723 
00724   if ( newFilename )
00725   {
00726     QgsDebugMsg( "newFilename = " + *newFilename );
00727   }
00728 
00729   // check whether file creation was successful
00730   WriterError err = writer->hasError();
00731   if ( err != NoError )
00732   {
00733     if ( errorMessage )
00734       *errorMessage = writer->errorMessage();
00735     delete writer;
00736     return err;
00737   }
00738 
00739   if ( errorMessage )
00740   {
00741     errorMessage->clear();
00742   }
00743 
00744   QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
00745   QgsFeature fet;
00746 
00747   //add possible attributes needed by renderer
00748   writer->addRendererAttributes( layer, allAttr );
00749 
00750   QgsFeatureRequest req;
00751   if ( layer->wkbType() == QGis::WKBNoGeometry )
00752   {
00753     req.setFlags( QgsFeatureRequest::NoGeometry );
00754   }
00755   req.setSubsetOfAttributes( allAttr );
00756   QgsFeatureIterator fit = layer->getFeatures( req );
00757 
00758   const QgsFeatureIds& ids = layer->selectedFeaturesIds();
00759 
00760   // Create our transform
00761   if ( destCRS )
00762   {
00763     ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
00764   }
00765 
00766   // Check for failure
00767   if ( ct == NULL )
00768   {
00769     shallTransform = false;
00770   }
00771 
00772   //create symbol table if needed
00773   if ( writer->symbologyExport() != NoSymbology )
00774   {
00775     //writer->createSymbolLayerTable( layer,  writer->mDS );
00776   }
00777 
00778   if ( writer->symbologyExport() == SymbolLayerSymbology )
00779   {
00780     QgsFeatureRendererV2* r = layer->rendererV2();
00781     if ( r->capabilities() & QgsFeatureRendererV2::SymbolLevels
00782          && r->usingSymbolLevels() )
00783     {
00784       QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
00785       delete writer;
00786       delete ct;
00787       return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
00788     }
00789   }
00790 
00791   int n = 0, errors = 0;
00792 
00793   //unit type
00794   QGis::UnitType mapUnits = layer->crs().mapUnits();
00795   if ( ct )
00796   {
00797     mapUnits = ct->destCRS().mapUnits();
00798   }
00799 
00800   writer->startRender( layer );
00801 
00802   // write all features
00803   while ( fit.nextFeature( fet ) )
00804   {
00805     if ( onlySelected && !ids.contains( fet.id() ) )
00806       continue;
00807 
00808     if ( shallTransform )
00809     {
00810       try
00811       {
00812         if ( fet.geometry() )
00813         {
00814           fet.geometry()->transform( *ct );
00815         }
00816       }
00817       catch ( QgsCsException &e )
00818       {
00819         delete ct;
00820         delete writer;
00821 
00822         QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
00823                       .arg( fet.id() ).arg( e.what() );
00824         QgsLogger::warning( msg );
00825         if ( errorMessage )
00826           *errorMessage = msg;
00827 
00828         return ErrProjection;
00829       }
00830     }
00831     if ( allAttr.size() < 1 && skipAttributeCreation )
00832     {
00833       fet.initAttributes( 0 );
00834     }
00835 
00836     if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
00837     {
00838       WriterError err = writer->hasError();
00839       if ( err != NoError && errorMessage )
00840       {
00841         if ( errorMessage->isEmpty() )
00842         {
00843           *errorMessage = QObject::tr( "Feature write errors:" );
00844         }
00845         *errorMessage += "\n" + writer->errorMessage();
00846       }
00847       errors++;
00848 
00849       if ( errors > 1000 )
00850       {
00851         if ( errorMessage )
00852         {
00853           *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
00854         }
00855 
00856         n = -1;
00857         break;
00858       }
00859     }
00860     n++;
00861   }
00862 
00863   writer->stopRender( layer );
00864   delete writer;
00865 
00866   if ( shallTransform )
00867   {
00868     delete ct;
00869   }
00870 
00871   if ( errors > 0 && errorMessage && n > 0 )
00872   {
00873     *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
00874   }
00875 
00876   return errors == 0 ? NoError : ErrFeatureWriteFailed;
00877 }
00878 
00879 
00880 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName )
00881 {
00882   QFileInfo fi( theFileName );
00883   QDir dir = fi.dir();
00884 
00885   QStringList filter;
00886   const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
00887   for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
00888   {
00889     filter << fi.completeBaseName() + suffixes[i];
00890   }
00891 
00892   bool ok = true;
00893   foreach ( QString file, dir.entryList( filter ) )
00894   {
00895     if ( !QFile::remove( dir.canonicalPath() + "/" + file ) )
00896     {
00897       QgsDebugMsg( "Removing file failed : " + file );
00898       ok = false;
00899     }
00900   }
00901 
00902   return ok;
00903 }
00904 
00905 QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
00906 {
00907   QMap<QString, QString> resultMap;
00908 
00909   QgsApplication::registerOgrDrivers();
00910   int const drvCount = OGRGetDriverCount();
00911 
00912   for ( int i = 0; i < drvCount; ++i )
00913   {
00914     OGRSFDriverH drv = OGRGetDriver( i );
00915     if ( drv )
00916     {
00917       QString drvName = OGR_Dr_GetName( drv );
00918       if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
00919       {
00920         QString filterString = filterForDriver( drvName );
00921         if ( filterString.isEmpty() )
00922           continue;
00923 
00924         resultMap.insert( filterString, drvName );
00925       }
00926     }
00927   }
00928 
00929   return resultMap;
00930 }
00931 
00932 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
00933 {
00934   QMap<QString, QString> resultMap;
00935 
00936   QgsApplication::registerOgrDrivers();
00937   int const drvCount = OGRGetDriverCount();
00938 
00939   QStringList writableDrivers;
00940   for ( int i = 0; i < drvCount; ++i )
00941   {
00942     OGRSFDriverH drv = OGRGetDriver( i );
00943     if ( drv )
00944     {
00945       QString drvName = OGR_Dr_GetName( drv );
00946       if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
00947       {
00948         // Add separate format for Mapinfo MIF (MITAB is OGR default)
00949         if ( drvName == "MapInfo File" )
00950         {
00951           writableDrivers << "MapInfo MIF";
00952         }
00953         else if ( drvName == "SQLite" )
00954         {
00955           // Unfortunately it seems that there is no simple way to detect if
00956           // OGR SQLite driver is compiled with SpatiaLite support.
00957           // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
00958           // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
00959           // -> test if creation failes
00960           QString option = "SPATIALITE=YES";
00961           char **options =  new char *[2];
00962           options[0] = CPLStrdup( option.toLocal8Bit().data() );
00963           options[1] = NULL;
00964           OGRSFDriverH poDriver;
00965           QgsApplication::registerOgrDrivers();
00966           poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() );
00967           if ( poDriver )
00968           {
00969             OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8( QString( "/vsimem/spatialitetest.sqlite" ) ), options );
00970             if ( ds )
00971             {
00972               writableDrivers << "SpatiaLite";
00973               OGR_DS_Destroy( ds );
00974             }
00975           }
00976           CPLFree( options[0] );
00977           delete [] options;
00978         }
00979         writableDrivers << drvName;
00980       }
00981     }
00982   }
00983 
00984   foreach ( QString drvName, writableDrivers )
00985   {
00986     QString longName;
00987     QString trLongName;
00988     QString glob;
00989     QString exts;
00990     if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() )
00991     {
00992       resultMap.insert( trLongName, drvName );
00993     }
00994   }
00995 
00996   return resultMap;
00997 }
00998 
00999 QString QgsVectorFileWriter::fileFilterString()
01000 {
01001   QString filterString;
01002   QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats();
01003   QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
01004   for ( ; it != driverFormatMap.constEnd(); ++it )
01005   {
01006     if ( filterString.isEmpty() )
01007       filterString += ";;";
01008 
01009     filterString += it.key();
01010   }
01011   return filterString;
01012 }
01013 
01014 QString QgsVectorFileWriter::filterForDriver( const QString& driverName )
01015 {
01016   QString longName;
01017   QString trLongName;
01018   QString glob;
01019   QString exts;
01020   if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() )
01021     return "";
01022 
01023   return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")";
01024 }
01025 
01026 QString QgsVectorFileWriter::convertCodecNameForEncodingOption( const QString &codecName )
01027 {
01028   if ( codecName == "System" )
01029     return QString( "LDID/0" );
01030 
01031   QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
01032   if ( re.exactMatch( codecName ) )
01033   {
01034     QString c = re.cap( 2 ).replace( "-" , "" );
01035     bool isNumber;
01036     c.toInt( &isNumber );
01037     if ( isNumber )
01038       return c;
01039   }
01040   return codecName;
01041 }
01042 
01043 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext )
01044 {
01045   if ( driverName.startsWith( "AVCE00" ) )
01046   {
01047     longName = "Arc/Info ASCII Coverage";
01048     trLongName = QObject::tr( "Arc/Info ASCII Coverage" );
01049     glob = "*.e00";
01050     ext = "e00";
01051   }
01052   else if ( driverName.startsWith( "BNA" ) )
01053   {
01054     longName = "Atlas BNA";
01055     trLongName = QObject::tr( "Atlas BNA" );
01056     glob = "*.bna";
01057     ext = "bna";
01058   }
01059   else if ( driverName.startsWith( "CSV" ) )
01060   {
01061     longName = "Comma Separated Value";
01062     trLongName = QObject::tr( "Comma Separated Value" );
01063     glob = "*.csv";
01064     ext = "csv";
01065   }
01066   else if ( driverName.startsWith( "ESRI" ) )
01067   {
01068     longName = "ESRI Shapefile";
01069     trLongName = QObject::tr( "ESRI Shapefile" );
01070     glob = "*.shp";
01071     ext = "shp";
01072   }
01073   else if ( driverName.startsWith( "FMEObjects Gateway" ) )
01074   {
01075     longName = "FMEObjects Gateway";
01076     trLongName = QObject::tr( "FMEObjects Gateway" );
01077     glob = "*.fdd";
01078     ext = "fdd";
01079   }
01080   else if ( driverName.startsWith( "GeoJSON" ) )
01081   {
01082     longName = "GeoJSON";
01083     trLongName = QObject::tr( "GeoJSON" );
01084     glob = "*.geojson";
01085     ext = "geojson";
01086   }
01087   else if ( driverName.startsWith( "GeoRSS" ) )
01088   {
01089     longName = "GeoRSS";
01090     trLongName = QObject::tr( "GeoRSS" );
01091     glob = "*.xml";
01092     ext = "xml";
01093   }
01094   else if ( driverName.startsWith( "GML" ) )
01095   {
01096     longName = "Geography Markup Language [GML]";
01097     trLongName = QObject::tr( "Geography Markup Language [GML]" );
01098     glob = "*.gml";
01099     ext = "gml";
01100   }
01101   else if ( driverName.startsWith( "GMT" ) )
01102   {
01103     longName = "Generic Mapping Tools [GMT]";
01104     trLongName = QObject::tr( "Generic Mapping Tools [GMT]" );
01105     glob = "*.gmt";
01106     ext = "gmt";
01107   }
01108   else if ( driverName.startsWith( "GPX" ) )
01109   {
01110     longName = "GPS eXchange Format [GPX]";
01111     trLongName = QObject::tr( "GPS eXchange Format [GPX]" );
01112     glob = "*.gpx";
01113     ext = "gpx";
01114   }
01115   else if ( driverName.startsWith( "Interlis 1" ) )
01116   {
01117     longName = "INTERLIS 1";
01118     trLongName = QObject::tr( "INTERLIS 1" );
01119     glob = "*.itf *.xml *.ili";
01120     ext = "ili";
01121   }
01122   else if ( driverName.startsWith( "Interlis 2" ) )
01123   {
01124     longName = "INTERLIS 2";
01125     trLongName = QObject::tr( "INTERLIS 2" );
01126     glob = "*.itf *.xml *.ili";
01127     ext = "ili";
01128   }
01129   else if ( driverName.startsWith( "KML" ) )
01130   {
01131     longName = "Keyhole Markup Language [KML]";
01132     trLongName = QObject::tr( "Keyhole Markup Language [KML]" );
01133     glob = "*.kml" ;
01134     ext = "kml" ;
01135   }
01136   else if ( driverName.startsWith( "MapInfo File" ) )
01137   {
01138     longName = "Mapinfo TAB";
01139     trLongName = QObject::tr( "Mapinfo TAB" );
01140     glob = "*.tab";
01141     ext = "tab";
01142   }
01143   // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF
01144   else if ( driverName.startsWith( "MapInfo MIF" ) )
01145   {
01146     longName = "Mapinfo MIF";
01147     trLongName = QObject::tr( "Mapinfo MIF" );
01148     glob = "*.mif";
01149     ext = "mif";
01150   }
01151   else if ( driverName.startsWith( "DGN" ) )
01152   {
01153     longName = "Microstation DGN";
01154     trLongName = QObject::tr( "Microstation DGN" );
01155     glob = "*.dgn";
01156     ext = "dgn";
01157   }
01158   else if ( driverName.startsWith( "S57" ) )
01159   {
01160     longName = "S-57 Base file";
01161     trLongName = QObject::tr( "S-57 Base file" );
01162     glob = "*.000";
01163     ext = "000";
01164   }
01165   else if ( driverName.startsWith( "SDTS" ) )
01166   {
01167     longName = "Spatial Data Transfer Standard [SDTS]";
01168     trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" );
01169     glob = "*catd.ddf";
01170     ext = "ddf";
01171   }
01172   else if ( driverName.startsWith( "SQLite" ) )
01173   {
01174     longName = "SQLite";
01175     trLongName = QObject::tr( "SQLite" );
01176     glob = "*.sqlite";
01177     ext = "sqlite";
01178   }
01179   // QGIS internal addition for SpatialLite
01180   else if ( driverName.startsWith( "SpatiaLite" ) )
01181   {
01182     longName = "SpatiaLite";
01183     trLongName = QObject::tr( "SpatiaLite" );
01184     glob = "*.sqlite";
01185     ext = "sqlite";
01186   }
01187   else if ( driverName.startsWith( "DXF" ) )
01188   {
01189     longName = "AutoCAD DXF";
01190     trLongName = QObject::tr( "AutoCAD DXF" );
01191     glob = "*.dxf";
01192     ext = "dxf";
01193   }
01194   else if ( driverName.startsWith( "Geoconcept" ) )
01195   {
01196     longName = "Geoconcept";
01197     trLongName = QObject::tr( "Geoconcept" );
01198     glob = "*.gxt *.txt";
01199     ext = "gxt";
01200   }
01201   else if ( driverName.startsWith( "FileGDB" ) )
01202   {
01203     longName = "ESRI FileGDB";
01204     trLongName = QObject::tr( "ESRI FileGDB" );
01205     glob = "*.gdb";
01206     ext = "gdb";
01207   }
01208   else
01209   {
01210     return false;
01211   }
01212 
01213   return true;
01214 }
01215 
01216 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl,  const QgsCoordinateTransform* ct, OGRDataSourceH ds )
01217 {
01218   if ( !vl || !ds )
01219   {
01220     return;
01221   }
01222 
01223   QgsFeatureRendererV2* renderer = vl->rendererV2();
01224   if ( !renderer )
01225   {
01226     return;
01227   }
01228 
01229   //unit type
01230   QGis::UnitType mapUnits = vl->crs().mapUnits();
01231   if ( ct )
01232   {
01233     mapUnits = ct->destCRS().mapUnits();
01234   }
01235 
01236 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700
01237   mSymbolLayerTable.clear();
01238   OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
01239   OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
01240 
01241   //get symbols
01242   int nTotalLevels = 0;
01243   QgsSymbolV2List symbolList = renderer->symbols();
01244   QgsSymbolV2List::iterator symbolIt = symbolList.begin();
01245   for ( ; symbolIt != symbolList.end(); ++symbolIt )
01246   {
01247     double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
01248     double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
01249 
01250     int nLevels = ( *symbolIt )->symbolLayerCount();
01251     for ( int i = 0; i < nLevels; ++i )
01252     {
01253       mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
01254       OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
01255                        ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
01256       ++nTotalLevels;
01257     }
01258   }
01259   OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
01260 #endif
01261 }
01262 
01263 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit,
01264     const QgsCoordinateTransform* ct, QString* errorMessage )
01265 {
01266   if ( !layer )
01267   {
01268     //return error
01269   }
01270   QgsFeatureRendererV2* renderer = layer->rendererV2();
01271   if ( !renderer )
01272   {
01273     //return error
01274   }
01275   QHash< QgsSymbolV2*, QList<QgsFeature> > features;
01276 
01277   //unit type
01278   QGis::UnitType mapUnits = layer->crs().mapUnits();
01279   if ( ct )
01280   {
01281     mapUnits = ct->destCRS().mapUnits();
01282   }
01283 
01284   startRender( layer );
01285 
01286   //fetch features
01287   QgsFeature fet;
01288   QgsSymbolV2* featureSymbol = 0;
01289   while ( fit.nextFeature( fet ) )
01290   {
01291     if ( ct )
01292     {
01293       try
01294       {
01295         if ( fet.geometry() )
01296         {
01297           fet.geometry()->transform( *ct );
01298         }
01299       }
01300       catch ( QgsCsException &e )
01301       {
01302         delete ct;
01303 
01304         QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
01305                       .arg( e.what() );
01306         QgsLogger::warning( msg );
01307         if ( errorMessage )
01308           *errorMessage = msg;
01309 
01310         return ErrProjection;
01311       }
01312     }
01313 
01314     featureSymbol = renderer->symbolForFeature( fet );
01315     if ( !featureSymbol )
01316     {
01317       continue;
01318     }
01319 
01320     QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
01321     if ( it == features.end() )
01322     {
01323       it = features.insert( featureSymbol, QList<QgsFeature>() );
01324     }
01325     it.value().append( fet );
01326   }
01327 
01328   //find out order
01329   QgsSymbolV2LevelOrder levels;
01330   QgsSymbolV2List symbols = renderer->symbols();
01331   for ( int i = 0; i < symbols.count(); i++ )
01332   {
01333     QgsSymbolV2* sym = symbols[i];
01334     for ( int j = 0; j < sym->symbolLayerCount(); j++ )
01335     {
01336       int level = sym->symbolLayer( j )->renderingPass();
01337       if ( level < 0 || level >= 1000 ) // ignore invalid levels
01338         continue;
01339       QgsSymbolV2LevelItem item( sym, j );
01340       while ( level >= levels.count() ) // append new empty levels
01341         levels.append( QgsSymbolV2Level() );
01342       levels[level].append( item );
01343     }
01344   }
01345 
01346   int nErrors = 0;
01347   int nTotalFeatures = 0;
01348 
01349   //export symbol layers and symbology
01350   for ( int l = 0; l < levels.count(); l++ )
01351   {
01352     QgsSymbolV2Level& level = levels[l];
01353     for ( int i = 0; i < level.count(); i++ )
01354     {
01355       QgsSymbolV2LevelItem& item = level[i];
01356       QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
01357       if ( levelIt == features.end() )
01358       {
01359         ++nErrors;
01360         continue;
01361       }
01362 
01363       double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
01364       double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
01365 
01366       int llayer = item.layer();
01367       QList<QgsFeature>& featureList = levelIt.value();
01368       QList<QgsFeature>::iterator featureIt = featureList.begin();
01369       for ( ; featureIt != featureList.end(); ++featureIt )
01370       {
01371         ++nTotalFeatures;
01372         OGRFeatureH ogrFeature = createFeature( *featureIt );
01373         if ( !ogrFeature )
01374         {
01375           ++nErrors;
01376           continue;
01377         }
01378 
01379         QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
01380         if ( !styleString.isEmpty() )
01381         {
01382           OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
01383           if ( ! writeFeature( mLayer, ogrFeature ) )
01384           {
01385             ++nErrors;
01386           }
01387         }
01388         OGR_F_Destroy( ogrFeature );
01389       }
01390     }
01391   }
01392 
01393   stopRender( layer );
01394 
01395   if ( nErrors > 0 && errorMessage )
01396   {
01397     *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
01398   }
01399 
01400   return ( nErrors > 0 ) ? QgsVectorFileWriter::ErrFeatureWriteFailed : QgsVectorFileWriter::NoError;
01401 }
01402 
01403 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
01404 {
01405   if ( symbolUnits == QgsSymbolV2::MM )
01406   {
01407     return 1.0;
01408   }
01409   else
01410   {
01411     //conversion factor map units -> mm
01412     if ( mapUnits == QGis::Meters )
01413     {
01414       return 1000 / scaleDenominator;
01415     }
01416 
01417   }
01418   return 1.0; //todo: map units
01419 }
01420 
01421 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
01422 {
01423   if ( symbolUnits == QgsSymbolV2::MapUnit )
01424   {
01425     return 1.0;
01426   }
01427   else
01428   {
01429     if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
01430     {
01431       return scaleDenominator / 1000;
01432     }
01433   }
01434   return 1.0;
01435 }
01436 
01437 QgsRenderContext QgsVectorFileWriter::renderContext() const
01438 {
01439   QgsRenderContext context;
01440   context.setRendererScale( mSymbologyScaleDenominator );
01441   return context;
01442 }
01443 
01444 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl ) const
01445 {
01446   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01447   if ( !renderer )
01448   {
01449     return;
01450   }
01451 
01452   QgsRenderContext ctx = renderContext();
01453   renderer->startRender( ctx, vl );
01454 }
01455 
01456 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl ) const
01457 {
01458   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01459   if ( !renderer )
01460   {
01461     return;
01462   }
01463 
01464   QgsRenderContext ctx = renderContext();
01465   renderer->stopRender( ctx );
01466 }
01467 
01468 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const
01469 {
01470   if ( mSymbologyExport == NoSymbology )
01471   {
01472     return 0;
01473   }
01474   if ( !vl )
01475   {
01476     return 0;
01477   }
01478 
01479   return vl->rendererV2();
01480 }
01481 
01482 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList )
01483 {
01484   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01485   if ( renderer )
01486   {
01487     QList<QString> rendererAttributes = renderer->usedAttributes();
01488     for ( int i = 0; i < rendererAttributes.size(); ++i )
01489     {
01490       int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
01491       if ( index != -1 )
01492       {
01493         attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
01494       }
01495     }
01496   }
01497 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines