QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsvectorfilewriter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorfilewriter.cpp
3  generic vector file writer
4  -------------------
5  begin : Sat Jun 16 2004
6  copyright : (C) 2004 by Tim Sutton
7  email : tim at linfiniti.com
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "qgsapplication.h"
20 #include "qgsfield.h"
21 #include "qgsfeature.h"
22 #include "qgsgeometry.h"
23 #include "qgslogger.h"
24 #include "qgsmessagelog.h"
26 #include "qgsvectorfilewriter.h"
27 #include "qgsrendererv2.h"
28 #include "qgssymbollayerv2.h"
29 
30 #include <QFile>
31 #include <QSettings>
32 #include <QFileInfo>
33 #include <QDir>
34 #include <QTextCodec>
35 #include <QTextStream>
36 #include <QSet>
37 #include <QMetaType>
38 
39 #include <cassert>
40 #include <cstdlib> // size_t
41 #include <limits> // std::numeric_limits
42 
43 #include <ogr_srs_api.h>
44 #include <cpl_error.h>
45 #include <cpl_conv.h>
46 
47 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
48 #define TO8(x) (x).toUtf8().constData()
49 #define TO8F(x) (x).toUtf8().constData()
50 #else
51 #define TO8(x) (x).toLocal8Bit().constData()
52 #define TO8F(x) QFile::encodeName( x ).constData()
53 #endif
54 
55 
57  const QString &theVectorFileName,
58  const QString &theFileEncoding,
59  const QgsFields& fields,
60  QGis::WkbType geometryType,
62  const QString& driverName,
63  const QStringList &datasourceOptions,
64  const QStringList &layerOptions,
65  QString *newFilename,
66  SymbologyExport symbologyExport
67 )
68  : mDS( NULL )
69  , mLayer( NULL )
70  , mGeom( NULL )
71  , mError( NoError )
72  , mSymbologyExport( symbologyExport )
73 {
74  QString vectorFileName = theVectorFileName;
75  QString fileEncoding = theFileEncoding;
76  QStringList layOptions = layerOptions;
77  QStringList dsOptions = datasourceOptions;
78 
79  QString ogrDriverName;
80  if ( driverName == "MapInfo MIF" )
81  {
82  ogrDriverName = "MapInfo File";
83  }
84  else if ( driverName == "SpatiaLite" )
85  {
86  ogrDriverName = "SQLite";
87  if ( !dsOptions.contains( "SPATIALITE=YES" ) )
88  {
89  dsOptions.append( "SPATIALITE=YES" );
90  }
91  }
92  else if ( driverName == "DBF file" )
93  {
94  ogrDriverName = "ESRI Shapefile";
95  if ( !layOptions.contains( "SHPT=NULL" ) )
96  {
97  layOptions.append( "SHPT=NULL" );
98  }
99  srs = 0;
100  }
101  else
102  {
103  ogrDriverName = driverName;
104  }
105 
106  // find driver in OGR
107  OGRSFDriverH poDriver;
109 
110  poDriver = OGRGetDriverByName( ogrDriverName.toLocal8Bit().data() );
111 
112  if ( poDriver == NULL )
113  {
114  mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" )
115  .arg( driverName )
116  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
118  return;
119  }
120 
121  if ( ogrDriverName == "ESRI Shapefile" )
122  {
123  if ( layOptions.join( "" ).toUpper().indexOf( "ENCODING=" ) == -1 )
124  {
125  layOptions.append( "ENCODING=" + convertCodecNameForEncodingOption( fileEncoding ) );
126  }
127 
128  if ( driverName == "ESRI Shapefile" && !vectorFileName.endsWith( ".shp", Qt::CaseInsensitive ) )
129  {
130  vectorFileName += ".shp";
131  }
132  else if ( driverName == "DBF file" && !vectorFileName.endsWith( ".dbf", Qt::CaseInsensitive ) )
133  {
134  vectorFileName += ".dbf";
135  }
136 
137 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
138  // check for unique fieldnames
139  QSet<QString> fieldNames;
140  for ( int i = 0; i < fields.count(); ++i )
141  {
142  QString name = fields[i].name().left( 10 );
143  if ( fieldNames.contains( name ) )
144  {
145  mErrorMessage = QObject::tr( "trimming attribute name '%1' to ten significant characters produces duplicate column name." )
146  .arg( fields[i].name() );
148  return;
149  }
150  fieldNames << name;
151  }
152 #endif
153 
154  deleteShapeFile( vectorFileName );
155  }
156  else if ( driverName == "KML" )
157  {
158  if ( !vectorFileName.endsWith( ".kml", Qt::CaseInsensitive ) )
159  {
160  vectorFileName += ".kml";
161  }
162 
163  if ( fileEncoding.compare( "UTF-8", Qt::CaseInsensitive ) != 0 )
164  {
165  QgsDebugMsg( "forced UTF-8 encoding for KML" );
166  fileEncoding = "UTF-8";
167  }
168 
169  QFile::remove( vectorFileName );
170  }
171  else
172  {
173  QString longName;
174  QString trLongName;
175  QString glob;
176  QString exts;
177  if ( QgsVectorFileWriter::driverMetadata( driverName, longName, trLongName, glob, exts ) )
178  {
179  QStringList allExts = exts.split( " ", QString::SkipEmptyParts );
180  bool found = false;
181  foreach ( QString ext, allExts )
182  {
183  if ( vectorFileName.endsWith( "." + ext, Qt::CaseInsensitive ) )
184  {
185  found = true;
186  break;
187  }
188  }
189 
190  if ( !found )
191  {
192  vectorFileName += "." + allExts[0];
193  }
194  }
195 
196  QFile::remove( vectorFileName );
197  }
198 
199  char **options = NULL;
200  if ( !dsOptions.isEmpty() )
201  {
202  options = new char *[ dsOptions.size()+1 ];
203  for ( int i = 0; i < dsOptions.size(); i++ )
204  {
205  options[i] = CPLStrdup( dsOptions[i].toLocal8Bit().data() );
206  }
207  options[ dsOptions.size()] = NULL;
208  }
209 
210  // create the data source
211  mDS = OGR_Dr_CreateDataSource( poDriver, TO8F( vectorFileName ), options );
212 
213  if ( options )
214  {
215  for ( int i = 0; i < dsOptions.size(); i++ )
216  CPLFree( options[i] );
217  delete [] options;
218  options = NULL;
219  }
220 
221  if ( mDS == NULL )
222  {
224  mErrorMessage = QObject::tr( "creation of data source failed (OGR error:%1)" )
225  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
226  return;
227  }
228 
229  QgsDebugMsg( "Created data source" );
230 
231  // use appropriate codec
232  mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
233  if ( !mCodec )
234  {
235  QgsDebugMsg( "error finding QTextCodec for " + fileEncoding );
236 
237  QSettings settings;
238  QString enc = settings.value( "/UI/encoding", "System" ).toString();
239  mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
240  if ( !mCodec )
241  {
242  QgsDebugMsg( "error finding QTextCodec for " + enc );
243  mCodec = QTextCodec::codecForLocale();
244  Q_ASSERT( mCodec );
245  }
246  }
247 
248  // consider spatial reference system of the layer
249  OGRSpatialReferenceH ogrRef = NULL;
250  if ( srs )
251  {
252  QString srsWkt = srs->toWkt();
253  QgsDebugMsg( "WKT to save as is " + srsWkt );
254  ogrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() );
255  }
256 
257  // datasource created, now create the output layer
258  QString layerName = QFileInfo( vectorFileName ).baseName();
259  OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( geometryType );
260 
261  if ( !layOptions.isEmpty() )
262  {
263  options = new char *[ layOptions.size()+1 ];
264  for ( int i = 0; i < layOptions.size(); i++ )
265  {
266  options[i] = CPLStrdup( layOptions[i].toLocal8Bit().data() );
267  }
268  options[ layOptions.size()] = NULL;
269  }
270 
271  // disable encoding conversion of OGR Shapefile layer
272  CPLSetConfigOption( "SHAPE_ENCODING", "" );
273 
274  mLayer = OGR_DS_CreateLayer( mDS, TO8F( layerName ), ogrRef, wkbType, options );
275 
276  if ( options )
277  {
278  for ( int i = 0; i < layOptions.size(); i++ )
279  CPLFree( options[i] );
280  delete [] options;
281  options = NULL;
282  }
283 
284  QSettings settings;
285  if ( !settings.value( "/qgis/ignoreShapeEncoding", true ).toBool() )
286  {
287  CPLSetConfigOption( "SHAPE_ENCODING", 0 );
288  }
289 
290  if ( srs )
291  {
292  if ( ogrDriverName == "ESRI Shapefile" )
293  {
294  QString layerName = vectorFileName.left( vectorFileName.indexOf( ".shp", Qt::CaseInsensitive ) );
295  QFile prjFile( layerName + ".qpj" );
296  if ( prjFile.open( QIODevice::WriteOnly ) )
297  {
298  QTextStream prjStream( &prjFile );
299  prjStream << srs->toWkt().toLocal8Bit().data() << endl;
300  prjFile.close();
301  }
302  else
303  {
304  QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" );
305  }
306  }
307 
308  OSRDestroySpatialReference( ogrRef );
309  }
310 
311  if ( mLayer == NULL )
312  {
313  mErrorMessage = QObject::tr( "creation of layer failed (OGR error:%1)" )
314  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
316  return;
317  }
318 
319  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer );
320 
321  QgsDebugMsg( "created layer" );
322 
323  // create the fields
324  QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" );
325 
326  mFields = fields;
327  mAttrIdxToOgrIdx.clear();
328 
329  for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
330  {
331  const QgsField& attrField = fields[fldIdx];
332 
333  OGRFieldType ogrType = OFTString; //default to string
334  int ogrWidth = attrField.length();
335  int ogrPrecision = attrField.precision();
336  switch ( attrField.type() )
337  {
338  case QVariant::LongLong:
339  ogrType = OFTString;
340  ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21;
341  ogrPrecision = -1;
342  break;
343 
344  case QVariant::String:
345  ogrType = OFTString;
346  if ( ogrWidth <= 0 || ogrWidth > 255 )
347  ogrWidth = 255;
348  break;
349 
350  case QVariant::Int:
351  ogrType = OFTInteger;
352  ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
353  ogrPrecision = 0;
354  break;
355 
356  case QVariant::Double:
357  ogrType = OFTReal;
358  break;
359 
360  case QVariant::Date:
361  ogrType = OFTDate;
362  break;
363 
364  case QVariant::DateTime:
365  ogrType = OFTDateTime;
366  break;
367 
368  default:
369  //assert(0 && "invalid variant type!");
370  mErrorMessage = QObject::tr( "unsupported type for field %1" )
371  .arg( attrField.name() );
373  return;
374  }
375 
376  QString name( attrField.name() );
377 
378  if ( ogrDriverName == "SQLite" && name.compare( "ogc_fid", Qt::CaseInsensitive ) == 0 )
379  {
380  int i;
381  for ( i = 0; i < 10; i++ )
382  {
383  name = QString( "ogc_fid%1" ).arg( i );
384 
385  int j;
386  for ( j = 0; j < fields.size() && name.compare( fields[j].name(), Qt::CaseInsensitive ) != 0; j++ )
387  ;
388 
389  if ( j == fields.size() )
390  break;
391  }
392 
393  if ( i == 10 )
394  {
395  mErrorMessage = QObject::tr( "no available replacement for internal fieldname ogc_fid found" ).arg( attrField.name() );
397  return;
398  }
399 
400  QgsMessageLog::logMessage( QObject::tr( "Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr( "OGR" ) );
401  }
402 
403  // create field definition
404  OGRFieldDefnH fld = OGR_Fld_Create( mCodec->fromUnicode( name ), ogrType );
405  if ( ogrWidth > 0 )
406  {
407  OGR_Fld_SetWidth( fld, ogrWidth );
408  }
409 
410  if ( ogrPrecision >= 0 )
411  {
412  OGR_Fld_SetPrecision( fld, ogrPrecision );
413  }
414 
415  // create the field
416  QgsDebugMsg( "creating field " + attrField.name() +
417  " type " + QString( QVariant::typeToName( attrField.type() ) ) +
418  " width " + QString::number( ogrWidth ) +
419  " precision " + QString::number( ogrPrecision ) );
420  if ( OGR_L_CreateField( mLayer, fld, true ) != OGRERR_NONE )
421  {
422  QgsDebugMsg( "error creating field " + attrField.name() );
423  mErrorMessage = QObject::tr( "creation of field %1 failed (OGR error: %2)" )
424  .arg( attrField.name() )
425  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
427  OGR_Fld_Destroy( fld );
428  return;
429  }
430  OGR_Fld_Destroy( fld );
431 
432  int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
433  if ( ogrIdx < 0 )
434  {
435 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
436  // if we didn't find our new column, assume it's name was truncated and
437  // it was the last one added (like for shape files)
438  int fieldCount = OGR_FD_GetFieldCount( defn );
439 
440  OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 );
441  if ( fdefn )
442  {
443  const char *fieldName = OGR_Fld_GetNameRef( fdefn );
444 
445  if ( attrField.name().left( strlen( fieldName ) ) == fieldName )
446  {
447  ogrIdx = fieldCount - 1;
448  }
449  }
450 #else
451  // GDAL 1.7 not just truncates, but launders more aggressivly.
452  ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
453 #endif
454 
455  if ( ogrIdx < 0 )
456  {
457  QgsDebugMsg( "error creating field " + attrField.name() );
458  mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" )
459  .arg( attrField.name() )
460  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
462  return;
463  }
464  }
465 
466  mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
467  }
468 
469  QgsDebugMsg( "Done creating fields" );
470 
471  mWkbType = geometryType;
472  if ( mWkbType != QGis::WKBNoGeometry )
473  {
474  // create geometry which will be used for import
476  }
477 
478  if ( newFilename )
479  *newFilename = vectorFileName;
480 }
481 
483 {
484  return OGR_G_CreateGeometry(( OGRwkbGeometryType ) wkbType );
485 }
486 
487 
489 {
490  return mError;
491 }
492 
494 {
495  return mErrorMessage;
496 }
497 
499 {
500  // create the feature
501  OGRFeatureH poFeature = createFeature( feature );
502 
503  //add OGR feature style type
504  if ( mSymbologyExport != NoSymbology && renderer )
505  {
506  //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
507  QgsSymbolV2List symbols = renderer->symbolsForFeature( feature );
508  QString styleString;
509  QString currentStyle;
510 
511  QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin();
512  for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
513  {
514  int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
515  for ( int i = 0; i < nSymbolLayers; ++i )
516  {
517 #if 0
518  QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) );
519  if ( it == mSymbolLayerTable.constEnd() )
520  {
521  continue;
522  }
523 #endif
524  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
525  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
526 
527  currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
528 
530  {
531  if ( symbolIt != symbols.constBegin() || i != 0 )
532  {
533  styleString.append( ";" );
534  }
535  styleString.append( currentStyle );
536  }
538  {
539  OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() );
540  if ( !writeFeature( mLayer, poFeature ) )
541  {
542  return false;
543  }
544  }
545  }
546  }
547  OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() );
548  }
549 
551  {
552  if ( !writeFeature( mLayer, poFeature ) )
553  {
554  return false;
555  }
556  }
557 
558  OGR_F_Destroy( poFeature );
559  return true;
560 }
561 
563 {
564  OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) );
565 
566  qint64 fid = FID_TO_NUMBER( feature.id() );
567  if ( fid > std::numeric_limits<int>::max() )
568  {
569  QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
570  OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
571  if ( err != OGRERR_NONE )
572  {
573  QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
574  .arg( feature.id() )
575  .arg( err ).arg( CPLGetLastErrorMsg() )
576  );
577  }
578  }
579 
580  // attribute handling
581  for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx )
582  {
583  if ( !mAttrIdxToOgrIdx.contains( fldIdx ) )
584  {
585  QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) );
586  continue;
587  }
588 
589  const QVariant& attrValue = feature.attribute( fldIdx );
590  int ogrField = mAttrIdxToOgrIdx[ fldIdx ];
591 
592  if ( !attrValue.isValid() || attrValue.isNull() )
593  continue;
594 
595  switch ( attrValue.type() )
596  {
597  case QVariant::Int:
598  OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
599  break;
600  case QVariant::Double:
601  OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() );
602  break;
603  case QVariant::LongLong:
604  case QVariant::String:
605  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
606  break;
607  case QVariant::Date:
608  OGR_F_SetFieldDateTime( poFeature, ogrField,
609  attrValue.toDate().year(),
610  attrValue.toDate().month(),
611  attrValue.toDate().day(),
612  0, 0, 0, 0 );
613  break;
614  case QVariant::DateTime:
615  OGR_F_SetFieldDateTime( poFeature, ogrField,
616  attrValue.toDateTime().date().year(),
617  attrValue.toDateTime().date().month(),
618  attrValue.toDateTime().date().day(),
619  attrValue.toDateTime().time().hour(),
620  attrValue.toDateTime().time().minute(),
621  attrValue.toDateTime().time().second(),
622  0 );
623  break;
624  case QVariant::Invalid:
625  break;
626  default:
627  mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
628  .arg( mFields[fldIdx].name() )
629  .arg( ogrField )
630  .arg( QMetaType::typeName( attrValue.type() ) )
631  .arg( attrValue.toString() );
634  return 0;
635  }
636  }
637 
638  if ( mWkbType != QGis::WKBNoGeometry )
639  {
640  // build geometry from WKB
641  QgsGeometry *geom = feature.geometry();
642 
643  // turn single geoemetry to multi geometry if needed
644  if ( geom && geom->wkbType() != mWkbType && geom->wkbType() == QGis::singleType( mWkbType ) )
645  {
646  geom->convertToMultiType();
647  }
648 
649  if ( geom && geom->wkbType() != mWkbType )
650  {
651  // there's a problem when layer type is set as wkbtype Polygon
652  // although there are also features of type MultiPolygon
653  // (at least in OGR provider)
654  // If the feature's wkbtype is different from the layer's wkbtype,
655  // try to export it too.
656  //
657  // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
658  // i.e. Polygons can't be imported to OGRMultiPolygon
659 
660  OGRGeometryH mGeom2 = createEmptyGeometry( geom->wkbType() );
661 
662  if ( !mGeom2 )
663  {
664  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
665  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
668  OGR_F_Destroy( poFeature );
669  return 0;
670  }
671 
672  OGRErr err = OGR_G_ImportFromWkb( mGeom2, const_cast<unsigned char *>( geom->asWkb() ), geom->wkbSize() );
673  if ( err != OGRERR_NONE )
674  {
675  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
676  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
679  OGR_F_Destroy( poFeature );
680  return 0;
681  }
682 
683  // pass ownership to geometry
684  OGR_F_SetGeometryDirectly( poFeature, mGeom2 );
685  }
686  else if ( geom )
687  {
688  OGRErr err = OGR_G_ImportFromWkb( mGeom, const_cast<unsigned char *>( geom->asWkb() ), geom->wkbSize() );
689  if ( err != OGRERR_NONE )
690  {
691  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
692  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
695  OGR_F_Destroy( poFeature );
696  return 0;
697  }
698 
699  // set geometry (ownership is not passed to OGR)
700  OGR_F_SetGeometry( poFeature, mGeom );
701  }
702  }
703  return poFeature;
704 }
705 
706 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
707 {
708  if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
709  {
710  mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
713  OGR_F_Destroy( feature );
714  return false;
715  }
716  return true;
717 }
718 
720 {
721  if ( mGeom )
722  {
723  OGR_G_DestroyGeometry( mGeom );
724  }
725 
726  if ( mDS )
727  {
728  OGR_DS_Destroy( mDS );
729  }
730 }
731 
734  const QString& fileName,
735  const QString& fileEncoding,
736  const QgsCoordinateReferenceSystem *destCRS,
737  const QString& driverName,
738  bool onlySelected,
739  QString *errorMessage,
740  const QStringList &datasourceOptions,
741  const QStringList &layerOptions,
742  bool skipAttributeCreation,
743  QString *newFilename,
744  SymbologyExport symbologyExport,
745  double symbologyScale )
746 {
747  QgsDebugMsg( "fileName = " + fileName );
748  const QgsCoordinateReferenceSystem* outputCRS;
749  QgsCoordinateTransform* ct = 0;
750  int shallTransform = false;
751 
752  if ( !layer )
753  {
754  return ErrInvalidLayer;
755  }
756 
757  if ( destCRS && destCRS->isValid() )
758  {
759  // This means we should transform
760  outputCRS = destCRS;
761  shallTransform = true;
762  }
763  else
764  {
765  // This means we shouldn't transform, use source CRS as output (if defined)
766  outputCRS = &layer->crs();
767  }
768  QgsVectorFileWriter* writer =
769  new QgsVectorFileWriter( fileName, fileEncoding, skipAttributeCreation ? QgsFields() : layer->pendingFields(), layer->wkbType(), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
770  writer->setSymbologyScaleDenominator( symbologyScale );
771 
772  if ( newFilename )
773  {
774  QgsDebugMsg( "newFilename = " + *newFilename );
775  }
776 
777  // check whether file creation was successful
778  WriterError err = writer->hasError();
779  if ( err != NoError )
780  {
781  if ( errorMessage )
782  *errorMessage = writer->errorMessage();
783  delete writer;
784  return err;
785  }
786 
787  if ( errorMessage )
788  {
789  errorMessage->clear();
790  }
791 
792  QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->pendingAllAttributesList();
793  QgsFeature fet;
794 
795  //add possible attributes needed by renderer
796  writer->addRendererAttributes( layer, allAttr );
797 
798  QgsFeatureRequest req;
799  if ( layer->wkbType() == QGis::WKBNoGeometry )
800  {
802  }
803  req.setSubsetOfAttributes( allAttr );
804  QgsFeatureIterator fit = layer->getFeatures( req );
805 
806  const QgsFeatureIds& ids = layer->selectedFeaturesIds();
807 
808  // Create our transform
809  if ( destCRS )
810  {
811  ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
812  }
813 
814  // Check for failure
815  if ( ct == NULL )
816  {
817  shallTransform = false;
818  }
819 
820  //create symbol table if needed
821  if ( writer->symbologyExport() != NoSymbology )
822  {
823  //writer->createSymbolLayerTable( layer, writer->mDS );
824  }
825 
826  if ( writer->symbologyExport() == SymbolLayerSymbology )
827  {
828  QgsFeatureRendererV2* r = layer->rendererV2();
830  && r->usingSymbolLevels() )
831  {
832  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
833  delete writer;
834  delete ct;
835  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
836  }
837  }
838 
839  int n = 0, errors = 0;
840 
841  //unit type
842  QGis::UnitType mapUnits = layer->crs().mapUnits();
843  if ( ct )
844  {
845  mapUnits = ct->destCRS().mapUnits();
846  }
847 
848  writer->startRender( layer );
849 
850  // enabling transaction on databases that support it
851  bool transactionsEnabled = true;
852 
853  if ( OGRERR_NONE != OGR_L_StartTransaction( writer->mLayer ) )
854  {
855  QgsDebugMsg( "Error when trying to enable transactions on OGRLayer." );
856  transactionsEnabled = false;
857  }
858 
859  // write all features
860  while ( fit.nextFeature( fet ) )
861  {
862  if ( onlySelected && !ids.contains( fet.id() ) )
863  continue;
864 
865  if ( shallTransform )
866  {
867  try
868  {
869  if ( fet.geometry() )
870  {
871  fet.geometry()->transform( *ct );
872  }
873  }
874  catch ( QgsCsException &e )
875  {
876  delete ct;
877  delete writer;
878 
879  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
880  .arg( fet.id() ).arg( e.what() );
881  QgsLogger::warning( msg );
882  if ( errorMessage )
883  *errorMessage = msg;
884 
885  return ErrProjection;
886  }
887  }
888  if ( allAttr.size() < 1 && skipAttributeCreation )
889  {
890  fet.initAttributes( 0 );
891  }
892 
893  if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
894  {
895  WriterError err = writer->hasError();
896  if ( err != NoError && errorMessage )
897  {
898  if ( errorMessage->isEmpty() )
899  {
900  *errorMessage = QObject::tr( "Feature write errors:" );
901  }
902  *errorMessage += "\n" + writer->errorMessage();
903  }
904  errors++;
905 
906  if ( errors > 1000 )
907  {
908  if ( errorMessage )
909  {
910  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
911  }
912 
913  n = -1;
914  break;
915  }
916  }
917  n++;
918  }
919 
920  if ( transactionsEnabled )
921  {
922  if ( OGRERR_NONE != OGR_L_CommitTransaction( writer->mLayer ) )
923  {
924  QgsDebugMsg( "Error while committing transaction on OGRLayer." );
925  }
926  }
927 
928  writer->stopRender( layer );
929  delete writer;
930 
931  if ( shallTransform )
932  {
933  delete ct;
934  }
935 
936  if ( errors > 0 && errorMessage && n > 0 )
937  {
938  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
939  }
940 
941  return errors == 0 ? NoError : ErrFeatureWriteFailed;
942 }
943 
944 
945 bool QgsVectorFileWriter::deleteShapeFile( QString theFileName )
946 {
947  QFileInfo fi( theFileName );
948  QDir dir = fi.dir();
949 
950  QStringList filter;
951  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
952  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
953  {
954  filter << fi.completeBaseName() + suffixes[i];
955  }
956 
957  bool ok = true;
958  foreach ( QString file, dir.entryList( filter ) )
959  {
960  if ( !QFile::remove( dir.canonicalPath() + "/" + file ) )
961  {
962  QgsDebugMsg( "Removing file failed : " + file );
963  ok = false;
964  }
965  }
966 
967  return ok;
968 }
969 
971 {
972  QMap<QString, QString> resultMap;
973 
975  int const drvCount = OGRGetDriverCount();
976 
977  for ( int i = 0; i < drvCount; ++i )
978  {
979  OGRSFDriverH drv = OGRGetDriver( i );
980  if ( drv )
981  {
982  QString drvName = OGR_Dr_GetName( drv );
983  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
984  {
985  QString filterString = filterForDriver( drvName );
986  if ( filterString.isEmpty() )
987  continue;
988 
989  resultMap.insert( filterString, drvName );
990  }
991  }
992  }
993 
994  return resultMap;
995 }
996 
997 QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
998 {
999  QMap<QString, QString> resultMap;
1000 
1002  int const drvCount = OGRGetDriverCount();
1003 
1004  QStringList writableDrivers;
1005  for ( int i = 0; i < drvCount; ++i )
1006  {
1007  OGRSFDriverH drv = OGRGetDriver( i );
1008  if ( drv )
1009  {
1010  QString drvName = OGR_Dr_GetName( drv );
1011  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
1012  {
1013  // Add separate format for Mapinfo MIF (MITAB is OGR default)
1014  if ( drvName == "MapInfo File" )
1015  {
1016  writableDrivers << "MapInfo MIF";
1017  }
1018  else if ( drvName == "SQLite" )
1019  {
1020  // Unfortunately it seems that there is no simple way to detect if
1021  // OGR SQLite driver is compiled with SpatiaLite support.
1022  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
1023  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
1024  // -> test if creation failes
1025  QString option = "SPATIALITE=YES";
1026  char **options = new char *[2];
1027  options[0] = CPLStrdup( option.toLocal8Bit().data() );
1028  options[1] = NULL;
1029  OGRSFDriverH poDriver;
1031  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() );
1032  if ( poDriver )
1033  {
1034  OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ), options );
1035  if ( ds )
1036  {
1037  writableDrivers << "SpatiaLite";
1038  OGR_Dr_DeleteDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ) );
1039  OGR_DS_Destroy( ds );
1040  }
1041  }
1042  CPLFree( options[0] );
1043  delete [] options;
1044  }
1045  else if ( drvName == "ESRI Shapefile" )
1046  {
1047  writableDrivers << "DBF file";
1048  }
1049  writableDrivers << drvName;
1050  }
1051  }
1052  }
1053 
1054  foreach ( QString drvName, writableDrivers )
1055  {
1056  QString longName;
1057  QString trLongName;
1058  QString glob;
1059  QString exts;
1060  if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() )
1061  {
1062  resultMap.insert( trLongName, drvName );
1063  }
1064  }
1065 
1066  return resultMap;
1067 }
1068 
1070 {
1071  QString filterString;
1072  QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats();
1073  QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
1074  for ( ; it != driverFormatMap.constEnd(); ++it )
1075  {
1076  if ( filterString.isEmpty() )
1077  filterString += ";;";
1078 
1079  filterString += it.key();
1080  }
1081  return filterString;
1082 }
1083 
1084 QString QgsVectorFileWriter::filterForDriver( const QString& driverName )
1085 {
1086  QString longName;
1087  QString trLongName;
1088  QString glob;
1089  QString exts;
1090  if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() )
1091  return "";
1092 
1093  return trLongName + " [OGR] (" + glob.toLower() + " " + glob.toUpper() + ")";
1094 }
1095 
1097 {
1098  if ( codecName == "System" )
1099  return QString( "LDID/0" );
1100 
1101  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
1102  if ( re.exactMatch( codecName ) )
1103  {
1104  QString c = re.cap( 2 ).replace( "-" , "" );
1105  bool isNumber;
1106  c.toInt( &isNumber );
1107  if ( isNumber )
1108  return c;
1109  }
1110  return codecName;
1111 }
1112 
1113 bool QgsVectorFileWriter::driverMetadata( QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext )
1114 {
1115  if ( driverName.startsWith( "AVCE00" ) )
1116  {
1117  longName = "Arc/Info ASCII Coverage";
1118  trLongName = QObject::tr( "Arc/Info ASCII Coverage" );
1119  glob = "*.e00";
1120  ext = "e00";
1121  }
1122  else if ( driverName.startsWith( "BNA" ) )
1123  {
1124  longName = "Atlas BNA";
1125  trLongName = QObject::tr( "Atlas BNA" );
1126  glob = "*.bna";
1127  ext = "bna";
1128  }
1129  else if ( driverName.startsWith( "CSV" ) )
1130  {
1131  longName = "Comma Separated Value";
1132  trLongName = QObject::tr( "Comma Separated Value" );
1133  glob = "*.csv";
1134  ext = "csv";
1135  }
1136  else if ( driverName.startsWith( "ESRI" ) )
1137  {
1138  longName = "ESRI Shapefile";
1139  trLongName = QObject::tr( "ESRI Shapefile" );
1140  glob = "*.shp";
1141  ext = "shp";
1142  }
1143  else if ( driverName.startsWith( "DBF file" ) )
1144  {
1145  longName = "DBF File";
1146  trLongName = QObject::tr( "DBF file" );
1147  glob = "*.dbf";
1148  ext = "dbf";
1149  }
1150  else if ( driverName.startsWith( "FMEObjects Gateway" ) )
1151  {
1152  longName = "FMEObjects Gateway";
1153  trLongName = QObject::tr( "FMEObjects Gateway" );
1154  glob = "*.fdd";
1155  ext = "fdd";
1156  }
1157  else if ( driverName.startsWith( "GeoJSON" ) )
1158  {
1159  longName = "GeoJSON";
1160  trLongName = QObject::tr( "GeoJSON" );
1161  glob = "*.geojson";
1162  ext = "geojson";
1163  }
1164  else if ( driverName.startsWith( "GeoRSS" ) )
1165  {
1166  longName = "GeoRSS";
1167  trLongName = QObject::tr( "GeoRSS" );
1168  glob = "*.xml";
1169  ext = "xml";
1170  }
1171  else if ( driverName.startsWith( "GML" ) )
1172  {
1173  longName = "Geography Markup Language [GML]";
1174  trLongName = QObject::tr( "Geography Markup Language [GML]" );
1175  glob = "*.gml";
1176  ext = "gml";
1177  }
1178  else if ( driverName.startsWith( "GMT" ) )
1179  {
1180  longName = "Generic Mapping Tools [GMT]";
1181  trLongName = QObject::tr( "Generic Mapping Tools [GMT]" );
1182  glob = "*.gmt";
1183  ext = "gmt";
1184  }
1185  else if ( driverName.startsWith( "GPX" ) )
1186  {
1187  longName = "GPS eXchange Format [GPX]";
1188  trLongName = QObject::tr( "GPS eXchange Format [GPX]" );
1189  glob = "*.gpx";
1190  ext = "gpx";
1191  }
1192  else if ( driverName.startsWith( "Interlis 1" ) )
1193  {
1194  longName = "INTERLIS 1";
1195  trLongName = QObject::tr( "INTERLIS 1" );
1196  glob = "*.itf *.xml *.ili";
1197  ext = "ili";
1198  }
1199  else if ( driverName.startsWith( "Interlis 2" ) )
1200  {
1201  longName = "INTERLIS 2";
1202  trLongName = QObject::tr( "INTERLIS 2" );
1203  glob = "*.itf *.xml *.ili";
1204  ext = "ili";
1205  }
1206  else if ( driverName.startsWith( "KML" ) )
1207  {
1208  longName = "Keyhole Markup Language [KML]";
1209  trLongName = QObject::tr( "Keyhole Markup Language [KML]" );
1210  glob = "*.kml" ;
1211  ext = "kml" ;
1212  }
1213  else if ( driverName.startsWith( "MapInfo File" ) )
1214  {
1215  longName = "Mapinfo TAB";
1216  trLongName = QObject::tr( "Mapinfo TAB" );
1217  glob = "*.tab";
1218  ext = "tab";
1219  }
1220  // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF
1221  else if ( driverName.startsWith( "MapInfo MIF" ) )
1222  {
1223  longName = "Mapinfo MIF";
1224  trLongName = QObject::tr( "Mapinfo MIF" );
1225  glob = "*.mif";
1226  ext = "mif";
1227  }
1228  else if ( driverName.startsWith( "DGN" ) )
1229  {
1230  longName = "Microstation DGN";
1231  trLongName = QObject::tr( "Microstation DGN" );
1232  glob = "*.dgn";
1233  ext = "dgn";
1234  }
1235  else if ( driverName.startsWith( "S57" ) )
1236  {
1237  longName = "S-57 Base file";
1238  trLongName = QObject::tr( "S-57 Base file" );
1239  glob = "*.000";
1240  ext = "000";
1241  }
1242  else if ( driverName.startsWith( "SDTS" ) )
1243  {
1244  longName = "Spatial Data Transfer Standard [SDTS]";
1245  trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" );
1246  glob = "*catd.ddf";
1247  ext = "ddf";
1248  }
1249  else if ( driverName.startsWith( "SQLite" ) )
1250  {
1251  longName = "SQLite";
1252  trLongName = QObject::tr( "SQLite" );
1253  glob = "*.sqlite";
1254  ext = "sqlite";
1255  }
1256  // QGIS internal addition for SpatialLite
1257  else if ( driverName.startsWith( "SpatiaLite" ) )
1258  {
1259  longName = "SpatiaLite";
1260  trLongName = QObject::tr( "SpatiaLite" );
1261  glob = "*.sqlite";
1262  ext = "sqlite";
1263  }
1264  else if ( driverName.startsWith( "DXF" ) )
1265  {
1266  longName = "AutoCAD DXF";
1267  trLongName = QObject::tr( "AutoCAD DXF" );
1268  glob = "*.dxf";
1269  ext = "dxf";
1270  }
1271  else if ( driverName.startsWith( "Geoconcept" ) )
1272  {
1273  longName = "Geoconcept";
1274  trLongName = QObject::tr( "Geoconcept" );
1275  glob = "*.gxt *.txt";
1276  ext = "gxt";
1277  }
1278  else if ( driverName.startsWith( "FileGDB" ) )
1279  {
1280  longName = "ESRI FileGDB";
1281  trLongName = QObject::tr( "ESRI FileGDB" );
1282  glob = "*.gdb";
1283  ext = "gdb";
1284  }
1285  else
1286  {
1287  return false;
1288  }
1289 
1290  return true;
1291 }
1292 
1294 {
1295  if ( !vl || !ds )
1296  {
1297  return;
1298  }
1299 
1300  QgsFeatureRendererV2* renderer = vl->rendererV2();
1301  if ( !renderer )
1302  {
1303  return;
1304  }
1305 
1306  //unit type
1307  QGis::UnitType mapUnits = vl->crs().mapUnits();
1308  if ( ct )
1309  {
1310  mapUnits = ct->destCRS().mapUnits();
1311  }
1312 
1313 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700
1314  mSymbolLayerTable.clear();
1315  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
1316  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
1317 
1318  //get symbols
1319  int nTotalLevels = 0;
1320  QgsSymbolV2List symbolList = renderer->symbols();
1321  QgsSymbolV2List::iterator symbolIt = symbolList.begin();
1322  for ( ; symbolIt != symbolList.end(); ++symbolIt )
1323  {
1324  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
1325  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
1326 
1327  int nLevels = ( *symbolIt )->symbolLayerCount();
1328  for ( int i = 0; i < nLevels; ++i )
1329  {
1330  mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
1331  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
1332  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
1333  ++nTotalLevels;
1334  }
1335  }
1336  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
1337 #endif
1338 }
1339 
1341  const QgsCoordinateTransform* ct, QString* errorMessage )
1342 {
1343  if ( !layer )
1344  {
1345  //return error
1346  }
1347  QgsFeatureRendererV2* renderer = layer->rendererV2();
1348  if ( !renderer )
1349  {
1350  //return error
1351  }
1352  QHash< QgsSymbolV2*, QList<QgsFeature> > features;
1353 
1354  //unit type
1355  QGis::UnitType mapUnits = layer->crs().mapUnits();
1356  if ( ct )
1357  {
1358  mapUnits = ct->destCRS().mapUnits();
1359  }
1360 
1361  startRender( layer );
1362 
1363  //fetch features
1364  QgsFeature fet;
1365  QgsSymbolV2* featureSymbol = 0;
1366  while ( fit.nextFeature( fet ) )
1367  {
1368  if ( ct )
1369  {
1370  try
1371  {
1372  if ( fet.geometry() )
1373  {
1374  fet.geometry()->transform( *ct );
1375  }
1376  }
1377  catch ( QgsCsException &e )
1378  {
1379  delete ct;
1380 
1381  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
1382  .arg( e.what() );
1383  QgsLogger::warning( msg );
1384  if ( errorMessage )
1385  *errorMessage = msg;
1386 
1387  return ErrProjection;
1388  }
1389  }
1390 
1391  featureSymbol = renderer->symbolForFeature( fet );
1392  if ( !featureSymbol )
1393  {
1394  continue;
1395  }
1396 
1397  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
1398  if ( it == features.end() )
1399  {
1400  it = features.insert( featureSymbol, QList<QgsFeature>() );
1401  }
1402  it.value().append( fet );
1403  }
1404 
1405  //find out order
1406  QgsSymbolV2LevelOrder levels;
1407  QgsSymbolV2List symbols = renderer->symbols();
1408  for ( int i = 0; i < symbols.count(); i++ )
1409  {
1410  QgsSymbolV2* sym = symbols[i];
1411  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
1412  {
1413  int level = sym->symbolLayer( j )->renderingPass();
1414  if ( level < 0 || level >= 1000 ) // ignore invalid levels
1415  continue;
1416  QgsSymbolV2LevelItem item( sym, j );
1417  while ( level >= levels.count() ) // append new empty levels
1418  levels.append( QgsSymbolV2Level() );
1419  levels[level].append( item );
1420  }
1421  }
1422 
1423  int nErrors = 0;
1424  int nTotalFeatures = 0;
1425 
1426  //export symbol layers and symbology
1427  for ( int l = 0; l < levels.count(); l++ )
1428  {
1429  QgsSymbolV2Level& level = levels[l];
1430  for ( int i = 0; i < level.count(); i++ )
1431  {
1432  QgsSymbolV2LevelItem& item = level[i];
1433  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
1434  if ( levelIt == features.end() )
1435  {
1436  ++nErrors;
1437  continue;
1438  }
1439 
1440  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
1441  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
1442 
1443  int llayer = item.layer();
1444  QList<QgsFeature>& featureList = levelIt.value();
1445  QList<QgsFeature>::iterator featureIt = featureList.begin();
1446  for ( ; featureIt != featureList.end(); ++featureIt )
1447  {
1448  ++nTotalFeatures;
1449  OGRFeatureH ogrFeature = createFeature( *featureIt );
1450  if ( !ogrFeature )
1451  {
1452  ++nErrors;
1453  continue;
1454  }
1455 
1456  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
1457  if ( !styleString.isEmpty() )
1458  {
1459  OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
1460  if ( ! writeFeature( mLayer, ogrFeature ) )
1461  {
1462  ++nErrors;
1463  }
1464  }
1465  OGR_F_Destroy( ogrFeature );
1466  }
1467  }
1468  }
1469 
1470  stopRender( layer );
1471 
1472  if ( nErrors > 0 && errorMessage )
1473  {
1474  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
1475  }
1476 
1478 }
1479 
1480 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
1481 {
1482  if ( symbolUnits == QgsSymbolV2::MM )
1483  {
1484  return 1.0;
1485  }
1486  else
1487  {
1488  //conversion factor map units -> mm
1489  if ( mapUnits == QGis::Meters )
1490  {
1491  return 1000 / scaleDenominator;
1492  }
1493 
1494  }
1495  return 1.0; //todo: map units
1496 }
1497 
1498 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
1499 {
1500  if ( symbolUnits == QgsSymbolV2::MapUnit )
1501  {
1502  return 1.0;
1503  }
1504  else
1505  {
1506  if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
1507  {
1508  return scaleDenominator / 1000;
1509  }
1510  }
1511  return 1.0;
1512 }
1513 
1515 {
1516  QgsRenderContext context;
1518  return context;
1519 }
1520 
1522 {
1523  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
1524  if ( !renderer )
1525  {
1526  return;
1527  }
1528 
1530  renderer->startRender( ctx, vl );
1531 }
1532 
1534 {
1535  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
1536  if ( !renderer )
1537  {
1538  return;
1539  }
1540 
1542  renderer->stopRender( ctx );
1543 }
1544 
1546 {
1547  if ( mSymbologyExport == NoSymbology )
1548  {
1549  return 0;
1550  }
1551  if ( !vl )
1552  {
1553  return 0;
1554  }
1555 
1556  return vl->rendererV2();
1557 }
1558 
1560 {
1561  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
1562  if ( renderer )
1563  {
1564  QList<QString> rendererAttributes = renderer->usedAttributes();
1565  for ( int i = 0; i < rendererAttributes.size(); ++i )
1566  {
1567  int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
1568  if ( index != -1 )
1569  {
1570  attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
1571  }
1572  }
1573  }
1574 }