QGIS API Documentation  master-59fd5e0
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       OGR_Fld_Destroy( fld );
00382       return;
00383     }
00384     OGR_Fld_Destroy( fld );
00385 
00386     int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) );
00387     if ( ogrIdx < 0 )
00388     {
00389 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
00390       // if we didn't find our new column, assume it's name was truncated and
00391       // it was the last one added (like for shape files)
00392       int fieldCount = OGR_FD_GetFieldCount( defn );
00393 
00394       OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 );
00395       if ( fdefn )
00396       {
00397         const char *fieldName = OGR_Fld_GetNameRef( fdefn );
00398 
00399         if ( attrField.name().left( strlen( fieldName ) ) == fieldName )
00400         {
00401           ogrIdx = fieldCount - 1;
00402         }
00403       }
00404 #else
00405       // GDAL 1.7 not just truncates, but launders more aggressivly.
00406       ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
00407 #endif
00408 
00409       if ( ogrIdx < 0 )
00410       {
00411         QgsDebugMsg( "error creating field " + attrField.name() );
00412         mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" )
00413                         .arg( attrField.name() )
00414                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00415         mError = ErrAttributeCreationFailed;
00416         return;
00417       }
00418     }
00419 
00420     mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
00421   }
00422 
00423   QgsDebugMsg( "Done creating fields" );
00424 
00425   mWkbType = geometryType;
00426   if ( mWkbType != QGis::WKBNoGeometry )
00427   {
00428     // create geometry which will be used for import
00429     mGeom = createEmptyGeometry( mWkbType );
00430   }
00431 
00432   if ( newFilename )
00433     *newFilename = vectorFileName;
00434 }
00435 
00436 OGRGeometryH QgsVectorFileWriter::createEmptyGeometry( QGis::WkbType wkbType )
00437 {
00438   return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType );
00439 }
00440 
00441 
00442 QgsVectorFileWriter::WriterError QgsVectorFileWriter::hasError()
00443 {
00444   return mError;
00445 }
00446 
00447 QString QgsVectorFileWriter::errorMessage()
00448 {
00449   return mErrorMessage;
00450 }
00451 
00452 bool QgsVectorFileWriter::addFeature( QgsFeature& feature, QgsFeatureRendererV2* renderer, QGis::UnitType outputUnit )
00453 {
00454   // create the feature
00455   OGRFeatureH poFeature = createFeature( feature );
00456 
00457   //add OGR feature style type
00458   if ( mSymbologyExport != NoSymbology && renderer )
00459   {
00460     //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
00461     QgsSymbolV2List symbols = renderer->symbolsForFeature( feature );
00462     QString styleString;
00463     QString currentStyle;
00464 
00465     QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin();
00466     for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
00467     {
00468       int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
00469       for ( int i = 0; i < nSymbolLayers; ++i )
00470       {
00471 #if 0
00472         QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) );
00473         if ( it == mSymbolLayerTable.constEnd() )
00474         {
00475           continue;
00476         }
00477 #endif
00478         double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
00479         double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
00480 
00481         currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
00482 
00483         if ( mSymbologyExport == FeatureSymbology )
00484         {
00485           if ( symbolIt != symbols.constBegin() || i != 0 )
00486           {
00487             styleString.append( ";" );
00488           }
00489           styleString.append( currentStyle );
00490         }
00491         else if ( mSymbologyExport == SymbolLayerSymbology )
00492         {
00493           OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() );
00494           if ( !writeFeature( mLayer, poFeature ) )
00495           {
00496             return false;
00497           }
00498         }
00499       }
00500     }
00501     OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() );
00502   }
00503 
00504   if ( mSymbologyExport == NoSymbology || mSymbologyExport == FeatureSymbology )
00505   {
00506     if ( !writeFeature( mLayer, poFeature ) )
00507     {
00508       return false;
00509     }
00510   }
00511 
00512   OGR_F_Destroy( poFeature );
00513   return true;
00514 }
00515 
00516 OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
00517 {
00518   OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) );
00519 
00520   qint64 fid = FID_TO_NUMBER( feature.id() );
00521   if ( fid > std::numeric_limits<int>::max() )
00522   {
00523     QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
00524     OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
00525     if ( err != OGRERR_NONE )
00526     {
00527       QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
00528                    .arg( feature.id() )
00529                    .arg( err ).arg( CPLGetLastErrorMsg() )
00530                  );
00531     }
00532   }
00533 
00534   // attribute handling
00535   for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx )
00536   {
00537     if ( !mAttrIdxToOgrIdx.contains( fldIdx ) )
00538     {
00539       QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) );
00540       continue;
00541     }
00542 
00543     const QVariant& attrValue = feature.attribute( fldIdx );
00544     int ogrField = mAttrIdxToOgrIdx[ fldIdx ];
00545 
00546     if ( !attrValue.isValid() || attrValue.isNull() )
00547       continue;
00548 
00549     switch ( attrValue.type() )
00550     {
00551       case QVariant::Int:
00552         OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
00553         break;
00554       case QVariant::Double:
00555         OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() );
00556         break;
00557       case QVariant::LongLong:
00558       case QVariant::String:
00559         OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
00560         break;
00561       case QVariant::Date:
00562         OGR_F_SetFieldDateTime( poFeature, ogrField,
00563                                 attrValue.toDate().year(),
00564                                 attrValue.toDate().month(),
00565                                 attrValue.toDate().day(),
00566                                 0, 0, 0, 0 );
00567         break;
00568       case QVariant::DateTime:
00569         OGR_F_SetFieldDateTime( poFeature, ogrField,
00570                                 attrValue.toDateTime().date().year(),
00571                                 attrValue.toDateTime().date().month(),
00572                                 attrValue.toDateTime().date().day(),
00573                                 attrValue.toDateTime().time().hour(),
00574                                 attrValue.toDateTime().time().minute(),
00575                                 attrValue.toDateTime().time().second(),
00576                                 0 );
00577         break;
00578       case QVariant::Invalid:
00579         break;
00580       default:
00581         mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
00582                         .arg( mFields[fldIdx].name() )
00583                         .arg( ogrField )
00584                         .arg( QMetaType::typeName( attrValue.type() ) )
00585                         .arg( attrValue.toString() );
00586         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00587         mError = ErrFeatureWriteFailed;
00588         return 0;
00589     }
00590   }
00591 
00592   if ( mWkbType != QGis::WKBNoGeometry )
00593   {
00594     // build geometry from WKB
00595     QgsGeometry *geom = feature.geometry();
00596 
00597     // turn single geoemetry to multi geometry if needed
00598     if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) )
00599     {
00600       geom->convertToMultiType();
00601     }
00602 
00603     if ( geom && geom->wkbType() != mWkbType )
00604     {
00605       // there's a problem when layer type is set as wkbtype Polygon
00606       // although there are also features of type MultiPolygon
00607       // (at least in OGR provider)
00608       // If the feature's wkbtype is different from the layer's wkbtype,
00609       // try to export it too.
00610       //
00611       // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
00612       // i.e. Polygons can't be imported to OGRMultiPolygon
00613 
00614       OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() );
00615 
00616       if ( !mGeom2 )
00617       {
00618         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00619                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00620         mError = ErrFeatureWriteFailed;
00621         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00622         OGR_F_Destroy( poFeature );
00623         return 0;
00624       }
00625 
00626       OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() );
00627       if ( err != OGRERR_NONE )
00628       {
00629         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00630                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00631         mError = ErrFeatureWriteFailed;
00632         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00633         OGR_F_Destroy( poFeature );
00634         return 0;
00635       }
00636 
00637       // pass ownership to geometry
00638       OGR_F_SetGeometryDirectly( poFeature, mGeom2 );
00639     }
00640     else if ( geom )
00641     {
00642       OGRErr err = OGR_G_ImportFromWkb( mGeom, geom->asWkb(), geom->wkbSize() );
00643       if ( err != OGRERR_NONE )
00644       {
00645         mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
00646                         .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00647         mError = ErrFeatureWriteFailed;
00648         QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00649         OGR_F_Destroy( poFeature );
00650         return 0;
00651       }
00652 
00653       // set geometry (ownership is not passed to OGR)
00654       OGR_F_SetGeometry( poFeature, mGeom );
00655     }
00656   }
00657   return poFeature;
00658 }
00659 
00660 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
00661 {
00662   if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
00663   {
00664     mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
00665     mError = ErrFeatureWriteFailed;
00666     QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
00667     OGR_F_Destroy( feature );
00668     return false;
00669   }
00670   return true;
00671 }
00672 
00673 QgsVectorFileWriter::~QgsVectorFileWriter()
00674 {
00675   if ( mGeom )
00676   {
00677     OGR_G_DestroyGeometry( mGeom );
00678   }
00679 
00680   if ( mDS )
00681   {
00682     OGR_DS_Destroy( mDS );
00683   }
00684 }
00685 
00686 QgsVectorFileWriter::WriterError
00687 QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
00688     const QString& fileName,
00689     const QString& fileEncoding,
00690     const QgsCoordinateReferenceSystem *destCRS,
00691     const QString& driverName,
00692     bool onlySelected,
00693     QString *errorMessage,
00694     const QStringList &datasourceOptions,
00695     const QStringList &layerOptions,
00696     bool skipAttributeCreation,
00697     QString *newFilename,
00698     SymbologyExport symbologyExport,
00699     double symbologyScale )
00700 {
00701   QgsDebugMsg( "fileName = " + fileName );
00702   const QgsCoordinateReferenceSystem* outputCRS;
00703   QgsCoordinateTransform* ct = 0;
00704   int shallTransform = false;
00705 
00706   if ( layer == NULL )
00707   {
00708     return ErrInvalidLayer;
00709   }
00710 
00711   if ( destCRS && destCRS->isValid() )
00712   {
00713     // This means we should transform
00714     outputCRS = destCRS;
00715     shallTransform = true;
00716   }
00717   else
00718   {
00719     // This means we shouldn't transform, use source CRS as output (if defined)
00720     outputCRS = &layer->crs();
00721   }
00722   QgsVectorFileWriter* writer =
00723     new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
00724   writer->setSymbologyScaleDenominator( symbologyScale );
00725 
00726   if ( newFilename )
00727   {
00728     QgsDebugMsg( "newFilename = " + *newFilename );
00729   }
00730 
00731   // check whether file creation was successful
00732   WriterError err = writer->hasError();
00733   if ( err != NoError )
00734   {
00735     if ( errorMessage )
00736       *errorMessage = writer->errorMessage();
00737     delete writer;
00738     return err;
00739   }
00740 
00741   if ( errorMessage )
00742   {
00743     errorMessage->clear();
00744   }
00745 
00746   QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
00747   QgsFeature fet;
00748 
00749   //add possible attributes needed by renderer
00750   writer->addRendererAttributes( layer, allAttr );
00751 
00752   QgsFeatureRequest req;
00753   if ( layer->wkbType() == QGis::WKBNoGeometry )
00754   {
00755     req.setFlags( QgsFeatureRequest::NoGeometry );
00756   }
00757   req.setSubsetOfAttributes( allAttr );
00758   QgsFeatureIterator fit = layer->getFeatures( req );
00759 
00760   const QgsFeatureIds& ids = layer->selectedFeaturesIds();
00761 
00762   // Create our transform
00763   if ( destCRS )
00764   {
00765     ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
00766   }
00767 
00768   // Check for failure
00769   if ( ct == NULL )
00770   {
00771     shallTransform = false;
00772   }
00773 
00774   //create symbol table if needed
00775   if ( writer->symbologyExport() != NoSymbology )
00776   {
00777     //writer->createSymbolLayerTable( layer,  writer->mDS );
00778   }
00779 
00780   if ( writer->symbologyExport() == SymbolLayerSymbology )
00781   {
00782     QgsFeatureRendererV2* r = layer->rendererV2();
00783     if ( r->capabilities() & QgsFeatureRendererV2::SymbolLevels
00784          && r->usingSymbolLevels() )
00785     {
00786       QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
00787       delete writer;
00788       delete ct;
00789       return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
00790     }
00791   }
00792 
00793   int n = 0, errors = 0;
00794 
00795   //unit type
00796   QGis::UnitType mapUnits = layer->crs().mapUnits();
00797   if ( ct )
00798   {
00799     mapUnits = ct->destCRS().mapUnits();
00800   }
00801 
00802   writer->startRender( layer );
00803 
00804   // write all features
00805   while ( fit.nextFeature( fet ) )
00806   {
00807     if ( onlySelected && !ids.contains( fet.id() ) )
00808       continue;
00809 
00810     if ( shallTransform )
00811     {
00812       try
00813       {
00814         if ( fet.geometry() )
00815         {
00816           fet.geometry()->transform( *ct );
00817         }
00818       }
00819       catch ( QgsCsException &e )
00820       {
00821         delete ct;
00822         delete writer;
00823 
00824         QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
00825                       .arg( fet.id() ).arg( e.what() );
00826         QgsLogger::warning( msg );
00827         if ( errorMessage )
00828           *errorMessage = msg;
00829 
00830         return ErrProjection;
00831       }
00832     }
00833     if ( allAttr.size() < 1 && skipAttributeCreation )
00834     {
00835       fet.initAttributes( 0 );
00836     }
00837 
00838     if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
00839     {
00840       WriterError err = writer->hasError();
00841       if ( err != NoError && errorMessage )
00842       {
00843         if ( errorMessage->isEmpty() )
00844         {
00845           *errorMessage = QObject::tr( "Feature write errors:" );
00846         }
00847         *errorMessage += "\n" + writer->errorMessage();
00848       }
00849       errors++;
00850 
00851       if ( errors > 1000 )
00852       {
00853         if ( errorMessage )
00854         {
00855           *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
00856         }
00857 
00858         n = -1;
00859         break;
00860       }
00861     }
00862     n++;
00863   }
00864 
00865   writer->stopRender( layer );
00866   delete writer;
00867 
00868   if ( shallTransform )
00869   {
00870     delete ct;
00871   }
00872 
00873   if ( errors > 0 && errorMessage && n > 0 )
00874   {
00875     *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
00876   }
00877 
00878   return errors == 0 ? NoError : ErrFeatureWriteFailed;
00879 }
00880 
00881 
00882 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName )
00883 {
00884   QFileInfo fi( theFileName );
00885   QDir dir = fi.dir();
00886 
00887   QStringList filter;
00888   const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
00889   for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
00890   {
00891     filter << fi.completeBaseName() + suffixes[i];
00892   }
00893 
00894   bool ok = true;
00895   foreach ( QString file, dir.entryList( filter ) )
00896   {
00897     if ( !QFile::remove( dir.canonicalPath() + "/" + file ) )
00898     {
00899       QgsDebugMsg( "Removing file failed : " + file );
00900       ok = false;
00901     }
00902   }
00903 
00904   return ok;
00905 }
00906 
00907 QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
00908 {
00909   QMap<QString, QString> resultMap;
00910 
00911   QgsApplication::registerOgrDrivers();
00912   int const drvCount = OGRGetDriverCount();
00913 
00914   for ( int i = 0; i < drvCount; ++i )
00915   {
00916     OGRSFDriverH drv = OGRGetDriver( i );
00917     if ( drv )
00918     {
00919       QString drvName = OGR_Dr_GetName( drv );
00920       if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
00921       {
00922         QString filterString = filterForDriver( drvName );
00923         if ( filterString.isEmpty() )
00924           continue;
00925 
00926         resultMap.insert( filterString, drvName );
00927       }
00928     }
00929   }
00930 
00931   return resultMap;
00932 }
00933 
00934 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
00935 {
00936   QMap<QString, QString> resultMap;
00937 
00938   QgsApplication::registerOgrDrivers();
00939   int const drvCount = OGRGetDriverCount();
00940 
00941   QStringList writableDrivers;
00942   for ( int i = 0; i < drvCount; ++i )
00943   {
00944     OGRSFDriverH drv = OGRGetDriver( i );
00945     if ( drv )
00946     {
00947       QString drvName = OGR_Dr_GetName( drv );
00948       if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
00949       {
00950         // Add separate format for Mapinfo MIF (MITAB is OGR default)
00951         if ( drvName == "MapInfo File" )
00952         {
00953           writableDrivers << "MapInfo MIF";
00954         }
00955         else if ( drvName == "SQLite" )
00956         {
00957           // Unfortunately it seems that there is no simple way to detect if
00958           // OGR SQLite driver is compiled with SpatiaLite support.
00959           // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
00960           // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
00961           // -> test if creation failes
00962           QString option = "SPATIALITE=YES";
00963           char **options =  new char *[2];
00964           options[0] = CPLStrdup( option.toLocal8Bit().data() );
00965           options[1] = NULL;
00966           OGRSFDriverH poDriver;
00967           QgsApplication::registerOgrDrivers();
00968           poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() );
00969           if ( poDriver )
00970           {
00971             OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8( QString( "/vsimem/spatialitetest.sqlite" ) ), options );
00972             if ( ds )
00973             {
00974               writableDrivers << "SpatiaLite";
00975               OGR_DS_Destroy( ds );
00976             }
00977           }
00978           CPLFree( options[0] );
00979           delete [] options;
00980         }
00981         writableDrivers << drvName;
00982       }
00983     }
00984   }
00985 
00986   foreach ( QString drvName, writableDrivers )
00987   {
00988     QString longName;
00989     QString trLongName;
00990     QString glob;
00991     QString exts;
00992     if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() )
00993     {
00994       resultMap.insert( trLongName, drvName );
00995     }
00996   }
00997 
00998   return resultMap;
00999 }
01000 
01001 QString QgsVectorFileWriter::fileFilterString()
01002 {
01003   QString filterString;
01004   QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats();
01005   QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
01006   for ( ; it != driverFormatMap.constEnd(); ++it )
01007   {
01008     if ( filterString.isEmpty() )
01009       filterString += ";;";
01010 
01011     filterString += it.key();
01012   }
01013   return filterString;
01014 }
01015 
01016 QString QgsVectorFileWriter::filterForDriver( const QString& driverName )
01017 {
01018   QString longName;
01019   QString trLongName;
01020   QString glob;
01021   QString exts;
01022   if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() )
01023     return "";
01024 
01025   return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")";
01026 }
01027 
01028 QString QgsVectorFileWriter::convertCodecNameForEncodingOption( const QString &codecName )
01029 {
01030   if ( codecName == "System" )
01031     return QString( "LDID/0" );
01032 
01033   QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
01034   if ( re.exactMatch( codecName ) )
01035   {
01036     QString c = re.cap( 2 ).replace( "-" , "" );
01037     bool isNumber;
01038     c.toInt( &isNumber );
01039     if ( isNumber )
01040       return c;
01041   }
01042   return codecName;
01043 }
01044 
01045 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext )
01046 {
01047   if ( driverName.startsWith( "AVCE00" ) )
01048   {
01049     longName = "Arc/Info ASCII Coverage";
01050     trLongName = QObject::tr( "Arc/Info ASCII Coverage" );
01051     glob = "*.e00";
01052     ext = "e00";
01053   }
01054   else if ( driverName.startsWith( "BNA" ) )
01055   {
01056     longName = "Atlas BNA";
01057     trLongName = QObject::tr( "Atlas BNA" );
01058     glob = "*.bna";
01059     ext = "bna";
01060   }
01061   else if ( driverName.startsWith( "CSV" ) )
01062   {
01063     longName = "Comma Separated Value";
01064     trLongName = QObject::tr( "Comma Separated Value" );
01065     glob = "*.csv";
01066     ext = "csv";
01067   }
01068   else if ( driverName.startsWith( "ESRI" ) )
01069   {
01070     longName = "ESRI Shapefile";
01071     trLongName = QObject::tr( "ESRI Shapefile" );
01072     glob = "*.shp";
01073     ext = "shp";
01074   }
01075   else if ( driverName.startsWith( "FMEObjects Gateway" ) )
01076   {
01077     longName = "FMEObjects Gateway";
01078     trLongName = QObject::tr( "FMEObjects Gateway" );
01079     glob = "*.fdd";
01080     ext = "fdd";
01081   }
01082   else if ( driverName.startsWith( "GeoJSON" ) )
01083   {
01084     longName = "GeoJSON";
01085     trLongName = QObject::tr( "GeoJSON" );
01086     glob = "*.geojson";
01087     ext = "geojson";
01088   }
01089   else if ( driverName.startsWith( "GeoRSS" ) )
01090   {
01091     longName = "GeoRSS";
01092     trLongName = QObject::tr( "GeoRSS" );
01093     glob = "*.xml";
01094     ext = "xml";
01095   }
01096   else if ( driverName.startsWith( "GML" ) )
01097   {
01098     longName = "Geography Markup Language [GML]";
01099     trLongName = QObject::tr( "Geography Markup Language [GML]" );
01100     glob = "*.gml";
01101     ext = "gml";
01102   }
01103   else if ( driverName.startsWith( "GMT" ) )
01104   {
01105     longName = "Generic Mapping Tools [GMT]";
01106     trLongName = QObject::tr( "Generic Mapping Tools [GMT]" );
01107     glob = "*.gmt";
01108     ext = "gmt";
01109   }
01110   else if ( driverName.startsWith( "GPX" ) )
01111   {
01112     longName = "GPS eXchange Format [GPX]";
01113     trLongName = QObject::tr( "GPS eXchange Format [GPX]" );
01114     glob = "*.gpx";
01115     ext = "gpx";
01116   }
01117   else if ( driverName.startsWith( "Interlis 1" ) )
01118   {
01119     longName = "INTERLIS 1";
01120     trLongName = QObject::tr( "INTERLIS 1" );
01121     glob = "*.itf *.xml *.ili";
01122     ext = "ili";
01123   }
01124   else if ( driverName.startsWith( "Interlis 2" ) )
01125   {
01126     longName = "INTERLIS 2";
01127     trLongName = QObject::tr( "INTERLIS 2" );
01128     glob = "*.itf *.xml *.ili";
01129     ext = "ili";
01130   }
01131   else if ( driverName.startsWith( "KML" ) )
01132   {
01133     longName = "Keyhole Markup Language [KML]";
01134     trLongName = QObject::tr( "Keyhole Markup Language [KML]" );
01135     glob = "*.kml" ;
01136     ext = "kml" ;
01137   }
01138   else if ( driverName.startsWith( "MapInfo File" ) )
01139   {
01140     longName = "Mapinfo TAB";
01141     trLongName = QObject::tr( "Mapinfo TAB" );
01142     glob = "*.tab";
01143     ext = "tab";
01144   }
01145   // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF
01146   else if ( driverName.startsWith( "MapInfo MIF" ) )
01147   {
01148     longName = "Mapinfo MIF";
01149     trLongName = QObject::tr( "Mapinfo MIF" );
01150     glob = "*.mif";
01151     ext = "mif";
01152   }
01153   else if ( driverName.startsWith( "DGN" ) )
01154   {
01155     longName = "Microstation DGN";
01156     trLongName = QObject::tr( "Microstation DGN" );
01157     glob = "*.dgn";
01158     ext = "dgn";
01159   }
01160   else if ( driverName.startsWith( "S57" ) )
01161   {
01162     longName = "S-57 Base file";
01163     trLongName = QObject::tr( "S-57 Base file" );
01164     glob = "*.000";
01165     ext = "000";
01166   }
01167   else if ( driverName.startsWith( "SDTS" ) )
01168   {
01169     longName = "Spatial Data Transfer Standard [SDTS]";
01170     trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" );
01171     glob = "*catd.ddf";
01172     ext = "ddf";
01173   }
01174   else if ( driverName.startsWith( "SQLite" ) )
01175   {
01176     longName = "SQLite";
01177     trLongName = QObject::tr( "SQLite" );
01178     glob = "*.sqlite";
01179     ext = "sqlite";
01180   }
01181   // QGIS internal addition for SpatialLite
01182   else if ( driverName.startsWith( "SpatiaLite" ) )
01183   {
01184     longName = "SpatiaLite";
01185     trLongName = QObject::tr( "SpatiaLite" );
01186     glob = "*.sqlite";
01187     ext = "sqlite";
01188   }
01189   else if ( driverName.startsWith( "DXF" ) )
01190   {
01191     longName = "AutoCAD DXF";
01192     trLongName = QObject::tr( "AutoCAD DXF" );
01193     glob = "*.dxf";
01194     ext = "dxf";
01195   }
01196   else if ( driverName.startsWith( "Geoconcept" ) )
01197   {
01198     longName = "Geoconcept";
01199     trLongName = QObject::tr( "Geoconcept" );
01200     glob = "*.gxt *.txt";
01201     ext = "gxt";
01202   }
01203   else if ( driverName.startsWith( "FileGDB" ) )
01204   {
01205     longName = "ESRI FileGDB";
01206     trLongName = QObject::tr( "ESRI FileGDB" );
01207     glob = "*.gdb";
01208     ext = "gdb";
01209   }
01210   else
01211   {
01212     return false;
01213   }
01214 
01215   return true;
01216 }
01217 
01218 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl,  const QgsCoordinateTransform* ct, OGRDataSourceH ds )
01219 {
01220   if ( !vl || !ds )
01221   {
01222     return;
01223   }
01224 
01225   QgsFeatureRendererV2* renderer = vl->rendererV2();
01226   if ( !renderer )
01227   {
01228     return;
01229   }
01230 
01231   //unit type
01232   QGis::UnitType mapUnits = vl->crs().mapUnits();
01233   if ( ct )
01234   {
01235     mapUnits = ct->destCRS().mapUnits();
01236   }
01237 
01238 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700
01239   mSymbolLayerTable.clear();
01240   OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
01241   OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
01242 
01243   //get symbols
01244   int nTotalLevels = 0;
01245   QgsSymbolV2List symbolList = renderer->symbols();
01246   QgsSymbolV2List::iterator symbolIt = symbolList.begin();
01247   for ( ; symbolIt != symbolList.end(); ++symbolIt )
01248   {
01249     double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
01250     double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
01251 
01252     int nLevels = ( *symbolIt )->symbolLayerCount();
01253     for ( int i = 0; i < nLevels; ++i )
01254     {
01255       mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
01256       OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
01257                        ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
01258       ++nTotalLevels;
01259     }
01260   }
01261   OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
01262 #endif
01263 }
01264 
01265 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit,
01266     const QgsCoordinateTransform* ct, QString* errorMessage )
01267 {
01268   if ( !layer )
01269   {
01270     //return error
01271   }
01272   QgsFeatureRendererV2* renderer = layer->rendererV2();
01273   if ( !renderer )
01274   {
01275     //return error
01276   }
01277   QHash< QgsSymbolV2*, QList<QgsFeature> > features;
01278 
01279   //unit type
01280   QGis::UnitType mapUnits = layer->crs().mapUnits();
01281   if ( ct )
01282   {
01283     mapUnits = ct->destCRS().mapUnits();
01284   }
01285 
01286   startRender( layer );
01287 
01288   //fetch features
01289   QgsFeature fet;
01290   QgsSymbolV2* featureSymbol = 0;
01291   while ( fit.nextFeature( fet ) )
01292   {
01293     if ( ct )
01294     {
01295       try
01296       {
01297         if ( fet.geometry() )
01298         {
01299           fet.geometry()->transform( *ct );
01300         }
01301       }
01302       catch ( QgsCsException &e )
01303       {
01304         delete ct;
01305 
01306         QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
01307                       .arg( e.what() );
01308         QgsLogger::warning( msg );
01309         if ( errorMessage )
01310           *errorMessage = msg;
01311 
01312         return ErrProjection;
01313       }
01314     }
01315 
01316     featureSymbol = renderer->symbolForFeature( fet );
01317     if ( !featureSymbol )
01318     {
01319       continue;
01320     }
01321 
01322     QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
01323     if ( it == features.end() )
01324     {
01325       it = features.insert( featureSymbol, QList<QgsFeature>() );
01326     }
01327     it.value().append( fet );
01328   }
01329 
01330   //find out order
01331   QgsSymbolV2LevelOrder levels;
01332   QgsSymbolV2List symbols = renderer->symbols();
01333   for ( int i = 0; i < symbols.count(); i++ )
01334   {
01335     QgsSymbolV2* sym = symbols[i];
01336     for ( int j = 0; j < sym->symbolLayerCount(); j++ )
01337     {
01338       int level = sym->symbolLayer( j )->renderingPass();
01339       if ( level < 0 || level >= 1000 ) // ignore invalid levels
01340         continue;
01341       QgsSymbolV2LevelItem item( sym, j );
01342       while ( level >= levels.count() ) // append new empty levels
01343         levels.append( QgsSymbolV2Level() );
01344       levels[level].append( item );
01345     }
01346   }
01347 
01348   int nErrors = 0;
01349   int nTotalFeatures = 0;
01350 
01351   //export symbol layers and symbology
01352   for ( int l = 0; l < levels.count(); l++ )
01353   {
01354     QgsSymbolV2Level& level = levels[l];
01355     for ( int i = 0; i < level.count(); i++ )
01356     {
01357       QgsSymbolV2LevelItem& item = level[i];
01358       QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
01359       if ( levelIt == features.end() )
01360       {
01361         ++nErrors;
01362         continue;
01363       }
01364 
01365       double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
01366       double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
01367 
01368       int llayer = item.layer();
01369       QList<QgsFeature>& featureList = levelIt.value();
01370       QList<QgsFeature>::iterator featureIt = featureList.begin();
01371       for ( ; featureIt != featureList.end(); ++featureIt )
01372       {
01373         ++nTotalFeatures;
01374         OGRFeatureH ogrFeature = createFeature( *featureIt );
01375         if ( !ogrFeature )
01376         {
01377           ++nErrors;
01378           continue;
01379         }
01380 
01381         QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
01382         if ( !styleString.isEmpty() )
01383         {
01384           OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
01385           if ( ! writeFeature( mLayer, ogrFeature ) )
01386           {
01387             ++nErrors;
01388           }
01389         }
01390         OGR_F_Destroy( ogrFeature );
01391       }
01392     }
01393   }
01394 
01395   stopRender( layer );
01396 
01397   if ( nErrors > 0 && errorMessage )
01398   {
01399     *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
01400   }
01401 
01402   return ( nErrors > 0 ) ? QgsVectorFileWriter::ErrFeatureWriteFailed : QgsVectorFileWriter::NoError;
01403 }
01404 
01405 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
01406 {
01407   if ( symbolUnits == QgsSymbolV2::MM )
01408   {
01409     return 1.0;
01410   }
01411   else
01412   {
01413     //conversion factor map units -> mm
01414     if ( mapUnits == QGis::Meters )
01415     {
01416       return 1000 / scaleDenominator;
01417     }
01418 
01419   }
01420   return 1.0; //todo: map units
01421 }
01422 
01423 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
01424 {
01425   if ( symbolUnits == QgsSymbolV2::MapUnit )
01426   {
01427     return 1.0;
01428   }
01429   else
01430   {
01431     if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
01432     {
01433       return scaleDenominator / 1000;
01434     }
01435   }
01436   return 1.0;
01437 }
01438 
01439 QgsRenderContext QgsVectorFileWriter::renderContext() const
01440 {
01441   QgsRenderContext context;
01442   context.setRendererScale( mSymbologyScaleDenominator );
01443   return context;
01444 }
01445 
01446 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl ) const
01447 {
01448   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01449   if ( !renderer )
01450   {
01451     return;
01452   }
01453 
01454   QgsRenderContext ctx = renderContext();
01455   renderer->startRender( ctx, vl );
01456 }
01457 
01458 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl ) const
01459 {
01460   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01461   if ( !renderer )
01462   {
01463     return;
01464   }
01465 
01466   QgsRenderContext ctx = renderContext();
01467   renderer->stopRender( ctx );
01468 }
01469 
01470 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const
01471 {
01472   if ( mSymbologyExport == NoSymbology )
01473   {
01474     return 0;
01475   }
01476   if ( !vl )
01477   {
01478     return 0;
01479   }
01480 
01481   return vl->rendererV2();
01482 }
01483 
01484 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList )
01485 {
01486   QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
01487   if ( renderer )
01488   {
01489     QList<QString> rendererAttributes = renderer->usedAttributes();
01490     for ( int i = 0; i < rendererAttributes.size(); ++i )
01491     {
01492       int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
01493       if ( index != -1 )
01494       {
01495         attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
01496       }
01497     }
01498   }
01499 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines