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 }
QgsFeatureId id() const
Get the feature id for this feature.
Definition: qgsfeature.cpp:101
static WkbType singleType(WkbType type)
Definition: qgis.h:71
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:55
Wrapper for iterator of features from vector data provider or vector layer.
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
static QMap< QString, QString > supportedFiltersAndFormats()
Returns map with format filter string as key and OGR format key as value.
SymbologyExport symbologyExport() const
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:36
void createSymbolLayerTable(QgsVectorLayer *vl, const QgsCoordinateTransform *ct, OGRDataSourceH ds)
bool writeFeature(OGRLayerH layer, OGRFeatureH feature)
WriterError mError
contains error value if construction was not successful
size_t wkbSize() const
Returns the size of the WKB in asWkb().
static QString fileFilterString()
Returns filter string that can be used for dialogs.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:321
SymbologyExport mSymbologyExport
double mSymbologyScaleDenominator
Scale for symbology export (e.g.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:162
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:113
void setRendererScale(double scale)
int precision() const
Gets the precision of the field.
Definition: qgsfield.cpp:75
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
static void registerOgrDrivers()
Register OGR drivers ensuring this only happens once.
static bool deleteShapeFile(QString theFileName)
Delete a shapefile (and its accompanying shx / dbf / prf)
Container of fields for a vector layer.
Definition: qgsfield.h:162
double mmScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
void addRendererAttributes(QgsVectorLayer *vl, QgsAttributeList &attList)
Adds attributes needed for classification.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:72
WkbType
Used for symbology operations.
Definition: qgis.h:53
virtual QList< QString > usedAttributes()=0
A convenience class for writing vector files to disk.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:114
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QGis::WkbType wkbType() const
Returns the WKBType or WKBUnknown in case of error.
virtual void stopRender(QgsRenderContext &context)=0
double ANALYSIS_EXPORT max(double x, double y)
returns the maximum of two doubles or the first argument if both are equal
virtual QgsSymbolV2List symbols()=0
for symbol levels
#define TO8F(x)
double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
void startRender(QgsVectorLayer *vl) const
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
#define FID_TO_NUMBER(fid)
Definition: qgsfeature.h:82
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:182
This class wraps a request for features to a vector layer (or directly its vector data provider)...
~QgsVectorFileWriter()
close opened shapefile for writing
QList< int > QgsAttributeList
OGRFeatureH createFeature(QgsFeature &feature)
int symbolLayerCount()
Definition: qgssymbolv2.h:83
bool addFeature(QgsFeature &feature, QgsFeatureRendererV2 *renderer=0, QGis::UnitType outputUnit=QGis::Meters)
add feature to the currently opened shapefile
int count() const
Return number of items.
Definition: qgsfield.h:196
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
void stopRender(QgsVectorLayer *vl) const
QGis::WkbType mWkbType
geometry type which is being used
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:29
static bool driverMetadata(QString driverName, QString &longName, QString &trLongName, QString &glob, QString &ext)
QMap< int, int > mAttrIdxToOgrIdx
map attribute indizes to OGR field indexes
WriterError exportFeaturesSymbolLevels(QgsVectorLayer *layer, QgsFeatureIterator &fit, const QgsCoordinateTransform *ct, QString *errorMessage=0)
Writes features considering symbol level order.
QList< QgsSymbolV2LevelItem > QgsSymbolV2Level
Definition: qgsrendererv2.h:59
int renderingPass() const
static QMap< QString, QString > ogrDriverList()
Returns driver list that can be used for dialogs.
QString file
Definition: qgssvgcache.cpp:74
QString errorMessage()
retrieves error message
QgsRenderContext renderContext() const
QString what() const
Definition: qgsexception.h:35
Contains information about the context of a rendering operation.
static QString convertCodecNameForEncodingOption(const QString &codecName)
Converts codec name to string passed to ENCODING layer creation option of OGR Shapefile.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
WriterError hasError()
checks whether there were any errors in constructor
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:231
QgsAttributeList pendingAllAttributesList()
returns list of attributes
QgsVectorFileWriter(const QString &vectorFileName, const QString &fileEncoding, const QgsFields &fields, QGis::WkbType geometryType, const QgsCoordinateReferenceSystem *srs, const QString &driverName="ESRI Shapefile", const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QString *newFilename=0, SymbologyExport symbologyExport=NoSymbology)
create shapefile and initialize it
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
return list of symbols used for rendering the feature.
void setSymbologyScaleDenominator(double d)
QgsSymbolV2 * symbol()
Definition: qgsrendererv2.h:51
bool usingSymbolLevels() const
Class for storing a coordinate reference system (CRS)
int length() const
Gets the length of the field.
Definition: qgsfield.cpp:70
int size() const
Return number of items.
Definition: qgsfield.h:198
Class for doing transforms between two map coordinate systems.
UnitType
Map units that qgis supports.
Definition: qgis.h:188
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTranasform ct.
QList< QgsSymbolV2Level > QgsSymbolV2LevelOrder
Definition: qgsrendererv2.h:62
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
virtual void startRender(QgsRenderContext &context, const QgsVectorLayer *vlayer)=0
static WriterError writeAsVectorFormat(QgsVectorLayer *layer, const QString &fileName, const QString &fileEncoding, const QgsCoordinateReferenceSystem *destCRS, const QString &driverName="ESRI Shapefile", bool onlySelected=false, QString *errorMessage=0, const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), bool skipAttributeCreation=false, QString *newFilename=0, SymbologyExport symbologyExport=NoSymbology, double symbologyScale=1.0)
Write contents of vector layer to an (OGR supported) vector formt.
Custom exception class for Coordinate Reference System related exceptions.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QgsSymbolLayerV2 * symbolLayer(int layer)
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
Do not fetch geometry.
const QgsCoordinateReferenceSystem & destCRS() const
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)=0
to be overridden
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
QgsFeatureRendererV2 * symbologyRenderer(QgsVectorLayer *vl) const
OGRGeometryH createEmptyGeometry(QGis::WkbType wkbType)
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
void * OGRSpatialReferenceH
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:60
#define tr(sourceText)