QGIS API Documentation
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 #include "qgsvectordataprovider.h"
30 #include "qgslocalec.h"
31 
32 #include <QFile>
33 #include <QSettings>
34 #include <QFileInfo>
35 #include <QDir>
36 #include <QTextCodec>
37 #include <QTextStream>
38 #include <QSet>
39 #include <QMetaType>
40 
41 #include <cassert>
42 #include <cstdlib> // size_t
43 #include <limits> // std::numeric_limits
44 
45 #include <ogr_srs_api.h>
46 #include <cpl_error.h>
47 #include <cpl_conv.h>
48 
49 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
50 #define TO8F(x) (x).toUtf8().constData()
51 #else
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( nullptr )
69  , mLayer( nullptr )
70  , mOgrRef( nullptr )
71  , mGeom( nullptr )
72  , mError( NoError )
73  , mCodec( nullptr )
74  , mWkbType( QGis::fromOldWkbType( geometryType ) )
75  , mSymbologyExport( symbologyExport )
76  , mSymbologyScaleDenominator( 1.0 )
77 {
78  init( theVectorFileName, theFileEncoding, fields, QGis::fromOldWkbType( geometryType ), srs, driverName, datasourceOptions, layerOptions, newFilename );
79 }
80 
81 QgsVectorFileWriter::QgsVectorFileWriter( const QString& vectorFileName, const QString& fileEncoding, const QgsFields& fields, QgsWKBTypes::Type geometryType, const QgsCoordinateReferenceSystem* srs, const QString& driverName, const QStringList& datasourceOptions, const QStringList& layerOptions, QString* newFilename, QgsVectorFileWriter::SymbologyExport symbologyExport )
82  : mDS( nullptr )
83  , mLayer( nullptr )
84  , mOgrRef( nullptr )
85  , mGeom( nullptr )
86  , mError( NoError )
87  , mCodec( nullptr )
88  , mWkbType( geometryType )
89  , mSymbologyExport( symbologyExport )
91 {
92  init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName, datasourceOptions, layerOptions, newFilename );
93 }
94 
95 void QgsVectorFileWriter::init( QString vectorFileName, QString fileEncoding, const QgsFields& fields, QgsWKBTypes::Type geometryType, const QgsCoordinateReferenceSystem* srs, const QString& driverName, QStringList datasourceOptions, QStringList layerOptions, QString* newFilename )
96 {
98 
99  if ( vectorFileName.isEmpty() )
100  {
101  mErrorMessage = QObject::tr( "Empty filename given" );
103  return;
104  }
105 
106  if ( driverName == "MapInfo MIF" )
107  {
108  mOgrDriverName = "MapInfo File";
109  }
110  else if ( driverName == "SpatiaLite" )
111  {
112  mOgrDriverName = "SQLite";
113  if ( !datasourceOptions.contains( "SPATIALITE=YES" ) )
114  {
115  datasourceOptions.append( "SPATIALITE=YES" );
116  }
117  }
118  else if ( driverName == "DBF file" )
119  {
120  mOgrDriverName = "ESRI Shapefile";
121  if ( !layerOptions.contains( "SHPT=NULL" ) )
122  {
123  layerOptions.append( "SHPT=NULL" );
124  }
125  srs = nullptr;
126  }
127  else
128  {
129  mOgrDriverName = driverName;
130  }
131 
132  // find driver in OGR
133  OGRSFDriverH poDriver;
135 
136  poDriver = OGRGetDriverByName( mOgrDriverName.toLocal8Bit().data() );
137 
138  if ( !poDriver )
139  {
140  mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" )
141  .arg( driverName,
142  QString::fromUtf8( CPLGetLastErrorMsg() ) );
144  return;
145  }
146 
147  if ( mOgrDriverName == "ESRI Shapefile" )
148  {
149  if ( layerOptions.join( "" ).toUpper().indexOf( "ENCODING=" ) == -1 )
150  {
151  layerOptions.append( "ENCODING=" + convertCodecNameForEncodingOption( fileEncoding ) );
152  }
153 
154  if ( driverName == "ESRI Shapefile" && !vectorFileName.endsWith( ".shp", Qt::CaseInsensitive ) )
155  {
156  vectorFileName += ".shp";
157  }
158  else if ( driverName == "DBF file" && !vectorFileName.endsWith( ".dbf", Qt::CaseInsensitive ) )
159  {
160  vectorFileName += ".dbf";
161  }
162 
163 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
164  // check for unique fieldnames
165  QSet<QString> fieldNames;
166  for ( int i = 0; i < fields.count(); ++i )
167  {
168  QString name = fields[i].name().left( 10 );
169  if ( fieldNames.contains( name ) )
170  {
171  mErrorMessage = QObject::tr( "trimming attribute name '%1' to ten significant characters produces duplicate column name." )
172  .arg( fields[i].name() );
174  return;
175  }
176  fieldNames << name;
177  }
178 #endif
179 
180  deleteShapeFile( vectorFileName );
181  }
182  else if ( driverName == "KML" )
183  {
184  if ( !vectorFileName.endsWith( ".kml", Qt::CaseInsensitive ) )
185  {
186  vectorFileName += ".kml";
187  }
188 
189  if ( fileEncoding.compare( "UTF-8", Qt::CaseInsensitive ) != 0 )
190  {
191  QgsDebugMsg( "forced UTF-8 encoding for KML" );
192  fileEncoding = "UTF-8";
193  }
194 
195  QFile::remove( vectorFileName );
196  }
197  else
198  {
199  QString longName;
200  QString trLongName;
201  QString glob;
202  QString exts;
203  if ( QgsVectorFileWriter::driverMetadata( driverName, longName, trLongName, glob, exts ) )
204  {
205  QStringList allExts = exts.split( ' ', QString::SkipEmptyParts );
206  bool found = false;
207  Q_FOREACH ( const QString& ext, allExts )
208  {
209  if ( vectorFileName.endsWith( '.' + ext, Qt::CaseInsensitive ) )
210  {
211  found = true;
212  break;
213  }
214  }
215 
216  if ( !found )
217  {
218  vectorFileName += '.' + allExts[0];
219  }
220  }
221 
222  QFile::remove( vectorFileName );
223  }
224 
225  char **options = nullptr;
226  if ( !datasourceOptions.isEmpty() )
227  {
228  options = new char *[ datasourceOptions.size()+1 ];
229  for ( int i = 0; i < datasourceOptions.size(); i++ )
230  {
231  options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().data() );
232  }
233  options[ datasourceOptions.size()] = nullptr;
234  }
235 
236  // create the data source
237  mDS = OGR_Dr_CreateDataSource( poDriver, TO8F( vectorFileName ), options );
238 
239  if ( options )
240  {
241  for ( int i = 0; i < datasourceOptions.size(); i++ )
242  CPLFree( options[i] );
243  delete [] options;
244  options = nullptr;
245  }
246 
247  if ( !mDS )
248  {
250  mErrorMessage = QObject::tr( "creation of data source failed (OGR error:%1)" )
251  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
252  return;
253  }
254 
255  QgsDebugMsg( "Created data source" );
256 
257  // use appropriate codec
259  if ( !mCodec )
260  {
261  QgsDebugMsg( "error finding QTextCodec for " + fileEncoding );
262 
263  QSettings settings;
264  QString enc = settings.value( "/UI/encoding", "System" ).toString();
266  if ( !mCodec )
267  {
268  QgsDebugMsg( "error finding QTextCodec for " + enc );
270  Q_ASSERT( mCodec );
271  }
272  }
273 
274  // consider spatial reference system of the layer
275  if ( srs )
276  {
277  QString srsWkt = srs->toWkt();
278  QgsDebugMsg( "WKT to save as is " + srsWkt );
279  mOgrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() );
280  }
281 
282  // datasource created, now create the output layer
283  QString layerName = QFileInfo( vectorFileName ).baseName();
284  OGRwkbGeometryType wkbType = ogrTypeFromWkbType( geometryType );
285 
286  if ( !layerOptions.isEmpty() )
287  {
288  options = new char *[ layerOptions.size()+1 ];
289  for ( int i = 0; i < layerOptions.size(); i++ )
290  {
291  options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().data() );
292  }
293  options[ layerOptions.size()] = nullptr;
294  }
295 
296  // disable encoding conversion of OGR Shapefile layer
297  CPLSetConfigOption( "SHAPE_ENCODING", "" );
298 
299  mLayer = OGR_DS_CreateLayer( mDS, TO8F( layerName ), mOgrRef, wkbType, options );
300 
301  if ( options )
302  {
303  for ( int i = 0; i < layerOptions.size(); i++ )
304  CPLFree( options[i] );
305  delete [] options;
306  options = nullptr;
307  }
308 
309  QSettings settings;
310  if ( !settings.value( "/qgis/ignoreShapeEncoding", true ).toBool() )
311  {
312  CPLSetConfigOption( "SHAPE_ENCODING", nullptr );
313  }
314 
315  if ( srs )
316  {
317  if ( mOgrDriverName == "ESRI Shapefile" )
318  {
319  QString layerName = vectorFileName.left( vectorFileName.indexOf( ".shp", Qt::CaseInsensitive ) );
320  QFile prjFile( layerName + ".qpj" );
321  if ( prjFile.open( QIODevice::WriteOnly ) )
322  {
323  QTextStream prjStream( &prjFile );
324  prjStream << srs->toWkt().toLocal8Bit().data() << endl;
325  prjFile.close();
326  }
327  else
328  {
329  QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" );
330  }
331  }
332  }
333 
334  if ( !mLayer )
335  {
336  mErrorMessage = QObject::tr( "creation of layer failed (OGR error:%1)" )
337  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
339  return;
340  }
341 
342  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer );
343 
344  QgsDebugMsg( "created layer" );
345 
346  // create the fields
347  QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" );
348 
349  mFields = fields;
351  QSet<int> existingIdxs;
352 
353  for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
354  {
355  const QgsField& attrField = fields[fldIdx];
356 
357  OGRFieldType ogrType = OFTString; //default to string
358  int ogrWidth = attrField.length();
359  int ogrPrecision = attrField.precision();
360  if ( ogrPrecision > 0 )
361  ++ogrWidth;
362 
363  switch ( attrField.type() )
364  {
365 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 2000000
366  case QVariant::LongLong:
367  ogrType = OFTString;
368  ogrWidth = ogrWidth > 0 && ogrWidth <= 21 ? ogrWidth : 21;
369  ogrPrecision = -1;
370  break;
371 #else
372  case QVariant::LongLong:
373  ogrType = OFTInteger64;
374  ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
375  ogrPrecision = 0;
376  break;
377 #endif
378  case QVariant::String:
379  ogrType = OFTString;
380  if ( ogrWidth <= 0 || ogrWidth > 255 )
381  ogrWidth = 255;
382  break;
383 
384  case QVariant::Int:
385  ogrType = OFTInteger;
386  ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
387  ogrPrecision = 0;
388  break;
389 
390  case QVariant::Double:
391  ogrType = OFTReal;
392  break;
393 
394  case QVariant::Date:
395  ogrType = OFTDate;
396  break;
397 
398  case QVariant::Time:
399  if ( mOgrDriverName == "ESRI Shapefile" )
400  {
401  ogrType = OFTString;
402  ogrWidth = 12; // %02d:%02d:%06.3f
403  }
404  else
405  {
406  ogrType = OFTTime;
407  }
408  break;
409 
410  case QVariant::DateTime:
411  if ( mOgrDriverName == "ESRI Shapefile" )
412  {
413  ogrType = OFTString;
414  ogrWidth = 24; // "%04d/%02d/%02d %02d:%02d:%06.3f"
415  }
416  else
417  {
418  ogrType = OFTDateTime;
419  }
420  break;
421 
422  default:
423  //assert(0 && "invalid variant type!");
424  mErrorMessage = QObject::tr( "unsupported type for field %1" )
425  .arg( attrField.name() );
427  return;
428  }
429 
430  QString name( attrField.name() );
431 
432  if ( mOgrDriverName == "SQLite" && name.compare( "ogc_fid", Qt::CaseInsensitive ) == 0 )
433  {
434  int i;
435  for ( i = 0; i < 10; i++ )
436  {
437  name = QString( "ogc_fid%1" ).arg( i );
438 
439  int j;
440  for ( j = 0; j < fields.size() && name.compare( fields[j].name(), Qt::CaseInsensitive ) != 0; j++ )
441  ;
442 
443  if ( j == fields.size() )
444  break;
445  }
446 
447  if ( i == 10 )
448  {
449  mErrorMessage = QObject::tr( "no available replacement for internal fieldname ogc_fid found" ).arg( attrField.name() );
451  return;
452  }
453 
454  QgsMessageLog::logMessage( QObject::tr( "Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr( "OGR" ) );
455  }
456 
457  // create field definition
458  OGRFieldDefnH fld = OGR_Fld_Create( mCodec->fromUnicode( name ), ogrType );
459  if ( ogrWidth > 0 )
460  {
461  OGR_Fld_SetWidth( fld, ogrWidth );
462  }
463 
464  if ( ogrPrecision >= 0 )
465  {
466  OGR_Fld_SetPrecision( fld, ogrPrecision );
467  }
468 
469  // create the field
470  QgsDebugMsg( "creating field " + attrField.name() +
471  " type " + QString( QVariant::typeToName( attrField.type() ) ) +
472  " width " + QString::number( ogrWidth ) +
473  " precision " + QString::number( ogrPrecision ) );
474  if ( OGR_L_CreateField( mLayer, fld, true ) != OGRERR_NONE )
475  {
476  QgsDebugMsg( "error creating field " + attrField.name() );
477  mErrorMessage = QObject::tr( "creation of field %1 failed (OGR error: %2)" )
478  .arg( attrField.name(),
479  QString::fromUtf8( CPLGetLastErrorMsg() ) );
481  OGR_Fld_Destroy( fld );
482  return;
483  }
484  OGR_Fld_Destroy( fld );
485 
486  int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
487  QgsDebugMsg( QString( "returned field index for %1: %2" ).arg( name ).arg( ogrIdx ) );
488  if ( ogrIdx < 0 || existingIdxs.contains( ogrIdx ) )
489  {
490 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM < 1700
491  // if we didn't find our new column, assume it's name was truncated and
492  // it was the last one added (like for shape files)
493  int fieldCount = OGR_FD_GetFieldCount( defn );
494 
495  OGRFieldDefnH fdefn = OGR_FD_GetFieldDefn( defn, fieldCount - 1 );
496  if ( fdefn )
497  {
498  const char *fieldName = OGR_Fld_GetNameRef( fdefn );
499 
500  if ( attrField.name().left( strlen( fieldName ) ) == fieldName )
501  {
502  ogrIdx = fieldCount - 1;
503  }
504  }
505 #else
506  // GDAL 1.7 not just truncates, but launders more aggressivly.
507  ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
508 #endif
509 
510  if ( ogrIdx < 0 )
511  {
512  QgsDebugMsg( "error creating field " + attrField.name() );
513  mErrorMessage = QObject::tr( "created field %1 not found (OGR error: %2)" )
514  .arg( attrField.name(),
515  QString::fromUtf8( CPLGetLastErrorMsg() ) );
517  return;
518  }
519  }
520 
521  existingIdxs.insert( ogrIdx );
522  mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
523  }
524 
525  QgsDebugMsg( "Done creating fields" );
526 
527  mWkbType = geometryType;
529  {
530  // create geometry which will be used for import
532  }
533 
534  if ( newFilename )
535  *newFilename = vectorFileName;
536 }
537 
539 {
540  return OGR_G_CreateGeometry( ogrTypeFromWkbType( wkbType ) );
541 }
542 
543 QMap<QString, QgsVectorFileWriter::MetaData> QgsVectorFileWriter::initMetaData()
544 {
546 
547  QMap<QString, Option*> datasetOptions;
548  QMap<QString, Option*> layerOptions;
549 
550  // Arc/Info ASCII Coverage
551  datasetOptions.clear();
552  layerOptions.clear();
553 
554  driverMetadata.insert( "AVCE00",
555  MetaData(
556  "Arc/Info ASCII Coverage",
557  QObject::tr( "Arc/Info ASCII Coverage" ),
558  "*.e00",
559  "e00",
560  datasetOptions,
561  layerOptions
562  )
563  );
564 
565  // Atlas BNA
566  datasetOptions.clear();
567  layerOptions.clear();
568 
569  datasetOptions.insert( "LINEFORMAT", new SetOption(
570  QObject::tr( "New BNA files are created by the "
571  "systems default line termination conventions. "
572  "This may be overridden here." ),
573  QStringList()
574  << "CRLF"
575  << "LF",
576  "", // Default value
577  true // Allow None
578  ) );
579 
580  datasetOptions.insert( "MULTILINE", new BoolOption(
581  QObject::tr( "By default, BNA files are created in multi-line format. "
582  "For each record, the first line contains the identifiers and the "
583  "type/number of coordinates to follow. Each following line contains "
584  "a pair of coordinates." ),
585  true // Default value
586  ) );
587 
588  datasetOptions.insert( "NB_IDS", new SetOption(
589  QObject::tr( "BNA records may contain from 2 to 4 identifiers per record. "
590  "Some software packages only support a precise number of identifiers. "
591  "You can override the default value (2) by a precise value" ),
592  QStringList()
593  << "2"
594  << "3"
595  << "4"
596  << "NB_SOURCE_FIELDS",
597  "2" // Default value
598  ) );
599 
600  datasetOptions.insert( "ELLIPSES_AS_ELLIPSES", new BoolOption(
601  QObject::tr( "The BNA writer will try to recognize ellipses and circles when writing a polygon. "
602  "This will only work if the feature has previously been read from a BNA file. "
603  "As some software packages do not support ellipses/circles in BNA data file, "
604  "it may be useful to tell the writer by specifying ELLIPSES_AS_ELLIPSES=NO not "
605  "to export them as such, but keep them as polygons." ),
606  true // Default value
607  ) );
608 
609  datasetOptions.insert( "NB_PAIRS_PER_LINE", new IntOption(
610  QObject::tr( "Limit the number of coordinate pairs per line in multiline format." ),
611  2 // Default value
612  ) );
613 
614  datasetOptions.insert( "COORDINATE_PRECISION", new IntOption(
615  QObject::tr( "Set the number of decimal for coordinates. Default value is 10." ),
616  10 // Default value
617  ) );
618 
619  driverMetadata.insert( "BNA",
620  MetaData(
621  "Atlas BNA",
622  QObject::tr( "Atlas BNA" ),
623  "*.bna",
624  "bna",
625  datasetOptions,
626  layerOptions
627  )
628  );
629 
630  // Comma Separated Value
631  datasetOptions.clear();
632  layerOptions.clear();
633 
634  layerOptions.insert( "LINEFORMAT", new SetOption(
635  QObject::tr( "By default when creating new .csv files they "
636  "are created with the line termination conventions "
637  "of the local platform (CR/LF on Win32 or LF on all other systems). "
638  "This may be overridden through the use of the LINEFORMAT option." ),
639  QStringList()
640  << "CRLF"
641  << "LF",
642  "", // Default value
643  true // Allow None
644  ) );
645 
646  layerOptions.insert( "GEOMETRY", new SetOption(
647  QObject::tr( "By default, the geometry of a feature written to a .csv file is discarded. "
648  "It is possible to export the geometry in its WKT representation by "
649  "specifying GEOMETRY=AS_WKT. It is also possible to export point geometries "
650  "into their X,Y,Z components by specifying GEOMETRY=AS_XYZ, GEOMETRY=AS_XY "
651  "or GEOMETRY=AS_YX." ),
652  QStringList()
653  << "AS_WKT"
654  << "AS_XYZ"
655  << "AS_XY"
656  << "AS_YX",
657  "AS_XY", // Default value
658  true // Allow None
659  ) );
660 
661  layerOptions.insert( "CREATE_CSVT", new BoolOption(
662  QObject::tr( "Create the associated .csvt file to describe the type of each "
663  "column of the layer and its optional width and precision." ),
664  false // Default value
665  ) );
666 
667  layerOptions.insert( "SEPARATOR", new SetOption(
668  QObject::tr( "Field separator character." ),
669  QStringList()
670  << "COMMA"
671  << "SEMICOLON"
672  << "TAB",
673  "COMMA" // Default value
674  ) );
675 
676  layerOptions.insert( "WRITE_BOM", new BoolOption(
677  QObject::tr( "Write a UTF-8 Byte Order Mark (BOM) at the start of the file." ),
678  false // Default value
679  ) );
680 
681  driverMetadata.insert( "CSV",
682  MetaData(
683  "Comma Separated Value [CSV]",
684  QObject::tr( "Comma Separated Value [CSV]" ),
685  "*.csv",
686  "csv",
687  datasetOptions,
688  layerOptions
689  )
690  );
691 
692  // ESRI Shapefile
693  datasetOptions.clear();
694  layerOptions.clear();
695 
696  layerOptions.insert( "SHPT", new SetOption(
697  QObject::tr( "Override the type of shapefile created. "
698  "Can be one of NULL for a simple .dbf file with no .shp file, POINT, "
699  "ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or "
700  "MULTIPOINTZ for 3D. Shapefiles with measure values are not supported, "
701  "nor are MULTIPATCH files." ),
702  QStringList()
703  << "NULL"
704  << "POINT"
705  << "ARC"
706  << "POLYGON"
707  << "MULTIPOINT"
708  << "POINTZ"
709  << "ARCZ"
710  << "POLYGONZ"
711  << "MULTIPOINTZ",
712  QString(), // Default value
713  true // Allow None
714  ) );
715 
716  // there does not seem to be a reason to provide this option to the user again
717  // as we set encoding for shapefiles based on "fileEncoding" parameter passed to the writer
718 #if 0
719  layerOptions.insert( "ENCODING", new SetOption(
720  QObject::tr( "set the encoding value in the DBF file. "
721  "The default value is LDID/87. It is not clear "
722  "what other values may be appropriate." ),
723  QStringList()
724  << "LDID/87",
725  "LDID/87" // Default value
726  ) );
727 #endif
728 
729  layerOptions.insert( "RESIZE", new BoolOption(
730  QObject::tr( "Set to YES to resize fields to their optimal size." ),
731  false // Default value
732  ) );
733 
734  driverMetadata.insert( "ESRI",
735  MetaData(
736  "ESRI Shapefile",
737  QObject::tr( "ESRI Shapefile" ),
738  "*.shp",
739  "shp",
740  datasetOptions,
741  layerOptions
742  )
743  );
744 
745  // DBF File
746  datasetOptions.clear();
747  layerOptions.clear();
748 
749  driverMetadata.insert( "DBF File",
750  MetaData(
751  "DBF File",
752  QObject::tr( "DBF File" ),
753  "*.dbf",
754  "dbf",
755  datasetOptions,
756  layerOptions
757  )
758  );
759 
760  // FMEObjects Gateway
761  datasetOptions.clear();
762  layerOptions.clear();
763 
764  driverMetadata.insert( "FMEObjects Gateway",
765  MetaData(
766  "FMEObjects Gateway",
767  QObject::tr( "FMEObjects Gateway" ),
768  "*.fdd",
769  "fdd",
770  datasetOptions,
771  layerOptions
772  )
773  );
774 
775  // GeoJSON
776  datasetOptions.clear();
777  layerOptions.clear();
778 
779  layerOptions.insert( "WRITE_BBOX", new BoolOption(
780  QObject::tr( "Set to YES to write a bbox property with the bounding box "
781  "of the geometries at the feature and feature collection level." ),
782  false // Default value
783  ) );
784 
785  layerOptions.insert( "COORDINATE_PRECISION", new IntOption(
786  QObject::tr( "Maximum number of figures after decimal separator to write in coordinates. "
787  "Default to 15. Truncation will occur to remove trailing zeros." ),
788  15 // Default value
789  ) );
790 
791  driverMetadata.insert( "GeoJSON",
792  MetaData(
793  "GeoJSON",
794  QObject::tr( "GeoJSON" ),
795  "*.geojson",
796  "geojson",
797  datasetOptions,
798  layerOptions
799  )
800  );
801 
802  // GeoRSS
803  datasetOptions.clear();
804  layerOptions.clear();
805 
806  datasetOptions.insert( "FORMAT", new SetOption(
807  QObject::tr( "whether the document must be in RSS 2.0 or Atom 1.0 format. "
808  "Default value : RSS" ),
809  QStringList()
810  << "RSS"
811  << "ATOM",
812  "RSS" // Default value
813  ) );
814 
815  datasetOptions.insert( "GEOM_DIALECT", new SetOption(
816  QObject::tr( "The encoding of location information. Default value : SIMPLE. "
817  "W3C_GEO only supports point geometries. "
818  "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
819  QStringList()
820  << "SIMPLE"
821  << "GML"
822  << "W3C_GEO",
823  "SIMPLE" // Default value
824  ) );
825 
826  datasetOptions.insert( "USE_EXTENSIONS", new BoolOption(
827  QObject::tr( "If defined to YES, extension fields will be written. "
828  "If the field name not found in the base schema matches "
829  "the foo_bar pattern, foo will be considered as the namespace "
830  "of the element, and a <foo:bar> element will be written. "
831  "Otherwise, elements will be written in the <ogr:> namespace." ),
832  true // Default value
833  ) );
834 
835  datasetOptions.insert( "WRITE_HEADER_AND_FOOTER", new BoolOption(
836  QObject::tr( "If defined to NO, only <entry> or <item> elements will be written. "
837  "The user will have to provide the appropriate header and footer of the document." ),
838  true // Default value
839  ) );
840 
841  datasetOptions.insert( "HEADER", new StringOption(
842  QObject::tr( "XML content that will be put between the <channel> element and the "
843  "first <item> element for a RSS document, or between the xml tag and "
844  "the first <entry> element for an Atom document. " ),
845  "" // Default value
846  ) );
847 
848  datasetOptions.insert( "TITLE", new StringOption(
849  QObject::tr( "Value put inside the <title> element in the header. "
850  "If not provided, a dummy value will be used as that element is compulsory." ),
851  "" // Default value
852  ) );
853 
854  datasetOptions.insert( "DESCRIPTION", new StringOption(
855  QObject::tr( "Value put inside the <description> element in the header. "
856  "If not provided, a dummy value will be used as that element is compulsory." ),
857  "" // Default value
858  ) );
859 
860  datasetOptions.insert( "LINK", new StringOption(
861  QObject::tr( "Value put inside the <link> element in the header. "
862  "If not provided, a dummy value will be used as that element is compulsory." ),
863  "" // Default value
864  ) );
865 
866  datasetOptions.insert( "UPDATED", new StringOption(
867  QObject::tr( "Value put inside the <updated> element in the header. "
868  "Should be formatted as a XML datetime. "
869  "If not provided, a dummy value will be used as that element is compulsory." ),
870  "" // Default value
871  ) );
872 
873  datasetOptions.insert( "AUTHOR_NAME", new StringOption(
874  QObject::tr( "Value put inside the <author><name> element in the header. "
875  "If not provided, a dummy value will be used as that element is compulsory." ),
876  "" // Default value
877  ) );
878 
879  datasetOptions.insert( "ID", new StringOption(
880  QObject::tr( "Value put inside the <id> element in the header. "
881  "If not provided, a dummy value will be used as that element is compulsory." ),
882  "" // Default value
883  ) );
884 
885  driverMetadata.insert( "GeoRSS",
886  MetaData(
887  "GeoRSS",
888  QObject::tr( "GeoRSS" ),
889  "*.xml",
890  "xml",
891  datasetOptions,
892  layerOptions
893  )
894  );
895 
896  // Geography Markup Language [GML]
897  datasetOptions.clear();
898  layerOptions.clear();
899 
900  datasetOptions.insert( "XSISCHEMAURI", new StringOption(
901  QObject::tr( "If provided, this URI will be inserted as the schema location. "
902  "Note that the schema file isn't actually accessed by OGR, so it "
903  "is up to the user to ensure it will match the schema of the OGR "
904  "produced GML data file." ),
905  "" // Default value
906  ) );
907 
908  datasetOptions.insert( "XSISCHEMA", new SetOption(
909  QObject::tr( "This writes a GML application schema file to a corresponding "
910  ".xsd file (with the same basename). If INTERNAL is used the "
911  "schema is written within the GML file, but this is experimental "
912  "and almost certainly not valid XML. "
913  "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
914  QStringList()
915  << "EXTERNAL"
916  << "INTERNAL"
917  << "OFF",
918  "EXTERNAL" // Default value
919  ) );
920 
921  datasetOptions.insert( "PREFIX", new StringOption(
922  QObject::tr( "This is the prefix for the application target namespace." ),
923  "ogr" // Default value
924  ) );
925 
926  datasetOptions.insert( "STRIP_PREFIX", new BoolOption(
927  QObject::tr( "Can be set to TRUE to avoid writing the prefix of the "
928  "application target namespace in the GML file." ),
929  false // Default value
930  ) );
931 
932  datasetOptions.insert( "TARGET_NAMESPACE", new StringOption(
933  QObject::tr( "Defaults to 'http://ogr.maptools.org/'. "
934  "This is the application target namespace." ),
935  "http://ogr.maptools.org/" // Default value
936  ) );
937 
938  datasetOptions.insert( "FORMAT", new SetOption(
939  QObject::tr( "If not specified, GML2 will be used." ),
940  QStringList()
941  << "GML3"
942  << "GML3Deegree"
943  << "GML3.2",
944  "", // Default value
945  true // Allow None
946  ) );
947 
948  datasetOptions.insert( "GML3_LONGSRS", new BoolOption(
949  QObject::tr( "only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
950  "If YES, SRS with EPSG authority will be written with the "
951  "'urn:ogc:def:crs:EPSG::' prefix. In the case, if the SRS is a "
952  "geographic SRS without explicit AXIS order, but that the same "
953  "SRS authority code imported with ImportFromEPSGA() should be "
954  "treated as lat/long, then the function will take care of coordinate "
955  "order swapping. If set to NO, SRS with EPSG authority will be "
956  "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
957  true // Default value
958  ) );
959 
960  datasetOptions.insert( "WRITE_FEATURE_BOUNDED_BY", new BoolOption(
961  QObject::tr( "only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
962  "If set to NO, the <gml:boundedBy> element will not be written for "
963  "each feature." ),
964  true // Default value
965  ) );
966 
967  datasetOptions.insert( "SPACE_INDENTATION", new BoolOption(
968  QObject::tr( "Default to YES. If YES, the output will be indented with spaces "
969  "for more readability, but at the expense of file size." ),
970  true // Default value
971  ) );
972 
973 
974  driverMetadata.insert( "GML",
975  MetaData(
976  "Geography Markup Language [GML]",
977  QObject::tr( "Geography Markup Language [GML]" ),
978  "*.gml",
979  "gml",
980  datasetOptions,
981  layerOptions
982  )
983  );
984 
985  // Generic Mapping Tools [GMT]
986  datasetOptions.clear();
987  layerOptions.clear();
988 
989  driverMetadata.insert( "GMT",
990  MetaData(
991  "Generic Mapping Tools [GMT]",
992  QObject::tr( "Generic Mapping Tools [GMT]" ),
993  "*.gmt",
994  "gmt",
995  datasetOptions,
996  layerOptions
997  )
998  );
999 
1000  // GPS eXchange Format [GPX]
1001  datasetOptions.clear();
1002  layerOptions.clear();
1003 
1004  layerOptions.insert( "FORCE_GPX_TRACK", new BoolOption(
1005  QObject::tr( "By default when writing a layer whose features are of "
1006  "type wkbLineString, the GPX driver chooses to write "
1007  "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1008  "they will be written as tracks." ),
1009  false // Default value
1010  ) );
1011 
1012  layerOptions.insert( "FORCE_GPX_ROUTE", new BoolOption(
1013  QObject::tr( "By default when writing a layer whose features are of "
1014  "type wkbMultiLineString, the GPX driver chooses to write "
1015  "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1016  "they will be written as routes, provided that the multilines "
1017  "are composed of only one single line." ),
1018  false // Default value
1019  ) );
1020 
1021  datasetOptions.insert( "GPX_USE_EXTENSIONS", new BoolOption(
1022  QObject::tr( "If GPX_USE_EXTENSIONS=YES is specified, "
1023  "extra fields will be written inside the <extensions> tag." ),
1024  true // Default value
1025  ) );
1026 
1027  datasetOptions.insert( "GPX_EXTENSIONS_NS", new StringOption(
1028  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1029  "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1030  "ogr" // Default value
1031  ) );
1032 
1033  datasetOptions.insert( "GPX_EXTENSIONS_NS_URL", new StringOption(
1034  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1035  "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1036  "http://osgeo.org/gdal" // Default value
1037  ) );
1038 
1039  datasetOptions.insert( "LINEFORMAT", new SetOption(
1040  QObject::tr( "By default files are created with the line termination "
1041  "conventions of the local platform (CR/LF on win32 or LF "
1042  "on all other systems). This may be overridden through use "
1043  "of the LINEFORMAT layer creation option which may have a value "
1044  "of CRLF (DOS format) or LF (Unix format)." ),
1045  QStringList()
1046  << "CRLF"
1047  << "LF",
1048  "", // Default value
1049  true // Allow None
1050  ) );
1051 
1052  driverMetadata.insert( "GPX",
1053  MetaData(
1054  "GPS eXchange Format [GPX]",
1055  QObject::tr( "GPS eXchange Format [GPX]" ),
1056  "*.gpx",
1057  "gpx",
1058  datasetOptions,
1059  layerOptions
1060  )
1061  );
1062 
1063  // INTERLIS 1
1064  datasetOptions.clear();
1065  layerOptions.clear();
1066 
1067  driverMetadata.insert( "Interlis 1",
1068  MetaData(
1069  "INTERLIS 1",
1070  QObject::tr( "INTERLIS 1" ),
1071  "*.itf *.xml *.ili",
1072  "ili",
1073  datasetOptions,
1074  layerOptions
1075  )
1076  );
1077 
1078  // INTERLIS 2
1079  datasetOptions.clear();
1080  layerOptions.clear();
1081 
1082  driverMetadata.insert( "Interlis 2",
1083  MetaData(
1084  "INTERLIS 2",
1085  QObject::tr( "INTERLIS 2" ),
1086  "*.itf *.xml *.ili",
1087  "ili",
1088  datasetOptions,
1089  layerOptions
1090  )
1091  );
1092 
1093  // Keyhole Markup Language [KML]
1094  datasetOptions.clear();
1095  layerOptions.clear();
1096 
1097  datasetOptions.insert( "NameField", new StringOption(
1098  QObject::tr( "Allows you to specify the field to use for the KML <name> element. " ),
1099  "Name" // Default value
1100  ) );
1101 
1102  datasetOptions.insert( "DescriptionField", new StringOption(
1103  QObject::tr( "Allows you to specify the field to use for the KML <description> element." ),
1104  "Description" // Default value
1105  ) );
1106 
1107  datasetOptions.insert( "AltitudeMode", new SetOption(
1108  QObject::tr( "Allows you to specify the AltitudeMode to use for KML geometries. "
1109  "This will only affect 3D geometries and must be one of the valid KML options." ),
1110  QStringList()
1111  << "clampToGround"
1112  << "relativeToGround"
1113  << "absolute",
1114  "clampToGround" // Default value
1115  ) );
1116 
1117  driverMetadata.insert( "KML",
1118  MetaData(
1119  "Keyhole Markup Language [KML]",
1120  QObject::tr( "Keyhole Markup Language [KML]" ),
1121  "*.kml",
1122  "kml",
1123  datasetOptions,
1124  layerOptions
1125  )
1126  );
1127 
1128  // Mapinfo
1129  datasetOptions.clear();
1130  layerOptions.clear();
1131 
1132  layerOptions.insert( "SPATIAL_INDEX_MODE", new SetOption(
1133  QObject::tr( "Use this to turn on 'quick spatial index mode'. "
1134  "In this mode writing files can be about 5 times faster, "
1135  "but spatial queries can be up to 30 times slower." ),
1136  QStringList()
1137  << "QUICK",
1138  "", // Default value
1139  true // Allow None
1140  ) );
1141 
1142  driverMetadata.insert( "MapInfo File",
1143  MetaData(
1144  "Mapinfo",
1145  QObject::tr( "Mapinfo TAB" ),
1146  "*.tab",
1147  "tab",
1148  datasetOptions,
1149  layerOptions
1150  )
1151  );
1152 
1153  // QGIS internal alias for MIF files
1154  driverMetadata.insert( "MapInfo MIF",
1155  MetaData(
1156  "Mapinfo",
1157  QObject::tr( "Mapinfo MIF" ),
1158  "*.mif",
1159  "mif",
1160  datasetOptions,
1161  layerOptions
1162  )
1163  );
1164 
1165  // Microstation DGN
1166  datasetOptions.clear();
1167  layerOptions.clear();
1168 
1169  datasetOptions.insert( "3D", new BoolOption(
1170  QObject::tr( "Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1171  "seed file should be used. This option is ignored if the SEED option is provided." ),
1172  false // Default value
1173  ) );
1174 
1175  datasetOptions.insert( "SEED", new StringOption(
1176  QObject::tr( "Override the seed file to use." ),
1177  "" // Default value
1178  ) );
1179 
1180  datasetOptions.insert( "COPY_WHOLE_SEED_FILE", new BoolOption(
1181  QObject::tr( "Indicate whether the whole seed file should be copied. "
1182  "If not, only the first three elements will be copied." ),
1183  false // Default value
1184  ) );
1185 
1186  datasetOptions.insert( "COPY_SEED_FILE_COLOR_TABLEE", new BoolOption(
1187  QObject::tr( "Indicates whether the color table should be copied from the seed file." ),
1188  false // Default value
1189  ) );
1190 
1191  datasetOptions.insert( "MASTER_UNIT_NAME", new StringOption(
1192  QObject::tr( "Override the master unit name from the seed file with "
1193  "the provided one or two character unit name." ),
1194  "" // Default value
1195  ) );
1196 
1197  datasetOptions.insert( "SUB_UNIT_NAME", new StringOption(
1198  QObject::tr( "Override the sub unit name from the seed file with the provided "
1199  "one or two character unit name." ),
1200  "" // Default value
1201  ) );
1202 
1203  datasetOptions.insert( "SUB_UNITS_PER_MASTER_UNIT", new IntOption(
1204  QObject::tr( "Override the number of subunits per master unit. "
1205  "By default the seed file value is used." ),
1206  0 // Default value
1207  ) );
1208 
1209  datasetOptions.insert( "UOR_PER_SUB_UNIT", new IntOption(
1210  QObject::tr( "Override the number of UORs (Units of Resolution) "
1211  "per sub unit. By default the seed file value is used." ),
1212  0 // Default value
1213  ) );
1214 
1215  datasetOptions.insert( "ORIGIN", new StringOption(
1216  QObject::tr( "ORIGIN=x,y,z: Override the origin of the design plane. "
1217  "By default the origin from the seed file is used." ),
1218  "" // Default value
1219  ) );
1220 
1221  driverMetadata.insert( "DGN",
1222  MetaData(
1223  "Microstation DGN",
1224  QObject::tr( "Microstation DGN" ),
1225  "*.dgn",
1226  "dgn",
1227  datasetOptions,
1228  layerOptions
1229  )
1230  );
1231 
1232  // Microstation DGN
1233  datasetOptions.clear();
1234  layerOptions.clear();
1235 
1236  driverMetadata.insert( "DGN",
1237  MetaData(
1238  "Microstation DGN",
1239  QObject::tr( "Microstation DGN" ),
1240  "*.dgn",
1241  "dgn",
1242  datasetOptions,
1243  layerOptions
1244  )
1245  );
1246 
1247  // S-57 Base file
1248  datasetOptions.clear();
1249  layerOptions.clear();
1250 
1251  datasetOptions.insert( "UPDATES", new SetOption(
1252  QObject::tr( "Should update files be incorporated into the base data on the fly. " ),
1253  QStringList()
1254  << "APPLY"
1255  << "IGNORE",
1256  "APPLY" // Default value
1257  ) );
1258 
1259  datasetOptions.insert( "SPLIT_MULTIPOINT", new BoolOption(
1260  QObject::tr( "Should multipoint soundings be split into many single point sounding features. "
1261  "Multipoint geometries are not well handled by many formats, "
1262  "so it can be convenient to split single sounding features with many points "
1263  "into many single point features." ),
1264  false // Default value
1265  ) );
1266 
1267  datasetOptions.insert( "ADD_SOUNDG_DEPTH", new BoolOption(
1268  QObject::tr( "Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1269  "of the sounding. This should only be enabled with SPLIT_MULTIPOINT is "
1270  "also enabled." ),
1271  false // Default value
1272  ) );
1273 
1274  datasetOptions.insert( "RETURN_PRIMITIVES", new BoolOption(
1275  QObject::tr( "Should all the low level geometry primitives be returned as special "
1276  "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1277  true // Default value
1278  ) );
1279 
1280  datasetOptions.insert( "PRESERVE_EMPTY_NUMBERS", new BoolOption(
1281  QObject::tr( "If enabled, numeric attributes assigned an empty string as a value will "
1282  "be preserved as a special numeric value. This option should not generally "
1283  "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1284  false // Default value
1285  ) );
1286 
1287  datasetOptions.insert( "LNAM_REFS", new BoolOption(
1288  QObject::tr( "Should LNAM and LNAM_REFS fields be attached to features capturing "
1289  "the feature to feature relationships in the FFPT group of the S-57 file." ),
1290  true // Default value
1291  ) );
1292 
1293  datasetOptions.insert( "RETURN_LINKAGES", new BoolOption(
1294  QObject::tr( "Should additional attributes relating features to their underlying "
1295  "geometric primitives be attached. These are the values of the FSPT group, "
1296  "and are primarily needed when doing S-57 to S-57 translations." ),
1297  true // Default value
1298  ) );
1299 
1300  datasetOptions.insert( "RECODE_BY_DSSI", new BoolOption(
1301  QObject::tr( "Should attribute values be recoded to UTF-8 from the character encoding "
1302  "specified in the S57 DSSI record." ),
1303  false // Default value
1304  ) );
1305 
1306  // set OGR_S57_OPTIONS = "RETURN_PRIMITIVES=ON,RETURN_LINKAGES=ON,LNAM_REFS=ON"
1307 
1308  driverMetadata.insert( "S57",
1309  MetaData(
1310  "S-57 Base file",
1311  QObject::tr( "S-57 Base file" ),
1312  "*.000",
1313  "000",
1314  datasetOptions,
1315  layerOptions
1316  )
1317  );
1318 
1319  // Spatial Data Transfer Standard [SDTS]
1320  datasetOptions.clear();
1321  layerOptions.clear();
1322 
1323  driverMetadata.insert( "SDTS",
1324  MetaData(
1325  "Spatial Data Transfer Standard [SDTS]",
1326  QObject::tr( "Spatial Data Transfer Standard [SDTS]" ),
1327  "*catd.ddf",
1328  "ddf",
1329  datasetOptions,
1330  layerOptions
1331  )
1332  );
1333 
1334  // SQLite
1335  datasetOptions.clear();
1336  layerOptions.clear();
1337 
1338  datasetOptions.insert( "METADATA", new BoolOption(
1339  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1340  "tables in a new database. By default these metadata tables are created "
1341  "when a new database is created." ),
1342  true // Default value
1343  ) );
1344 
1345  // Will handle the spatialite alias
1346  datasetOptions.insert( "SPATIALITE", new HiddenOption(
1347  "NO"
1348  ) );
1349 
1350 
1351  datasetOptions.insert( "INIT_WITH_EPSG", new HiddenOption(
1352  "NO"
1353  ) );
1354 
1355  layerOptions.insert( "FORMAT", new SetOption(
1356  QObject::tr( "Controls the format used for the geometry column. Defaults to WKB."
1357  "This is generally more space and processing efficient, but harder "
1358  "to inspect or use in simple applications than WKT (Well Known Text)." ),
1359  QStringList()
1360  << "WKB"
1361  << "WKT",
1362  "WKB" // Default value
1363  ) );
1364 
1365  layerOptions.insert( "LAUNDER", new BoolOption(
1366  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1367  "in SQLite. Laundered names will be converted to lower case and some special "
1368  "characters(' - #) will be changed to underscores." ),
1369  true // Default value
1370  ) );
1371 
1372  layerOptions.insert( "SPATIAL_INDEX", new HiddenOption(
1373  "NO"
1374  ) );
1375 
1376  layerOptions.insert( "COMPRESS_GEOM", new HiddenOption(
1377  "NO"
1378  ) );
1379 
1380  layerOptions.insert( "SRID", new HiddenOption(
1381  ""
1382  ) );
1383 
1384  layerOptions.insert( "COMPRESS_COLUMNS", new StringOption(
1385  QObject::tr( "column_name1[,column_name2, ...] A list of (String) columns that "
1386  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1387  "for databases that have big string blobs. However, use with care, since "
1388  "the value of such columns will be seen as compressed binary content with "
1389  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1390  "modifying or queryings compressed columns, compression/decompression is "
1391  "done transparently. However, such columns cannot be (easily) queried with "
1392  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1393  "have the 'VARCHAR_deflate' declaration type." ),
1394  "" // Default value
1395  ) );
1396 
1397  driverMetadata.insert( "SQLite",
1398  MetaData(
1399  "SQLite",
1400  QObject::tr( "SQLite" ),
1401  "*.sqlite",
1402  "sqlite",
1403  datasetOptions,
1404  layerOptions
1405  )
1406  );
1407 
1408  // SpatiaLite
1409  datasetOptions.clear();
1410  layerOptions.clear();
1411 
1412  datasetOptions.insert( "METADATA", new BoolOption(
1413  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1414  "tables in a new database. By default these metadata tables are created "
1415  "when a new database is created." ),
1416  true // Default value
1417  ) );
1418 
1419  datasetOptions.insert( "SPATIALITE", new HiddenOption(
1420  "YES"
1421  ) );
1422 
1423  datasetOptions.insert( "INIT_WITH_EPSG", new BoolOption(
1424  QObject::tr( "Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
1425  "Set to NO for regular SQLite databases." ),
1426  true // Default value
1427  ) );
1428 
1429  layerOptions.insert( "FORMAT", new HiddenOption(
1430  "SPATIALITE"
1431  ) );
1432 
1433  layerOptions.insert( "LAUNDER", new BoolOption(
1434  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1435  "in SQLite. Laundered names will be converted to lower case and some special "
1436  "characters(' - #) will be changed to underscores." ),
1437  true // Default value
1438  ) );
1439 
1440  layerOptions.insert( "SPATIAL_INDEX", new BoolOption(
1441  QObject::tr( "If the database is of the SpatiaLite flavour, and if OGR is linked "
1442  "against libspatialite, this option can be used to control if a spatial "
1443  "index must be created." ),
1444  true // Default value
1445  ) );
1446 
1447  layerOptions.insert( "COMPRESS_GEOM", new BoolOption(
1448  QObject::tr( "If the format of the geometry BLOB is of the SpatiaLite flavour, "
1449  "this option can be used to control if the compressed format for "
1450  "geometries (LINESTRINGs, POLYGONs) must be used" ),
1451  false // Default value
1452  ) );
1453 
1454  layerOptions.insert( "SRID", new StringOption(
1455  QObject::tr( "Used to force the SRID number of the SRS associated with the layer. "
1456  "When this option isn't specified and that a SRS is associated with the "
1457  "layer, a search is made in the spatial_ref_sys to find a match for the "
1458  "SRS, and, if there is no match, a new entry is inserted for the SRS in "
1459  "the spatial_ref_sys table. When the SRID option is specified, this "
1460  "search (and the eventual insertion of a new entry) will not be done: "
1461  "the specified SRID is used as such." ),
1462  "" // Default value
1463  ) );
1464 
1465  layerOptions.insert( "COMPRESS_COLUMNS", new StringOption(
1466  QObject::tr( "column_name1[,column_name2, ...] A list of (String) columns that "
1467  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1468  "for databases that have big string blobs. However, use with care, since "
1469  "the value of such columns will be seen as compressed binary content with "
1470  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1471  "modifying or queryings compressed columns, compression/decompression is "
1472  "done transparently. However, such columns cannot be (easily) queried with "
1473  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1474  "have the 'VARCHAR_deflate' declaration type." ),
1475  "" // Default value
1476  ) );
1477 
1478  driverMetadata.insert( "SpatiaLite",
1479  MetaData(
1480  "SpatiaLite",
1481  QObject::tr( "SpatiaLite" ),
1482  "*.sqlite",
1483  "sqlite",
1484  datasetOptions,
1485  layerOptions
1486  )
1487  );
1488  // AutoCAD DXF
1489  datasetOptions.clear();
1490  layerOptions.clear();
1491 
1492 #if 0
1493  datasetOptions.insert( "HEADER", new StringOption(
1494  QObject::tr( "Override the header file used - in place of header.dxf." ),
1495  "" // Default value
1496  ) );
1497 
1498  datasetOptions.insert( "TRAILER", new StringOption(
1499  QObject::tr( "Override the trailer file used - in place of trailer.dxf." ),
1500  "" // Default value
1501  ) );
1502 #endif
1503 
1504  driverMetadata.insert( "DXF",
1505  MetaData(
1506  "AutoCAD DXF",
1507  QObject::tr( "AutoCAD DXF" ),
1508  "*.dxf",
1509  "dxf",
1510  datasetOptions,
1511  layerOptions
1512  )
1513  );
1514 
1515  // Geoconcept
1516  datasetOptions.clear();
1517  layerOptions.clear();
1518 
1519  datasetOptions.insert( "EXTENSION", new SetOption(
1520  QObject::tr( "Indicates the GeoConcept export file extension. "
1521  "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
1522  QStringList()
1523  << "GXT"
1524  << "TXT",
1525  "GXT" // Default value
1526  ) );
1527 
1528 #if 0
1529  datasetOptions.insert( "CONFIG", new StringOption(
1530  QObject::tr( "path to the GCT : the GCT file describe the GeoConcept types definitions: "
1531  "In this file, every line must start with //# followed by a keyword. "
1532  "Lines starting with // are comments." ),
1533  "" // Default value
1534  ) );
1535 #endif
1536 
1537  driverMetadata.insert( "Geoconcept",
1538  MetaData(
1539  "Geoconcept",
1540  QObject::tr( "Geoconcept" ),
1541  "*.gxt *.txt",
1542  "gxt",
1543  datasetOptions,
1544  layerOptions
1545  )
1546  );
1547 
1548  // ESRI FileGDB
1549  datasetOptions.clear();
1550  layerOptions.clear();
1551 
1552  layerOptions.insert( "FEATURE_DATASET", new StringOption(
1553  QObject::tr( "When this option is set, the new layer will be created inside the named "
1554  "FeatureDataset folder. If the folder does not already exist, it will be created." ),
1555  "" // Default value
1556  ) );
1557 
1558  layerOptions.insert( "GEOMETRY_NAME", new StringOption(
1559  QObject::tr( "Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
1560  "SHAPE" // Default value
1561  ) );
1562 
1563  layerOptions.insert( "OID_NAME", new StringOption(
1564  QObject::tr( "Name of the OID column to create. Defaults to 'OBJECTID'." ),
1565  "OBJECTID" // Default value
1566  ) );
1567 
1568  driverMetadata.insert( "FileGDB",
1569  MetaData(
1570  "ESRI FileGDB",
1571  QObject::tr( "ESRI FileGDB" ),
1572  "*.gdb",
1573  "gdb",
1574  datasetOptions,
1575  layerOptions
1576  )
1577  );
1578 
1579  // XLSX
1580  datasetOptions.clear();
1581  layerOptions.clear();
1582 
1583  layerOptions.insert( "OGR_XLSX_FIELD_TYPES", new SetOption(
1584  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
1585  "to STRING, all fields will be of String type." ),
1586  QStringList()
1587  << "AUTO"
1588  << "STRING",
1589  "AUTO", // Default value
1590  false // Allow None
1591  ) );
1592 
1593  driverMetadata.insert( "XLSX",
1594  MetaData(
1595  "MS Office Open XML spreadsheet",
1596  QObject::tr( "MS Office Open XML spreadsheet" ),
1597  "*.xlsx",
1598  "xlsx",
1599  datasetOptions,
1600  layerOptions
1601  )
1602  );
1603 
1604  // ODS
1605  datasetOptions.clear();
1606  layerOptions.clear();
1607 
1608  layerOptions.insert( "OGR_ODS_FIELD_TYPES", new SetOption(
1609  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
1610  "to STRING, all fields will be of String type." ),
1611  QStringList()
1612  << "AUTO"
1613  << "STRING",
1614  "AUTO", // Default value
1615  false // Allow None
1616  ) );
1617 
1618  driverMetadata.insert( "ODS",
1619  MetaData(
1620  "Open Document Spreadsheet",
1621  QObject::tr( "Open Document Spreadsheet" ),
1622  "*.ods",
1623  "ods",
1624  datasetOptions,
1625  layerOptions
1626  )
1627  );
1628 
1629  return driverMetadata;
1630 }
1631 
1633 {
1634  static const QMap<QString, MetaData> sDriverMetadata = initMetaData();
1635 
1636  QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.constBegin();
1637 
1638  for ( ; it != sDriverMetadata.constEnd(); ++it )
1639  {
1640  if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
1641  {
1642  driverMetadata = it.value();
1643  return true;
1644  }
1645  }
1646 
1647  return false;
1648 }
1649 
1651 {
1652  type = QgsWKBTypes::dropM( type );
1653 
1654  OGRwkbGeometryType ogrType = static_cast<OGRwkbGeometryType>( type );
1655 
1656  if ( type >= QgsWKBTypes::PointZ && type <= QgsWKBTypes::GeometryCollectionZ )
1657  {
1658  ogrType = static_cast<OGRwkbGeometryType>( QgsWKBTypes::to25D( type ) );
1659  }
1660  return ogrType;
1661 }
1662 
1664 {
1665  return mError;
1666 }
1667 
1669 {
1670  return mErrorMessage;
1671 }
1672 
1674 {
1675  // create the feature
1676  OGRFeatureH poFeature = createFeature( feature );
1677  if ( !poFeature )
1678  return false;
1679 
1680  //add OGR feature style type
1681  if ( mSymbologyExport != NoSymbology && renderer )
1682  {
1683  mRenderContext.expressionContext().setFeature( feature );
1684  //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
1685  QgsSymbolV2List symbols = renderer->symbolsForFeature( feature, mRenderContext );
1686  QString styleString;
1687  QString currentStyle;
1688 
1689  QgsSymbolV2List::const_iterator symbolIt = symbols.constBegin();
1690  for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
1691  {
1692  int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
1693  for ( int i = 0; i < nSymbolLayers; ++i )
1694  {
1695 #if 0
1696  QMap< QgsSymbolLayerV2*, QString >::const_iterator it = mSymbolLayerTable.find(( *symbolIt )->symbolLayer( i ) );
1697  if ( it == mSymbolLayerTable.constEnd() )
1698  {
1699  continue;
1700  }
1701 #endif
1702  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
1703  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), outputUnit );
1704 
1705  currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
1706 
1708  {
1709  if ( symbolIt != symbols.constBegin() || i != 0 )
1710  {
1711  styleString.append( ';' );
1712  }
1713  styleString.append( currentStyle );
1714  }
1715  else if ( mSymbologyExport == SymbolLayerSymbology )
1716  {
1717  OGR_F_SetStyleString( poFeature, currentStyle.toLocal8Bit().data() );
1718  if ( !writeFeature( mLayer, poFeature ) )
1719  {
1720  return false;
1721  }
1722  }
1723  }
1724  }
1725  OGR_F_SetStyleString( poFeature, styleString.toLocal8Bit().data() );
1726  }
1727 
1729  {
1730  if ( !writeFeature( mLayer, poFeature ) )
1731  {
1732  return false;
1733  }
1734  }
1735 
1736  OGR_F_Destroy( poFeature );
1737  return true;
1738 }
1739 
1740 OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
1741 {
1742  QgsLocaleNumC l; // Make sure the decimal delimiter is a dot
1743  Q_UNUSED( l );
1744 
1745  OGRFeatureH poFeature = OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) );
1746 
1747  qint64 fid = FID_TO_NUMBER( feature.id() );
1748  if ( fid > std::numeric_limits<int>::max() )
1749  {
1750  QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
1751  OGRErr err = OGR_F_SetFID( poFeature, static_cast<long>( fid ) );
1752  if ( err != OGRERR_NONE )
1753  {
1754  QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
1755  .arg( feature.id() )
1756  .arg( err ).arg( CPLGetLastErrorMsg() )
1757  );
1758  }
1759  }
1760 
1761  // attribute handling
1763  {
1764  int fldIdx = it.key();
1765  int ogrField = it.value();
1766 
1767  const QVariant& attrValue = feature.attribute( fldIdx );
1768 
1769  if ( !attrValue.isValid() || attrValue.isNull() )
1770  continue;
1771 
1772  switch ( attrValue.type() )
1773  {
1774 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
1775  case QVariant::Int:
1776  case QVariant::UInt:
1777  OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
1778  break;
1779  case QVariant::LongLong:
1780  case QVariant::ULongLong:
1781  OGR_F_SetFieldInteger64( poFeature, ogrField, attrValue.toLongLong() );
1782  break;
1783  case QVariant::String:
1784  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1785  break;
1786 #else
1787  case QVariant::Int:
1788  OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
1789  break;
1790  case QVariant::String:
1791  case QVariant::LongLong:
1792  case QVariant::UInt:
1793  case QVariant::ULongLong:
1794  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1795  break;
1796 #endif
1797  case QVariant::Double:
1798  OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() );
1799  break;
1800  case QVariant::Date:
1801  OGR_F_SetFieldDateTime( poFeature, ogrField,
1802  attrValue.toDate().year(),
1803  attrValue.toDate().month(),
1804  attrValue.toDate().day(),
1805  0, 0, 0, 0 );
1806  break;
1807  case QVariant::DateTime:
1808  if ( mOgrDriverName == "ESRI Shapefile" )
1809  {
1810  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toDateTime().toString( "yyyy/MM/dd hh:mm:ss.zzz" ) ).data() );
1811  }
1812  else
1813  {
1814  OGR_F_SetFieldDateTime( poFeature, ogrField,
1815  attrValue.toDateTime().date().year(),
1816  attrValue.toDateTime().date().month(),
1817  attrValue.toDateTime().date().day(),
1818  attrValue.toDateTime().time().hour(),
1819  attrValue.toDateTime().time().minute(),
1820  attrValue.toDateTime().time().second(),
1821  0 );
1822  }
1823  break;
1824  case QVariant::Time:
1825  if ( mOgrDriverName == "ESRI Shapefile" )
1826  {
1827  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1828  }
1829  else
1830  {
1831  OGR_F_SetFieldDateTime( poFeature, ogrField,
1832  0, 0, 0,
1833  attrValue.toTime().hour(),
1834  attrValue.toTime().minute(),
1835  attrValue.toTime().second(),
1836  0 );
1837  }
1838  break;
1839  case QVariant::Invalid:
1840  break;
1841  default:
1842  mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
1843  .arg( mFields.at( fldIdx ).name() )
1844  .arg( ogrField )
1845  .arg( attrValue.typeName(),
1846  attrValue.toString() );
1849  return nullptr;
1850  }
1851  }
1852 
1854  {
1855  if ( feature.constGeometry() && !feature.constGeometry()->isEmpty() )
1856  {
1857  // build geometry from WKB
1858  QgsGeometry* geom = feature.geometry();
1859 
1860  // turn single geometry to multi geometry if needed
1863  {
1864  geom->convertToMultiType();
1865  }
1866 
1867  if ( geom->geometry()->wkbType() != mWkbType )
1868  {
1869  OGRGeometryH mGeom2 = nullptr;
1870 
1871  // If requested WKB type is 25D and geometry WKB type is 3D,
1872  // we must force the use of 25D.
1874  {
1875  //ND: I suspect there's a bug here, in that this is NOT converting the geometry's WKB type,
1876  //so the exported WKB has a different type to what the OGRGeometry is expecting.
1877  //possibly this is handled already in OGR, but it should be fixed regardless by actually converting
1878  //geom to the correct WKB type
1879  QgsWKBTypes::Type wkbType = geom->geometry()->wkbType();
1880  if ( wkbType >= QgsWKBTypes::PointZ && wkbType <= QgsWKBTypes::MultiPolygonZ )
1881  {
1883  mGeom2 = createEmptyGeometry( wkbType25d );
1884  }
1885  }
1886 
1887  if ( !mGeom2 )
1888  {
1889  // there's a problem when layer type is set as wkbtype Polygon
1890  // although there are also features of type MultiPolygon
1891  // (at least in OGR provider)
1892  // If the feature's wkbtype is different from the layer's wkbtype,
1893  // try to export it too.
1894  //
1895  // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
1896  // i.e. Polygons can't be imported to OGRMultiPolygon
1897  mGeom2 = createEmptyGeometry( geom->geometry()->wkbType() );
1898  }
1899 
1900  if ( !mGeom2 )
1901  {
1902  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1903  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1906  OGR_F_Destroy( poFeature );
1907  return nullptr;
1908  }
1909 
1910  OGRErr err = OGR_G_ImportFromWkb( mGeom2, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
1911  if ( err != OGRERR_NONE )
1912  {
1913  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1914  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1917  OGR_F_Destroy( poFeature );
1918  return nullptr;
1919  }
1920 
1921  // pass ownership to geometry
1922  OGR_F_SetGeometryDirectly( poFeature, mGeom2 );
1923  }
1924  else // wkb type matches
1925  {
1926  OGRErr err = OGR_G_ImportFromWkb( mGeom, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
1927  if ( err != OGRERR_NONE )
1928  {
1929  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1930  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1933  OGR_F_Destroy( poFeature );
1934  return nullptr;
1935  }
1936 
1937  // set geometry (ownership is not passed to OGR)
1938  OGR_F_SetGeometry( poFeature, mGeom );
1939  }
1940  }
1941  else
1942  {
1943  OGR_F_SetGeometry( poFeature, createEmptyGeometry( mWkbType ) );
1944  }
1945  }
1946  return poFeature;
1947 }
1948 
1949 void QgsVectorFileWriter::resetMap( const QgsAttributeList &attributes )
1950 {
1953  for ( int i = 0; i < attributes.size(); i++ )
1954  {
1955  mAttrIdxToOgrIdx.insert( attributes[i], omap[i] );
1956  }
1957 }
1958 
1959 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
1960 {
1961  if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
1962  {
1963  mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1966  OGR_F_Destroy( feature );
1967  return false;
1968  }
1969  return true;
1970 }
1971 
1973 {
1974  if ( mGeom )
1975  {
1976  OGR_G_DestroyGeometry( mGeom );
1977  }
1978 
1979  if ( mDS )
1980  {
1981  OGR_DS_Destroy( mDS );
1982  }
1983 
1984  if ( mOgrRef )
1985  {
1986  OSRDestroySpatialReference( mOgrRef );
1987  }
1988 }
1989 
1992  const QString& fileName,
1993  const QString& fileEncoding,
1994  const QgsCoordinateReferenceSystem *destCRS,
1995  const QString& driverName,
1996  bool onlySelected,
1998  const QStringList &datasourceOptions,
1999  const QStringList &layerOptions,
2000  bool skipAttributeCreation,
2001  QString *newFilename,
2003  double symbologyScale,
2004  const QgsRectangle* filterExtent,
2005  QgsWKBTypes::Type overrideGeometryType,
2006  bool forceMulti,
2007  bool includeZ,
2008  QgsAttributeList attributes )
2009 {
2010  QgsCoordinateTransform* ct = nullptr;
2011  if ( destCRS && layer )
2012  {
2013  ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
2014  }
2015 
2016  QgsVectorFileWriter::WriterError error = writeAsVectorFormat( layer, fileName, fileEncoding, ct, driverName, onlySelected,
2017  errorMessage, datasourceOptions, layerOptions, skipAttributeCreation, newFilename, symbologyExport, symbologyScale, filterExtent, overrideGeometryType, forceMulti, includeZ, attributes );
2018  delete ct;
2019  return error;
2020 }
2021 
2023  const QString& fileName,
2024  const QString& fileEncoding,
2025  const QgsCoordinateTransform* ct,
2026  const QString& driverName,
2027  bool onlySelected,
2029  const QStringList &datasourceOptions,
2030  const QStringList &layerOptions,
2031  bool skipAttributeCreation,
2032  QString *newFilename,
2034  double symbologyScale,
2035  const QgsRectangle* filterExtent,
2036  QgsWKBTypes::Type overrideGeometryType,
2037  bool forceMulti,
2038  bool includeZ,
2039  QgsAttributeList attributes )
2040 {
2041  if ( !layer )
2042  {
2043  return ErrInvalidLayer;
2044  }
2045 
2046  bool shallTransform = false;
2047  const QgsCoordinateReferenceSystem* outputCRS = nullptr;
2048  if ( ct )
2049  {
2050  // This means we should transform
2051  outputCRS = &( ct->destCRS() );
2052  shallTransform = true;
2053  }
2054  else
2055  {
2056  // This means we shouldn't transform, use source CRS as output (if defined)
2057  outputCRS = &layer->crs();
2058  }
2059 
2060  QgsWKBTypes::Type destWkbType = QGis::fromOldWkbType( layer->wkbType() );
2061  if ( overrideGeometryType != QgsWKBTypes::Unknown )
2062  {
2063  destWkbType = QgsWKBTypes::flatType( overrideGeometryType );
2064  if ( QgsWKBTypes::hasZ( overrideGeometryType ) || includeZ )
2065  destWkbType = QgsWKBTypes::addZ( destWkbType );
2066  }
2067  if ( forceMulti )
2068  {
2069  destWkbType = QgsWKBTypes::multiType( destWkbType );
2070  }
2071 
2072  if ( skipAttributeCreation )
2073  attributes.clear();
2074  else if ( attributes.isEmpty() )
2075  {
2076  Q_FOREACH ( int idx, layer->attributeList() )
2077  {
2078  const QgsField &fld = layer->fields()[idx];
2079  if ( layer->providerType() == "oracle" && fld.typeName().contains( "SDO_GEOMETRY" ) )
2080  continue;
2081  attributes.append( idx );
2082  }
2083  }
2084 
2085  QgsFields fields;
2086  if ( !attributes.isEmpty() )
2087  {
2088  Q_FOREACH ( int attrIdx, attributes )
2089  {
2090  fields.append( layer->fields()[attrIdx] );
2091  }
2092  }
2093 
2094  if ( layer->providerType() == "ogr" && layer->dataProvider() )
2095  {
2096  QStringList theURIParts = layer->dataProvider()->dataSourceUri().split( '|' );
2097  QString srcFileName = theURIParts[0];
2098 
2099  if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2100  {
2101  if ( errorMessage )
2102  *errorMessage = QObject::tr( "Cannot overwrite a OGR layer in place" );
2103  return ErrCreateDataSource;
2104  }
2105 
2106  // Shapefiles might contain multi types although wkbType() only reports singles
2107  if ( layer->storageType() == "ESRI Shapefile" && !QgsWKBTypes::isMultiType( destWkbType ) )
2108  {
2109  QgsFeatureRequest req;
2110  if ( onlySelected )
2111  {
2112  req.setFilterFids( layer->selectedFeaturesIds() );
2113  }
2114  QgsFeatureIterator fit = layer->getFeatures( req );
2115  QgsFeature fet;
2116 
2117  while ( fit.nextFeature( fet ) )
2118  {
2119  if ( fet.constGeometry() && !fet.constGeometry()->isEmpty() && QgsWKBTypes::isMultiType( fet.constGeometry()->geometry()->wkbType() ) )
2120  {
2121  destWkbType = QgsWKBTypes::multiType( destWkbType );
2122  break;
2123  }
2124  }
2125  }
2126  }
2127  else if ( layer->providerType() == "spatialite" )
2128  {
2129  for ( int i = 0; i < fields.size(); i++ )
2130  {
2131  if ( fields.at( i ).type() == QVariant::LongLong )
2132  {
2133  QVariant min = layer->minimumValue( i );
2134  QVariant max = layer->maximumValue( i );
2135  if ( qMax( qAbs( min.toLongLong() ), qAbs( max.toLongLong() ) ) < INT_MAX )
2136  {
2137  fields[i].setType( QVariant::Int );
2138  }
2139  }
2140  }
2141  }
2142 
2143  QgsVectorFileWriter* writer =
2144  new QgsVectorFileWriter( fileName, fileEncoding, fields, QGis::fromNewWkbType( destWkbType ), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
2145  writer->setSymbologyScaleDenominator( symbologyScale );
2146 
2147 
2148  if ( newFilename )
2149  {
2150  QgsDebugMsg( "newFilename = " + *newFilename );
2151  }
2152 
2153  // check whether file creation was successful
2154  WriterError err = writer->hasError();
2155  if ( err != NoError )
2156  {
2157  if ( errorMessage )
2158  *errorMessage = writer->errorMessage();
2159  delete writer;
2160  return err;
2161  }
2162 
2163  if ( errorMessage )
2164  {
2165  errorMessage->clear();
2166  }
2167 
2168  QgsFeature fet;
2169 
2170  //add possible attributes needed by renderer
2171  writer->addRendererAttributes( layer, attributes );
2172 
2173  QgsFeatureRequest req;
2174  if ( layer->wkbType() == QGis::WKBNoGeometry )
2175  {
2177  }
2178  req.setSubsetOfAttributes( attributes );
2179  if ( onlySelected )
2180  req.setFilterFids( layer->selectedFeaturesIds() );
2181  QgsFeatureIterator fit = layer->getFeatures( req );
2182 
2183  //create symbol table if needed
2184  if ( writer->symbologyExport() != NoSymbology )
2185  {
2186  //writer->createSymbolLayerTable( layer, writer->mDS );
2187  }
2188 
2189  if ( writer->symbologyExport() == SymbolLayerSymbology )
2190  {
2191  QgsFeatureRendererV2* r = layer->rendererV2();
2193  && r->usingSymbolLevels() )
2194  {
2195  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
2196  delete writer;
2197  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
2198  }
2199  }
2200 
2201  int n = 0, errors = 0;
2202 
2203  //unit type
2204  QGis::UnitType mapUnits = layer->crs().mapUnits();
2205  if ( ct )
2206  {
2207  mapUnits = ct->destCRS().mapUnits();
2208  }
2209 
2210  writer->startRender( layer );
2211 
2212  // enabling transaction on databases that support it
2213  bool transactionsEnabled = true;
2214 
2215  if ( OGRERR_NONE != OGR_L_StartTransaction( writer->mLayer ) )
2216  {
2217  QgsDebugMsg( "Error when trying to enable transactions on OGRLayer." );
2218  transactionsEnabled = false;
2219  }
2220 
2221  writer->resetMap( attributes );
2222 
2223  // write all features
2224  while ( fit.nextFeature( fet ) )
2225  {
2226  if ( shallTransform )
2227  {
2228  try
2229  {
2230  if ( fet.geometry() )
2231  {
2232  fet.geometry()->transform( *ct );
2233  }
2234  }
2235  catch ( QgsCsException &e )
2236  {
2237  delete writer;
2238 
2239  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
2240  .arg( fet.id() ).arg( e.what() );
2241  QgsLogger::warning( msg );
2242  if ( errorMessage )
2243  *errorMessage = msg;
2244 
2245  return ErrProjection;
2246  }
2247  }
2248 
2249  if ( fet.constGeometry() && filterExtent && !fet.constGeometry()->intersects( *filterExtent ) )
2250  continue;
2251 
2252  if ( attributes.size() < 1 && skipAttributeCreation )
2253  {
2254  fet.initAttributes( 0 );
2255  }
2256 
2257  if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
2258  {
2259  WriterError err = writer->hasError();
2260  if ( err != NoError && errorMessage )
2261  {
2262  if ( errorMessage->isEmpty() )
2263  {
2264  *errorMessage = QObject::tr( "Feature write errors:" );
2265  }
2266  *errorMessage += '\n' + writer->errorMessage();
2267  }
2268  errors++;
2269 
2270  if ( errors > 1000 )
2271  {
2272  if ( errorMessage )
2273  {
2274  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
2275  }
2276 
2277  n = -1;
2278  break;
2279  }
2280  }
2281  n++;
2282  }
2283 
2284  if ( transactionsEnabled )
2285  {
2286  if ( OGRERR_NONE != OGR_L_CommitTransaction( writer->mLayer ) )
2287  {
2288  QgsDebugMsg( "Error while committing transaction on OGRLayer." );
2289  }
2290  }
2291 
2292  writer->stopRender( layer );
2293  delete writer;
2294 
2295  if ( errors > 0 && errorMessage && n > 0 )
2296  {
2297  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
2298  }
2299 
2300  return errors == 0 ? NoError : ErrFeatureWriteFailed;
2301 }
2302 
2303 
2305 {
2306  QFileInfo fi( theFileName );
2307  QDir dir = fi.dir();
2308 
2309  QStringList filter;
2310  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
2311  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
2312  {
2313  filter << fi.completeBaseName() + suffixes[i];
2314  }
2315 
2316  bool ok = true;
2317  Q_FOREACH ( const QString& file, dir.entryList( filter ) )
2318  {
2319  QFile f( dir.canonicalPath() + '/' + file );
2320  if ( !f.remove() )
2321  {
2322  QgsDebugMsg( QString( "Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
2323  ok = false;
2324  }
2325  }
2326 
2327  return ok;
2328 }
2329 
2331 {
2333  mRenderContext.setRendererScale( mSymbologyScaleDenominator );
2334 }
2335 
2337 {
2338  QMap<QString, QString> resultMap;
2339 
2341  int const drvCount = OGRGetDriverCount();
2342 
2343  for ( int i = 0; i < drvCount; ++i )
2344  {
2345  OGRSFDriverH drv = OGRGetDriver( i );
2346  if ( drv )
2347  {
2348  QString drvName = OGR_Dr_GetName( drv );
2349  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2350  {
2351  QString filterString = filterForDriver( drvName );
2352  if ( filterString.isEmpty() )
2353  continue;
2354 
2355  resultMap.insert( filterString, drvName );
2356  }
2357  }
2358  }
2359 
2360  return resultMap;
2361 }
2362 
2364 {
2365  QMap<QString, QString> resultMap;
2366 
2368  int const drvCount = OGRGetDriverCount();
2369 
2370  QStringList writableDrivers;
2371  for ( int i = 0; i < drvCount; ++i )
2372  {
2373  OGRSFDriverH drv = OGRGetDriver( i );
2374  if ( drv )
2375  {
2376  QString drvName = OGR_Dr_GetName( drv );
2377  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2378  {
2379  // Add separate format for Mapinfo MIF (MITAB is OGR default)
2380  if ( drvName == "MapInfo File" )
2381  {
2382  writableDrivers << "MapInfo MIF";
2383  }
2384  else if ( drvName == "SQLite" )
2385  {
2386  // Unfortunately it seems that there is no simple way to detect if
2387  // OGR SQLite driver is compiled with SpatiaLite support.
2388  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
2389  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
2390  // -> test if creation failes
2391  QString option = "SPATIALITE=YES";
2392  char **options = new char *[2];
2393  options[0] = CPLStrdup( option.toLocal8Bit().data() );
2394  options[1] = nullptr;
2395  OGRSFDriverH poDriver;
2397  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() );
2398  if ( poDriver )
2399  {
2400  OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ), options );
2401  if ( ds )
2402  {
2403  writableDrivers << "SpatiaLite";
2404  OGR_Dr_DeleteDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ) );
2405  OGR_DS_Destroy( ds );
2406  }
2407  }
2408  CPLFree( options[0] );
2409  delete [] options;
2410  }
2411  else if ( drvName == "ESRI Shapefile" )
2412  {
2413  writableDrivers << "DBF file";
2414  }
2415  writableDrivers << drvName;
2416  }
2417  }
2418  }
2419 
2420  Q_FOREACH ( const QString& drvName, writableDrivers )
2421  {
2422  QString longName;
2423  QString trLongName;
2424  QString glob;
2425  QString exts;
2426  if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() )
2427  {
2428  resultMap.insert( trLongName, drvName );
2429  }
2430  }
2431 
2432  return resultMap;
2433 }
2434 
2436 {
2437  QString filterString;
2439  QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
2440  for ( ; it != driverFormatMap.constEnd(); ++it )
2441  {
2442  if ( !filterString.isEmpty() )
2443  filterString += ";;";
2444 
2445  filterString += it.key();
2446  }
2447  return filterString;
2448 }
2449 
2451 {
2452  QString longName;
2453  QString trLongName;
2454  QString glob;
2455  QString exts;
2456  if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() )
2457  return "";
2458 
2459  return trLongName + " [OGR] (" + glob.toLower() + ' ' + glob.toUpper() + ')';
2460 }
2461 
2463 {
2464  if ( codecName == "System" )
2465  return QString( "LDID/0" );
2466 
2467  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
2468  if ( re.exactMatch( codecName ) )
2469  {
2470  QString c = re.cap( 2 ).remove( '-' );
2471  bool isNumber;
2472  c.toInt( &isNumber );
2473  if ( isNumber )
2474  return c;
2475  }
2476  return codecName;
2477 }
2478 
2479 bool QgsVectorFileWriter::driverMetadata( const QString& driverName, QString &longName, QString &trLongName, QString &glob, QString &ext )
2480 {
2481  if ( driverName.startsWith( "AVCE00" ) )
2482  {
2483  longName = "Arc/Info ASCII Coverage";
2484  trLongName = QObject::tr( "Arc/Info ASCII Coverage" );
2485  glob = "*.e00";
2486  ext = "e00";
2487  }
2488  else if ( driverName.startsWith( "BNA" ) )
2489  {
2490  longName = "Atlas BNA";
2491  trLongName = QObject::tr( "Atlas BNA" );
2492  glob = "*.bna";
2493  ext = "bna";
2494  }
2495  else if ( driverName.startsWith( "CSV" ) )
2496  {
2497  longName = "Comma Separated Value [CSV]";
2498  trLongName = QObject::tr( "Comma Separated Value [CSV]" );
2499  glob = "*.csv";
2500  ext = "csv";
2501  }
2502  else if ( driverName.startsWith( "ESRI" ) )
2503  {
2504  longName = "ESRI Shapefile";
2505  trLongName = QObject::tr( "ESRI Shapefile" );
2506  glob = "*.shp";
2507  ext = "shp";
2508  }
2509  else if ( driverName.startsWith( "DBF file" ) )
2510  {
2511  longName = "DBF File";
2512  trLongName = QObject::tr( "DBF file" );
2513  glob = "*.dbf";
2514  ext = "dbf";
2515  }
2516  else if ( driverName.startsWith( "FMEObjects Gateway" ) )
2517  {
2518  longName = "FMEObjects Gateway";
2519  trLongName = QObject::tr( "FMEObjects Gateway" );
2520  glob = "*.fdd";
2521  ext = "fdd";
2522  }
2523  else if ( driverName.startsWith( "GeoJSON" ) )
2524  {
2525  longName = "GeoJSON";
2526  trLongName = QObject::tr( "GeoJSON" );
2527  glob = "*.geojson";
2528  ext = "geojson";
2529  }
2530  else if ( driverName.startsWith( "GPKG" ) )
2531  {
2532  longName = "GeoPackage";
2533  trLongName = QObject::tr( "GeoPackage" );
2534  glob = "*.gpkg";
2535  ext = "gpkg";
2536  }
2537  else if ( driverName.startsWith( "GeoRSS" ) )
2538  {
2539  longName = "GeoRSS";
2540  trLongName = QObject::tr( "GeoRSS" );
2541  glob = "*.xml";
2542  ext = "xml";
2543  }
2544  else if ( driverName.startsWith( "GML" ) )
2545  {
2546  longName = "Geography Markup Language [GML]";
2547  trLongName = QObject::tr( "Geography Markup Language [GML]" );
2548  glob = "*.gml";
2549  ext = "gml";
2550  }
2551  else if ( driverName.startsWith( "GMT" ) )
2552  {
2553  longName = "Generic Mapping Tools [GMT]";
2554  trLongName = QObject::tr( "Generic Mapping Tools [GMT]" );
2555  glob = "*.gmt";
2556  ext = "gmt";
2557  }
2558  else if ( driverName.startsWith( "GPX" ) )
2559  {
2560  longName = "GPS eXchange Format [GPX]";
2561  trLongName = QObject::tr( "GPS eXchange Format [GPX]" );
2562  glob = "*.gpx";
2563  ext = "gpx";
2564  }
2565  else if ( driverName.startsWith( "Interlis 1" ) )
2566  {
2567  longName = "INTERLIS 1";
2568  trLongName = QObject::tr( "INTERLIS 1" );
2569  glob = "*.itf *.xml *.ili";
2570  ext = "ili";
2571  }
2572  else if ( driverName.startsWith( "Interlis 2" ) )
2573  {
2574  longName = "INTERLIS 2";
2575  trLongName = QObject::tr( "INTERLIS 2" );
2576  glob = "*.itf *.xml *.ili";
2577  ext = "ili";
2578  }
2579  else if ( driverName.startsWith( "KML" ) )
2580  {
2581  longName = "Keyhole Markup Language [KML]";
2582  trLongName = QObject::tr( "Keyhole Markup Language [KML]" );
2583  glob = "*.kml";
2584  ext = "kml";
2585  }
2586  else if ( driverName.startsWith( "MapInfo File" ) )
2587  {
2588  longName = "Mapinfo TAB";
2589  trLongName = QObject::tr( "Mapinfo TAB" );
2590  glob = "*.tab";
2591  ext = "tab";
2592  }
2593  // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF
2594  else if ( driverName.startsWith( "MapInfo MIF" ) )
2595  {
2596  longName = "Mapinfo MIF";
2597  trLongName = QObject::tr( "Mapinfo MIF" );
2598  glob = "*.mif";
2599  ext = "mif";
2600  }
2601  else if ( driverName.startsWith( "DGN" ) )
2602  {
2603  longName = "Microstation DGN";
2604  trLongName = QObject::tr( "Microstation DGN" );
2605  glob = "*.dgn";
2606  ext = "dgn";
2607  }
2608  else if ( driverName.startsWith( "S57" ) )
2609  {
2610  longName = "S-57 Base file";
2611  trLongName = QObject::tr( "S-57 Base file" );
2612  glob = "*.000";
2613  ext = "000";
2614  }
2615  else if ( driverName.startsWith( "SDTS" ) )
2616  {
2617  longName = "Spatial Data Transfer Standard [SDTS]";
2618  trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" );
2619  glob = "*catd.ddf";
2620  ext = "ddf";
2621  }
2622  else if ( driverName.startsWith( "SQLite" ) )
2623  {
2624  longName = "SQLite";
2625  trLongName = QObject::tr( "SQLite" );
2626  glob = "*.sqlite";
2627  ext = "sqlite";
2628  }
2629  // QGIS internal addition for SpatialLite
2630  else if ( driverName.startsWith( "SpatiaLite" ) )
2631  {
2632  longName = "SpatiaLite";
2633  trLongName = QObject::tr( "SpatiaLite" );
2634  glob = "*.sqlite";
2635  ext = "sqlite";
2636  }
2637  else if ( driverName.startsWith( "DXF" ) )
2638  {
2639  longName = "AutoCAD DXF";
2640  trLongName = QObject::tr( "AutoCAD DXF" );
2641  glob = "*.dxf";
2642  ext = "dxf";
2643  }
2644  else if ( driverName.startsWith( "Geoconcept" ) )
2645  {
2646  longName = "Geoconcept";
2647  trLongName = QObject::tr( "Geoconcept" );
2648  glob = "*.gxt *.txt";
2649  ext = "gxt";
2650  }
2651  else if ( driverName.startsWith( "FileGDB" ) )
2652  {
2653  longName = "ESRI FileGDB";
2654  trLongName = QObject::tr( "ESRI FileGDB" );
2655  glob = "*.gdb";
2656  ext = "gdb";
2657  }
2658  else if ( driverName.startsWith( "XLSX" ) )
2659  {
2660  longName = "MS Office Open XML spreadsheet [XLSX]";
2661  trLongName = QObject::tr( "MS Office Open XML spreadsheet [XLSX]" );
2662  glob = "*.xlsx";
2663  ext = "xlsx";
2664  }
2665  else if ( driverName.startsWith( "ODS" ) )
2666  {
2667  longName = "Open Document Spreadsheet";
2668  trLongName = QObject::tr( "Open Document Spreadsheet [ODS]" );
2669  glob = "*.ods";
2670  ext = "ods";
2671  }
2672  else
2673  {
2674  return false;
2675  }
2676 
2677  return true;
2678 }
2679 
2680 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds )
2681 {
2682  if ( !vl || !ds )
2683  {
2684  return;
2685  }
2686 
2687  QgsFeatureRendererV2* renderer = vl->rendererV2();
2688  if ( !renderer )
2689  {
2690  return;
2691  }
2692 
2693  //unit type
2694  QGis::UnitType mapUnits = vl->crs().mapUnits();
2695  if ( ct )
2696  {
2697  mapUnits = ct->destCRS().mapUnits();
2698  }
2699 
2700 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700
2701  mSymbolLayerTable.clear();
2702  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
2703  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
2704 
2705  //get symbols
2706  int nTotalLevels = 0;
2707  QgsSymbolV2List symbolList = renderer->symbols( mRenderContext );
2708  QgsSymbolV2List::iterator symbolIt = symbolList.begin();
2709  for ( ; symbolIt != symbolList.end(); ++symbolIt )
2710  {
2711  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
2712  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
2713 
2714  int nLevels = ( *symbolIt )->symbolLayerCount();
2715  for ( int i = 0; i < nLevels; ++i )
2716  {
2717  mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
2718  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
2719  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
2720  ++nTotalLevels;
2721  }
2722  }
2723  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
2724 #endif
2725 }
2726 
2727 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit,
2729 {
2730  if ( !layer )
2731  return ErrInvalidLayer;
2732 
2733  mRenderContext.expressionContext() = QgsExpressionContext();
2737 
2738  QgsFeatureRendererV2 *renderer = layer->rendererV2();
2739  if ( !renderer )
2740  return ErrInvalidLayer;
2741 
2743 
2744  //unit type
2745  QGis::UnitType mapUnits = layer->crs().mapUnits();
2746  if ( ct )
2747  {
2748  mapUnits = ct->destCRS().mapUnits();
2749  }
2750 
2751  startRender( layer );
2752 
2753  //fetch features
2754  QgsFeature fet;
2755  QgsSymbolV2* featureSymbol = nullptr;
2756  while ( fit.nextFeature( fet ) )
2757  {
2758  if ( ct )
2759  {
2760  try
2761  {
2762  if ( fet.geometry() )
2763  {
2764  fet.geometry()->transform( *ct );
2765  }
2766  }
2767  catch ( QgsCsException &e )
2768  {
2769  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
2770  .arg( e.what() );
2771  QgsLogger::warning( msg );
2772  if ( errorMessage )
2773  *errorMessage = msg;
2774 
2775  return ErrProjection;
2776  }
2777  }
2778  mRenderContext.expressionContext().setFeature( fet );
2779 
2780  featureSymbol = renderer->symbolForFeature( fet, mRenderContext );
2781  if ( !featureSymbol )
2782  {
2783  continue;
2784  }
2785 
2786  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
2787  if ( it == features.end() )
2788  {
2789  it = features.insert( featureSymbol, QList<QgsFeature>() );
2790  }
2791  it.value().append( fet );
2792  }
2793 
2794  //find out order
2795  QgsSymbolV2LevelOrder levels;
2796  QgsSymbolV2List symbols = renderer->symbols( mRenderContext );
2797  for ( int i = 0; i < symbols.count(); i++ )
2798  {
2799  QgsSymbolV2* sym = symbols[i];
2800  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
2801  {
2802  int level = sym->symbolLayer( j )->renderingPass();
2803  if ( level < 0 || level >= 1000 ) // ignore invalid levels
2804  continue;
2805  QgsSymbolV2LevelItem item( sym, j );
2806  while ( level >= levels.count() ) // append new empty levels
2807  levels.append( QgsSymbolV2Level() );
2808  levels[level].append( item );
2809  }
2810  }
2811 
2812  int nErrors = 0;
2813  int nTotalFeatures = 0;
2814 
2815  //export symbol layers and symbology
2816  for ( int l = 0; l < levels.count(); l++ )
2817  {
2818  QgsSymbolV2Level& level = levels[l];
2819  for ( int i = 0; i < level.count(); i++ )
2820  {
2821  QgsSymbolV2LevelItem& item = level[i];
2822  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
2823  if ( levelIt == features.end() )
2824  {
2825  ++nErrors;
2826  continue;
2827  }
2828 
2829  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
2830  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
2831 
2832  int llayer = item.layer();
2833  QList<QgsFeature>& featureList = levelIt.value();
2834  QList<QgsFeature>::iterator featureIt = featureList.begin();
2835  for ( ; featureIt != featureList.end(); ++featureIt )
2836  {
2837  ++nTotalFeatures;
2838  OGRFeatureH ogrFeature = createFeature( *featureIt );
2839  if ( !ogrFeature )
2840  {
2841  ++nErrors;
2842  continue;
2843  }
2844 
2845  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
2846  if ( !styleString.isEmpty() )
2847  {
2848  OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
2849  if ( !writeFeature( mLayer, ogrFeature ) )
2850  {
2851  ++nErrors;
2852  }
2853  }
2854  OGR_F_Destroy( ogrFeature );
2855  }
2856  }
2857  }
2858 
2859  stopRender( layer );
2860 
2861  if ( nErrors > 0 && errorMessage )
2862  {
2863  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
2864  }
2865 
2867 }
2868 
2869 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
2870 {
2871  if ( symbolUnits == QgsSymbolV2::MM )
2872  {
2873  return 1.0;
2874  }
2875  else
2876  {
2877  //conversion factor map units -> mm
2878  if ( mapUnits == QGis::Meters )
2879  {
2880  return 1000 / scaleDenominator;
2881  }
2882 
2883  }
2884  return 1.0; //todo: map units
2885 }
2886 
2887 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
2888 {
2889  if ( symbolUnits == QgsSymbolV2::MapUnit )
2890  {
2891  return 1.0;
2892  }
2893  else
2894  {
2895  if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
2896  {
2897  return scaleDenominator / 1000;
2898  }
2899  }
2900  return 1.0;
2901 }
2902 
2903 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl )
2904 {
2905  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2906  if ( !renderer )
2907  {
2908  return;
2909  }
2910 
2911  renderer->startRender( mRenderContext, vl->fields() );
2912 }
2913 
2914 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl )
2915 {
2916  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2917  if ( !renderer )
2918  {
2919  return;
2920  }
2921 
2922  renderer->stopRender( mRenderContext );
2923 }
2924 
2925 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const
2926 {
2927  if ( mSymbologyExport == NoSymbology )
2928  {
2929  return nullptr;
2930  }
2931  if ( !vl )
2932  {
2933  return nullptr;
2934  }
2935 
2936  return vl->rendererV2();
2937 }
2938 
2939 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList )
2940 {
2941  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2942  if ( renderer )
2943  {
2944  QList<QString> rendererAttributes = renderer->usedAttributes();
2945  for ( int i = 0; i < rendererAttributes.size(); ++i )
2946  {
2947  int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
2948  if ( index != -1 )
2949  {
2950  attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
2951  }
2952  }
2953  }
2954 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
qlonglong toLongLong(bool *ok) const
void clear()
Wrapper for iterator of features from vector data provider or vector layer.
QString toString(Qt::DateFormat format) const
QByteArray fromUnicode(const QString &str) const
int minute() const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static unsigned index
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static QMap< QString, QString > supportedFiltersAndFormats()
Returns map with format filter string as key and OGR format key as value.
SymbologyExport symbologyExport() const
QString cap(int nth) const
QString & append(QChar ch)
QgsAttributeList attributeList() const
Returns list of attribute indexes.
iterator insert(const Key &key, const T &value)
QString toUpper() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
static OGRwkbGeometryType ogrTypeFromWkbType(QgsWKBTypes::Type type)
Get the ogr geometry type from an internal QGIS wkb type enum.
const Key key(const T &value) const
WriterError mError
Contains error value if construction was not successful.
static bool deleteShapeFile(const QString &theFileName)
Delete a shapefile (and its accompanying shx / dbf / prf)
void push_back(const T &value)
QVariant maximumValue(int index)
Returns maximum value for an attribute column or invalid variant in case of error.
static QString fileFilterString()
Returns filter string that can be used for dialogs.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:746
bool remove()
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QDateTime toDateTime() const
SymbologyExport mSymbologyExport
double mSymbologyScaleDenominator
Scale for symbology export (e.g.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:124
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:240
const_iterator constBegin() const
void setRendererScale(double scale)
const T & at(int i) const
QTime toTime() const
QString toWkt() const
Returns a WKT representation of this CRS.
static QGis::WkbType fromNewWkbType(QgsWKBTypes::Type type)
Converts from new (post 2.10) WKB type (OGC) to old WKB type.
Definition: qgis.cpp:146
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:476
int precision() const
Gets the precision of the field.
Definition: qgsfield.cpp:104
bool contains(const QString &str, Qt::CaseSensitivity cs) const
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.
Container of fields for a vector layer.
Definition: qgsfield.h:187
QTime time() const
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
bool addFeature(QgsFeature &feature, QgsFeatureRendererV2 *renderer=nullptr, QGis::UnitType outputUnit=QGis::Meters)
Add feature to the currently opened data source.
WkbType
Used for symbology operations.
Definition: qgis.h:57
static WriterError writeAsVectorFormat(QgsVectorLayer *layer, const QString &fileName, const QString &fileEncoding, const QgsCoordinateReferenceSystem *destCRS, const QString &driverName="ESRI Shapefile", bool onlySelected=false, QString *errorMessage=nullptr, const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), bool skipAttributeCreation=false, QString *newFilename=nullptr, SymbologyExport symbologyExport=NoSymbology, double symbologyScale=1.0, const QgsRectangle *filterExtent=nullptr, QgsWKBTypes::Type overrideGeometryType=QgsWKBTypes::Unknown, bool forceMulti=false, bool includeZ=false, QgsAttributeList attributes=QgsAttributeList())
Write contents of vector layer to an (OGR supported) vector formt.
The QGis class provides global constants for use throughout the application.
Definition: qgis.h:36
virtual QList< QString > usedAttributes()=0
Returns a set of attributes required for this renderer.
QString join(const QString &separator) const
bool exists() const
A convenience class for writing vector files to disk.
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QString & remove(int position, int n)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:656
int month() const
void clear()
QVariant minimumValue(int index)
Returns minimum value for an attribute column or invalid variant in case of error.
QString tr(const char *sourceText, const char *disambiguation, int n)
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=nullptr, SymbologyExport symbologyExport=NoSymbology)
Create a new vector file writer.
QTextCodec * codecForLocale()
int second() const
int size() const
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
QGis::WkbType wkbType() const
Returns the WKBType or WKBUnknown in case of error.
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
void clear()
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
static QgsWKBTypes::Type fromOldWkbType(QGis::WkbType type)
Converts from old (pre 2.10) WKB type (OGR) to new WKB type.
Definition: qgis.cpp:106
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
#define TO8F(x)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
QString number(int n, int base)
int count(const T &value) const
virtual Q_DECL_DEPRECATED QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
To be overridden.
void append(const T &value)
QString fromUtf8(const char *str, int size)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:94
int toInt(bool *ok) const
bool isNull() const
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
#define FID_TO_NUMBER(fid)
Definition: qgsfeature.h:88
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:213
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
int toInt(bool *ok, int base) const
bool isEmpty() const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isEmpty() const
const_iterator constEnd() const
int day() const
const char * constData() const
QgsWKBTypes::Type mWkbType
Geometry type which is being used.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
The output shall be in map unitx.
Definition: qgssymbolv2.h:65
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
This class wraps a request for features to a vector layer (or directly its vector data provider)...
~QgsVectorFileWriter()
Close opened shapefile for writing.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Get the data source specification.
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:131
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfield.cpp:309
int count() const
Return number of items.
Definition: qgsfield.cpp:365
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
int year() const
QDir dir() const
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbols()
For symbol levels.
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:385
QMap< int, int > mAttrIdxToOgrIdx
Map attribute indizes to OGR field indexes.
OGRSpatialReferenceH mOgrRef
int hour() const
iterator end()
QString toLower() const
const T value(const Key &key) const
QByteArray toLocal8Bit() const
iterator find(const Key &key)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
int renderingPass() const
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:76
virtual void close()
static QMap< QString, QString > ogrDriverList()
Returns driver list that can be used for dialogs.
bool contains(const T &value) const
const char * typeToName(Type typ)
QString errorMessage()
Retrieves error message.
const Key key(const T &value) const
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:817
QDate toDate() const
QString providerType() const
Return the provider type for this layer.
QString what() const
Definition: qgsexception.h:36
QVariant value(const QString &key, const QVariant &defaultValue) const
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:271
int wkbSize() const
Returns the size of the WKB in asWkb().
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set feature IDs that should be fetched.
QDate date() const
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
Returns list of symbols used for rendering the feature.
void setSymbologyScaleDenominator(double d)
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
QgsSymbolV2 * symbol()
Definition: qgsrendererv2.h:58
QTextCodec * codecForName(const QByteArray &name)
bool usingSymbolLevels() const
const char * typeName() const
Class for storing a coordinate reference system (CRS)
int length() const
Gets the length of the field.
Definition: qgsfield.cpp:99
int size() const
Return number of items.
Definition: qgsfield.cpp:370
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Class for doing transforms between two map coordinate systems.
bool toBool() const
UnitType
Map units that qgis supports.
Definition: qgis.h:155
char * data()
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
QString left(int n) const
QString completeBaseName() const
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
bool isValid() const
QString canonicalPath() const
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
double toDouble(bool *ok) const
iterator insert(const Key &key, const T &value)
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
Custom exception class for Coordinate Reference System related exceptions.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
QgsSymbolLayerV2 * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
QgsVectorDataProvider * dataProvider()
Returns the data provider.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
iterator end()
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
const_iterator constEnd() const
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
const_iterator constBegin() const
Type type() const
static Type to25D(Type type)
Will convert the 25D version of the flat type if supported or Unknown if not supported.
Definition: qgswkbtypes.h:833
Geometry is not required. It may still be returned if e.g. required for a filter condition.
OGRGeometryH createEmptyGeometry(QgsWKBTypes::Type wkbType)
const QgsCoordinateReferenceSystem & destCRS() const
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
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.
int compare(const QString &other) const
bool exactMatch(const QString &str) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
QString toString() const
QString baseName() const
iterator begin()
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:89
static Type singleType(Type type)
Returns the single type for a WKB type.
Definition: qgswkbtypes.h:114
const T value(const Key &key) const
static bool driverMetadata(const QString &driverName, MetaData &driverMetadata)
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QGis::UnitType mapUnits() const
Returns the units for the projection used by the CRS.