QGIS API Documentation  2.14.11-Essen
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
1762  for ( int fldIdx = 0; fldIdx < mFields.count(); ++fldIdx )
1763  {
1764  if ( !mAttrIdxToOgrIdx.contains( fldIdx ) )
1765  {
1766  QgsDebugMsg( QString( "no ogr field for field %1" ).arg( fldIdx ) );
1767  continue;
1768  }
1769 
1770  const QVariant& attrValue = feature.attribute( fldIdx );
1771  int ogrField = mAttrIdxToOgrIdx[ fldIdx ];
1772 
1773  if ( !attrValue.isValid() || attrValue.isNull() )
1774  continue;
1775 
1776  switch ( attrValue.type() )
1777  {
1778 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
1779  case QVariant::Int:
1780  case QVariant::UInt:
1781  OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
1782  break;
1783  case QVariant::LongLong:
1784  case QVariant::ULongLong:
1785  OGR_F_SetFieldInteger64( poFeature, ogrField, attrValue.toLongLong() );
1786  break;
1787  case QVariant::String:
1788  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1789  break;
1790 #else
1791  case QVariant::Int:
1792  OGR_F_SetFieldInteger( poFeature, ogrField, attrValue.toInt() );
1793  break;
1794  case QVariant::String:
1795  case QVariant::LongLong:
1796  case QVariant::UInt:
1797  case QVariant::ULongLong:
1798  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1799  break;
1800 #endif
1801  case QVariant::Double:
1802  OGR_F_SetFieldDouble( poFeature, ogrField, attrValue.toDouble() );
1803  break;
1804  case QVariant::Date:
1805  OGR_F_SetFieldDateTime( poFeature, ogrField,
1806  attrValue.toDate().year(),
1807  attrValue.toDate().month(),
1808  attrValue.toDate().day(),
1809  0, 0, 0, 0 );
1810  break;
1811  case QVariant::DateTime:
1812  if ( mOgrDriverName == "ESRI Shapefile" )
1813  {
1814  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toDateTime().toString( "yyyy/MM/dd hh:mm:ss.zzz" ) ).data() );
1815  }
1816  else
1817  {
1818  OGR_F_SetFieldDateTime( poFeature, ogrField,
1819  attrValue.toDateTime().date().year(),
1820  attrValue.toDateTime().date().month(),
1821  attrValue.toDateTime().date().day(),
1822  attrValue.toDateTime().time().hour(),
1823  attrValue.toDateTime().time().minute(),
1824  attrValue.toDateTime().time().second(),
1825  0 );
1826  }
1827  break;
1828  case QVariant::Time:
1829  if ( mOgrDriverName == "ESRI Shapefile" )
1830  {
1831  OGR_F_SetFieldString( poFeature, ogrField, mCodec->fromUnicode( attrValue.toString() ).data() );
1832  }
1833  else
1834  {
1835  OGR_F_SetFieldDateTime( poFeature, ogrField,
1836  0, 0, 0,
1837  attrValue.toTime().hour(),
1838  attrValue.toTime().minute(),
1839  attrValue.toTime().second(),
1840  0 );
1841  }
1842  break;
1843  case QVariant::Invalid:
1844  break;
1845  default:
1846  mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
1847  .arg( mFields.at( fldIdx ).name() )
1848  .arg( ogrField )
1849  .arg( attrValue.typeName(),
1850  attrValue.toString() );
1853  return nullptr;
1854  }
1855  }
1856 
1858  {
1859  if ( feature.constGeometry() && !feature.constGeometry()->isEmpty() )
1860  {
1861  // build geometry from WKB
1862  QgsGeometry* geom = feature.geometry();
1863 
1864  // turn single geometry to multi geometry if needed
1867  {
1868  geom->convertToMultiType();
1869  }
1870 
1871  if ( geom->geometry()->wkbType() != mWkbType )
1872  {
1873  OGRGeometryH mGeom2 = nullptr;
1874 
1875  // If requested WKB type is 25D and geometry WKB type is 3D,
1876  // we must force the use of 25D.
1878  {
1879  //ND: I suspect there's a bug here, in that this is NOT converting the geometry's WKB type,
1880  //so the exported WKB has a different type to what the OGRGeometry is expecting.
1881  //possibly this is handled already in OGR, but it should be fixed regardless by actually converting
1882  //geom to the correct WKB type
1883  QgsWKBTypes::Type wkbType = geom->geometry()->wkbType();
1884  if ( wkbType >= QgsWKBTypes::PointZ && wkbType <= QgsWKBTypes::MultiPolygonZ )
1885  {
1887  mGeom2 = createEmptyGeometry( wkbType25d );
1888  }
1889  }
1890 
1891  if ( !mGeom2 )
1892  {
1893  // there's a problem when layer type is set as wkbtype Polygon
1894  // although there are also features of type MultiPolygon
1895  // (at least in OGR provider)
1896  // If the feature's wkbtype is different from the layer's wkbtype,
1897  // try to export it too.
1898  //
1899  // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
1900  // i.e. Polygons can't be imported to OGRMultiPolygon
1901  mGeom2 = createEmptyGeometry( geom->geometry()->wkbType() );
1902  }
1903 
1904  if ( !mGeom2 )
1905  {
1906  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1907  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1910  OGR_F_Destroy( poFeature );
1911  return nullptr;
1912  }
1913 
1914  OGRErr err = OGR_G_ImportFromWkb( mGeom2, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
1915  if ( err != OGRERR_NONE )
1916  {
1917  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1918  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1921  OGR_F_Destroy( poFeature );
1922  return nullptr;
1923  }
1924 
1925  // pass ownership to geometry
1926  OGR_F_SetGeometryDirectly( poFeature, mGeom2 );
1927  }
1928  else // wkb type matches
1929  {
1930  OGRErr err = OGR_G_ImportFromWkb( mGeom, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
1931  if ( err != OGRERR_NONE )
1932  {
1933  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
1934  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1937  OGR_F_Destroy( poFeature );
1938  return nullptr;
1939  }
1940 
1941  // set geometry (ownership is not passed to OGR)
1942  OGR_F_SetGeometry( poFeature, mGeom );
1943  }
1944  }
1945  else
1946  {
1947  OGR_F_SetGeometry( poFeature, createEmptyGeometry( mWkbType ) );
1948  }
1949  }
1950  return poFeature;
1951 }
1952 
1953 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
1954 {
1955  if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
1956  {
1957  mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
1960  OGR_F_Destroy( feature );
1961  return false;
1962  }
1963  return true;
1964 }
1965 
1967 {
1968  if ( mGeom )
1969  {
1970  OGR_G_DestroyGeometry( mGeom );
1971  }
1972 
1973  if ( mDS )
1974  {
1975  OGR_DS_Destroy( mDS );
1976  }
1977 
1978  if ( mOgrRef )
1979  {
1980  OSRDestroySpatialReference( mOgrRef );
1981  }
1982 }
1983 
1986  const QString& fileName,
1987  const QString& fileEncoding,
1988  const QgsCoordinateReferenceSystem *destCRS,
1989  const QString& driverName,
1990  bool onlySelected,
1992  const QStringList &datasourceOptions,
1993  const QStringList &layerOptions,
1994  bool skipAttributeCreation,
1995  QString *newFilename,
1997  double symbologyScale,
1998  const QgsRectangle* filterExtent,
1999  QgsWKBTypes::Type overrideGeometryType,
2000  bool forceMulti,
2001  bool includeZ )
2002 {
2003  QgsCoordinateTransform* ct = nullptr;
2004  if ( destCRS && layer )
2005  {
2006  ct = new QgsCoordinateTransform( layer->crs(), *destCRS );
2007  }
2008 
2009  QgsVectorFileWriter::WriterError error = writeAsVectorFormat( layer, fileName, fileEncoding, ct, driverName, onlySelected,
2010  errorMessage, datasourceOptions, layerOptions, skipAttributeCreation, newFilename, symbologyExport, symbologyScale, filterExtent, overrideGeometryType, forceMulti, includeZ );
2011  delete ct;
2012  return error;
2013 }
2014 
2016  const QString& fileName,
2017  const QString& fileEncoding,
2018  const QgsCoordinateTransform* ct,
2019  const QString& driverName,
2020  bool onlySelected,
2022  const QStringList &datasourceOptions,
2023  const QStringList &layerOptions,
2024  bool skipAttributeCreation,
2025  QString *newFilename,
2027  double symbologyScale,
2028  const QgsRectangle* filterExtent,
2029  QgsWKBTypes::Type overrideGeometryType,
2030  bool forceMulti,
2031  bool includeZ )
2032 {
2033  if ( !layer )
2034  {
2035  return ErrInvalidLayer;
2036  }
2037 
2038  bool shallTransform = false;
2039  const QgsCoordinateReferenceSystem* outputCRS = nullptr;
2040  if ( ct )
2041  {
2042  // This means we should transform
2043  outputCRS = &( ct->destCRS() );
2044  shallTransform = true;
2045  }
2046  else
2047  {
2048  // This means we shouldn't transform, use source CRS as output (if defined)
2049  outputCRS = &layer->crs();
2050  }
2051 
2052  QgsWKBTypes::Type destWkbType = QGis::fromOldWkbType( layer->wkbType() );
2053  if ( overrideGeometryType != QgsWKBTypes::Unknown )
2054  {
2055  destWkbType = QgsWKBTypes::flatType( overrideGeometryType );
2056  if ( QgsWKBTypes::hasZ( overrideGeometryType ) || includeZ )
2057  destWkbType = QgsWKBTypes::addZ( destWkbType );
2058  }
2059  if ( forceMulti )
2060  {
2061  destWkbType = QgsWKBTypes::multiType( destWkbType );
2062  }
2063 
2064  QgsFields fields = skipAttributeCreation ? QgsFields() : layer->fields();
2065 
2066  if ( layer->providerType() == "ogr" && layer->dataProvider() )
2067  {
2068  QStringList theURIParts = layer->dataProvider()->dataSourceUri().split( '|' );
2069  QString srcFileName = theURIParts[0];
2070 
2071  if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2072  {
2073  if ( errorMessage )
2074  *errorMessage = QObject::tr( "Cannot overwrite a OGR layer in place" );
2075  return ErrCreateDataSource;
2076  }
2077 
2078  // Shapefiles might contain multi types although wkbType() only reports singles
2079  if ( layer->storageType() == "ESRI Shapefile" && !QgsWKBTypes::isMultiType( destWkbType ) )
2080  {
2081  QgsFeatureRequest req;
2082  if ( onlySelected )
2083  {
2084  req.setFilterFids( layer->selectedFeaturesIds() );
2085  }
2086  QgsFeatureIterator fit = layer->getFeatures( req );
2087  QgsFeature fet;
2088 
2089  while ( fit.nextFeature( fet ) )
2090  {
2091  if ( fet.constGeometry() && !fet.constGeometry()->isEmpty() && QgsWKBTypes::isMultiType( fet.constGeometry()->geometry()->wkbType() ) )
2092  {
2093  destWkbType = QgsWKBTypes::multiType( destWkbType );
2094  break;
2095  }
2096  }
2097  }
2098  }
2099  else if ( layer->providerType() == "spatialite" )
2100  {
2101  for ( int i = 0; i < fields.size(); i++ )
2102  {
2103  if ( fields.at( i ).type() == QVariant::LongLong )
2104  {
2105  QVariant min = layer->minimumValue( i );
2106  QVariant max = layer->maximumValue( i );
2107  if ( qMax( qAbs( min.toLongLong() ), qAbs( max.toLongLong() ) ) < INT_MAX )
2108  {
2109  fields[i].setType( QVariant::Int );
2110  }
2111  }
2112  }
2113  }
2114 
2115  QgsVectorFileWriter* writer =
2116  new QgsVectorFileWriter( fileName, fileEncoding, fields, QGis::fromNewWkbType( destWkbType ), outputCRS, driverName, datasourceOptions, layerOptions, newFilename, symbologyExport );
2117  writer->setSymbologyScaleDenominator( symbologyScale );
2118 
2119  if ( newFilename )
2120  {
2121  QgsDebugMsg( "newFilename = " + *newFilename );
2122  }
2123 
2124  // check whether file creation was successful
2125  WriterError err = writer->hasError();
2126  if ( err != NoError )
2127  {
2128  if ( errorMessage )
2129  *errorMessage = writer->errorMessage();
2130  delete writer;
2131  return err;
2132  }
2133 
2134  if ( errorMessage )
2135  {
2136  errorMessage->clear();
2137  }
2138 
2139  QgsAttributeList allAttr = skipAttributeCreation ? QgsAttributeList() : layer->attributeList();
2140  QgsFeature fet;
2141 
2142  //add possible attributes needed by renderer
2143  writer->addRendererAttributes( layer, allAttr );
2144 
2145  QgsFeatureRequest req;
2146  if ( layer->wkbType() == QGis::WKBNoGeometry )
2147  {
2149  }
2150  req.setSubsetOfAttributes( allAttr );
2151  if ( onlySelected )
2152  req.setFilterFids( layer->selectedFeaturesIds() );
2153  QgsFeatureIterator fit = layer->getFeatures( req );
2154 
2155  //create symbol table if needed
2156  if ( writer->symbologyExport() != NoSymbology )
2157  {
2158  //writer->createSymbolLayerTable( layer, writer->mDS );
2159  }
2160 
2161  if ( writer->symbologyExport() == SymbolLayerSymbology )
2162  {
2163  QgsFeatureRendererV2* r = layer->rendererV2();
2165  && r->usingSymbolLevels() )
2166  {
2167  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( layer, fit, ct, errorMessage );
2168  delete writer;
2169  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
2170  }
2171  }
2172 
2173  int n = 0, errors = 0;
2174 
2175  //unit type
2176  QGis::UnitType mapUnits = layer->crs().mapUnits();
2177  if ( ct )
2178  {
2179  mapUnits = ct->destCRS().mapUnits();
2180  }
2181 
2182  writer->startRender( layer );
2183 
2184  // enabling transaction on databases that support it
2185  bool transactionsEnabled = true;
2186 
2187  if ( OGRERR_NONE != OGR_L_StartTransaction( writer->mLayer ) )
2188  {
2189  QgsDebugMsg( "Error when trying to enable transactions on OGRLayer." );
2190  transactionsEnabled = false;
2191  }
2192 
2193  // write all features
2194  while ( fit.nextFeature( fet ) )
2195  {
2196  if ( shallTransform )
2197  {
2198  try
2199  {
2200  if ( fet.geometry() )
2201  {
2202  fet.geometry()->transform( *ct );
2203  }
2204  }
2205  catch ( QgsCsException &e )
2206  {
2207  delete writer;
2208 
2209  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
2210  .arg( fet.id() ).arg( e.what() );
2211  QgsLogger::warning( msg );
2212  if ( errorMessage )
2213  *errorMessage = msg;
2214 
2215  return ErrProjection;
2216  }
2217  }
2218 
2219  if ( fet.constGeometry() && filterExtent && !fet.constGeometry()->intersects( *filterExtent ) )
2220  continue;
2221 
2222  if ( allAttr.size() < 1 && skipAttributeCreation )
2223  {
2224  fet.initAttributes( 0 );
2225  }
2226 
2227  if ( !writer->addFeature( fet, layer->rendererV2(), mapUnits ) )
2228  {
2229  WriterError err = writer->hasError();
2230  if ( err != NoError && errorMessage )
2231  {
2232  if ( errorMessage->isEmpty() )
2233  {
2234  *errorMessage = QObject::tr( "Feature write errors:" );
2235  }
2236  *errorMessage += '\n' + writer->errorMessage();
2237  }
2238  errors++;
2239 
2240  if ( errors > 1000 )
2241  {
2242  if ( errorMessage )
2243  {
2244  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
2245  }
2246 
2247  n = -1;
2248  break;
2249  }
2250  }
2251  n++;
2252  }
2253 
2254  if ( transactionsEnabled )
2255  {
2256  if ( OGRERR_NONE != OGR_L_CommitTransaction( writer->mLayer ) )
2257  {
2258  QgsDebugMsg( "Error while committing transaction on OGRLayer." );
2259  }
2260  }
2261 
2262  writer->stopRender( layer );
2263  delete writer;
2264 
2265  if ( errors > 0 && errorMessage && n > 0 )
2266  {
2267  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
2268  }
2269 
2270  return errors == 0 ? NoError : ErrFeatureWriteFailed;
2271 }
2272 
2273 
2275 {
2276  QFileInfo fi( theFileName );
2277  QDir dir = fi.dir();
2278 
2279  QStringList filter;
2280  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
2281  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
2282  {
2283  filter << fi.completeBaseName() + suffixes[i];
2284  }
2285 
2286  bool ok = true;
2287  Q_FOREACH ( const QString& file, dir.entryList( filter ) )
2288  {
2289  QFile f( dir.canonicalPath() + '/' + file );
2290  if ( !f.remove() )
2291  {
2292  QgsDebugMsg( QString( "Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
2293  ok = false;
2294  }
2295  }
2296 
2297  return ok;
2298 }
2299 
2301 {
2303  mRenderContext.setRendererScale( mSymbologyScaleDenominator );
2304 }
2305 
2307 {
2308  QMap<QString, QString> resultMap;
2309 
2311  int const drvCount = OGRGetDriverCount();
2312 
2313  for ( int i = 0; i < drvCount; ++i )
2314  {
2315  OGRSFDriverH drv = OGRGetDriver( i );
2316  if ( drv )
2317  {
2318  QString drvName = OGR_Dr_GetName( drv );
2319  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2320  {
2321  QString filterString = filterForDriver( drvName );
2322  if ( filterString.isEmpty() )
2323  continue;
2324 
2325  resultMap.insert( filterString, drvName );
2326  }
2327  }
2328  }
2329 
2330  return resultMap;
2331 }
2332 
2334 {
2335  QMap<QString, QString> resultMap;
2336 
2338  int const drvCount = OGRGetDriverCount();
2339 
2340  QStringList writableDrivers;
2341  for ( int i = 0; i < drvCount; ++i )
2342  {
2343  OGRSFDriverH drv = OGRGetDriver( i );
2344  if ( drv )
2345  {
2346  QString drvName = OGR_Dr_GetName( drv );
2347  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2348  {
2349  // Add separate format for Mapinfo MIF (MITAB is OGR default)
2350  if ( drvName == "MapInfo File" )
2351  {
2352  writableDrivers << "MapInfo MIF";
2353  }
2354  else if ( drvName == "SQLite" )
2355  {
2356  // Unfortunately it seems that there is no simple way to detect if
2357  // OGR SQLite driver is compiled with SpatiaLite support.
2358  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
2359  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
2360  // -> test if creation failes
2361  QString option = "SPATIALITE=YES";
2362  char **options = new char *[2];
2363  options[0] = CPLStrdup( option.toLocal8Bit().data() );
2364  options[1] = nullptr;
2365  OGRSFDriverH poDriver;
2367  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().data() );
2368  if ( poDriver )
2369  {
2370  OGRDataSourceH ds = OGR_Dr_CreateDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ), options );
2371  if ( ds )
2372  {
2373  writableDrivers << "SpatiaLite";
2374  OGR_Dr_DeleteDataSource( poDriver, TO8F( QString( "/vsimem/spatialitetest.sqlite" ) ) );
2375  OGR_DS_Destroy( ds );
2376  }
2377  }
2378  CPLFree( options[0] );
2379  delete [] options;
2380  }
2381  else if ( drvName == "ESRI Shapefile" )
2382  {
2383  writableDrivers << "DBF file";
2384  }
2385  writableDrivers << drvName;
2386  }
2387  }
2388  }
2389 
2390  Q_FOREACH ( const QString& drvName, writableDrivers )
2391  {
2392  QString longName;
2393  QString trLongName;
2394  QString glob;
2395  QString exts;
2396  if ( QgsVectorFileWriter::driverMetadata( drvName, longName, trLongName, glob, exts ) && !trLongName.isEmpty() )
2397  {
2398  resultMap.insert( trLongName, drvName );
2399  }
2400  }
2401 
2402  return resultMap;
2403 }
2404 
2406 {
2407  QString filterString;
2409  QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
2410  for ( ; it != driverFormatMap.constEnd(); ++it )
2411  {
2412  if ( !filterString.isEmpty() )
2413  filterString += ";;";
2414 
2415  filterString += it.key();
2416  }
2417  return filterString;
2418 }
2419 
2421 {
2422  QString longName;
2423  QString trLongName;
2424  QString glob;
2425  QString exts;
2426  if ( !driverMetadata( driverName, longName, trLongName, glob, exts ) || trLongName.isEmpty() || glob.isEmpty() )
2427  return "";
2428 
2429  return trLongName + " [OGR] (" + glob.toLower() + ' ' + glob.toUpper() + ')';
2430 }
2431 
2433 {
2434  if ( codecName == "System" )
2435  return QString( "LDID/0" );
2436 
2437  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
2438  if ( re.exactMatch( codecName ) )
2439  {
2440  QString c = re.cap( 2 ).remove( '-' );
2441  bool isNumber;
2442  c.toInt( &isNumber );
2443  if ( isNumber )
2444  return c;
2445  }
2446  return codecName;
2447 }
2448 
2449 bool QgsVectorFileWriter::driverMetadata( const QString& driverName, QString &longName, QString &trLongName, QString &glob, QString &ext )
2450 {
2451  if ( driverName.startsWith( "AVCE00" ) )
2452  {
2453  longName = "Arc/Info ASCII Coverage";
2454  trLongName = QObject::tr( "Arc/Info ASCII Coverage" );
2455  glob = "*.e00";
2456  ext = "e00";
2457  }
2458  else if ( driverName.startsWith( "BNA" ) )
2459  {
2460  longName = "Atlas BNA";
2461  trLongName = QObject::tr( "Atlas BNA" );
2462  glob = "*.bna";
2463  ext = "bna";
2464  }
2465  else if ( driverName.startsWith( "CSV" ) )
2466  {
2467  longName = "Comma Separated Value [CSV]";
2468  trLongName = QObject::tr( "Comma Separated Value [CSV]" );
2469  glob = "*.csv";
2470  ext = "csv";
2471  }
2472  else if ( driverName.startsWith( "ESRI" ) )
2473  {
2474  longName = "ESRI Shapefile";
2475  trLongName = QObject::tr( "ESRI Shapefile" );
2476  glob = "*.shp";
2477  ext = "shp";
2478  }
2479  else if ( driverName.startsWith( "DBF file" ) )
2480  {
2481  longName = "DBF File";
2482  trLongName = QObject::tr( "DBF file" );
2483  glob = "*.dbf";
2484  ext = "dbf";
2485  }
2486  else if ( driverName.startsWith( "FMEObjects Gateway" ) )
2487  {
2488  longName = "FMEObjects Gateway";
2489  trLongName = QObject::tr( "FMEObjects Gateway" );
2490  glob = "*.fdd";
2491  ext = "fdd";
2492  }
2493  else if ( driverName.startsWith( "GeoJSON" ) )
2494  {
2495  longName = "GeoJSON";
2496  trLongName = QObject::tr( "GeoJSON" );
2497  glob = "*.geojson";
2498  ext = "geojson";
2499  }
2500  else if ( driverName.startsWith( "GPKG" ) )
2501  {
2502  longName = "GeoPackage";
2503  trLongName = QObject::tr( "GeoPackage" );
2504  glob = "*.gpkg";
2505  ext = "gpkg";
2506  }
2507  else if ( driverName.startsWith( "GeoRSS" ) )
2508  {
2509  longName = "GeoRSS";
2510  trLongName = QObject::tr( "GeoRSS" );
2511  glob = "*.xml";
2512  ext = "xml";
2513  }
2514  else if ( driverName.startsWith( "GML" ) )
2515  {
2516  longName = "Geography Markup Language [GML]";
2517  trLongName = QObject::tr( "Geography Markup Language [GML]" );
2518  glob = "*.gml";
2519  ext = "gml";
2520  }
2521  else if ( driverName.startsWith( "GMT" ) )
2522  {
2523  longName = "Generic Mapping Tools [GMT]";
2524  trLongName = QObject::tr( "Generic Mapping Tools [GMT]" );
2525  glob = "*.gmt";
2526  ext = "gmt";
2527  }
2528  else if ( driverName.startsWith( "GPX" ) )
2529  {
2530  longName = "GPS eXchange Format [GPX]";
2531  trLongName = QObject::tr( "GPS eXchange Format [GPX]" );
2532  glob = "*.gpx";
2533  ext = "gpx";
2534  }
2535  else if ( driverName.startsWith( "Interlis 1" ) )
2536  {
2537  longName = "INTERLIS 1";
2538  trLongName = QObject::tr( "INTERLIS 1" );
2539  glob = "*.itf *.xml *.ili";
2540  ext = "ili";
2541  }
2542  else if ( driverName.startsWith( "Interlis 2" ) )
2543  {
2544  longName = "INTERLIS 2";
2545  trLongName = QObject::tr( "INTERLIS 2" );
2546  glob = "*.itf *.xml *.ili";
2547  ext = "ili";
2548  }
2549  else if ( driverName.startsWith( "KML" ) )
2550  {
2551  longName = "Keyhole Markup Language [KML]";
2552  trLongName = QObject::tr( "Keyhole Markup Language [KML]" );
2553  glob = "*.kml";
2554  ext = "kml";
2555  }
2556  else if ( driverName.startsWith( "MapInfo File" ) )
2557  {
2558  longName = "Mapinfo TAB";
2559  trLongName = QObject::tr( "Mapinfo TAB" );
2560  glob = "*.tab";
2561  ext = "tab";
2562  }
2563  // 'MapInfo MIF' is internal QGIS addition to distinguish between MITAB and MIF
2564  else if ( driverName.startsWith( "MapInfo MIF" ) )
2565  {
2566  longName = "Mapinfo MIF";
2567  trLongName = QObject::tr( "Mapinfo MIF" );
2568  glob = "*.mif";
2569  ext = "mif";
2570  }
2571  else if ( driverName.startsWith( "DGN" ) )
2572  {
2573  longName = "Microstation DGN";
2574  trLongName = QObject::tr( "Microstation DGN" );
2575  glob = "*.dgn";
2576  ext = "dgn";
2577  }
2578  else if ( driverName.startsWith( "S57" ) )
2579  {
2580  longName = "S-57 Base file";
2581  trLongName = QObject::tr( "S-57 Base file" );
2582  glob = "*.000";
2583  ext = "000";
2584  }
2585  else if ( driverName.startsWith( "SDTS" ) )
2586  {
2587  longName = "Spatial Data Transfer Standard [SDTS]";
2588  trLongName = QObject::tr( "Spatial Data Transfer Standard [SDTS]" );
2589  glob = "*catd.ddf";
2590  ext = "ddf";
2591  }
2592  else if ( driverName.startsWith( "SQLite" ) )
2593  {
2594  longName = "SQLite";
2595  trLongName = QObject::tr( "SQLite" );
2596  glob = "*.sqlite";
2597  ext = "sqlite";
2598  }
2599  // QGIS internal addition for SpatialLite
2600  else if ( driverName.startsWith( "SpatiaLite" ) )
2601  {
2602  longName = "SpatiaLite";
2603  trLongName = QObject::tr( "SpatiaLite" );
2604  glob = "*.sqlite";
2605  ext = "sqlite";
2606  }
2607  else if ( driverName.startsWith( "DXF" ) )
2608  {
2609  longName = "AutoCAD DXF";
2610  trLongName = QObject::tr( "AutoCAD DXF" );
2611  glob = "*.dxf";
2612  ext = "dxf";
2613  }
2614  else if ( driverName.startsWith( "Geoconcept" ) )
2615  {
2616  longName = "Geoconcept";
2617  trLongName = QObject::tr( "Geoconcept" );
2618  glob = "*.gxt *.txt";
2619  ext = "gxt";
2620  }
2621  else if ( driverName.startsWith( "FileGDB" ) )
2622  {
2623  longName = "ESRI FileGDB";
2624  trLongName = QObject::tr( "ESRI FileGDB" );
2625  glob = "*.gdb";
2626  ext = "gdb";
2627  }
2628  else if ( driverName.startsWith( "XLSX" ) )
2629  {
2630  longName = "MS Office Open XML spreadsheet [XLSX]";
2631  trLongName = QObject::tr( "MS Office Open XML spreadsheet [XLSX]" );
2632  glob = "*.xlsx";
2633  ext = "xlsx";
2634  }
2635  else if ( driverName.startsWith( "ODS" ) )
2636  {
2637  longName = "Open Document Spreadsheet";
2638  trLongName = QObject::tr( "Open Document Spreadsheet [ODS]" );
2639  glob = "*.ods";
2640  ext = "ods";
2641  }
2642  else
2643  {
2644  return false;
2645  }
2646 
2647  return true;
2648 }
2649 
2650 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer* vl, const QgsCoordinateTransform* ct, OGRDataSourceH ds )
2651 {
2652  if ( !vl || !ds )
2653  {
2654  return;
2655  }
2656 
2657  QgsFeatureRendererV2* renderer = vl->rendererV2();
2658  if ( !renderer )
2659  {
2660  return;
2661  }
2662 
2663  //unit type
2664  QGis::UnitType mapUnits = vl->crs().mapUnits();
2665  if ( ct )
2666  {
2667  mapUnits = ct->destCRS().mapUnits();
2668  }
2669 
2670 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1700
2671  mSymbolLayerTable.clear();
2672  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
2673  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
2674 
2675  //get symbols
2676  int nTotalLevels = 0;
2677  QgsSymbolV2List symbolList = renderer->symbols( mRenderContext );
2678  QgsSymbolV2List::iterator symbolIt = symbolList.begin();
2679  for ( ; symbolIt != symbolList.end(); ++symbolIt )
2680  {
2681  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
2682  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, ( *symbolIt )->outputUnit(), mapUnits );
2683 
2684  int nLevels = ( *symbolIt )->symbolLayerCount();
2685  for ( int i = 0; i < nLevels; ++i )
2686  {
2687  mSymbolLayerTable.insert(( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
2688  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
2689  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
2690  ++nTotalLevels;
2691  }
2692  }
2693  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
2694 #endif
2695 }
2696 
2697 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( QgsVectorLayer* layer, QgsFeatureIterator& fit,
2699 {
2700  if ( !layer )
2701  return ErrInvalidLayer;
2702 
2703  mRenderContext.expressionContext() = QgsExpressionContext();
2707 
2708  QgsFeatureRendererV2 *renderer = layer->rendererV2();
2709  if ( !renderer )
2710  return ErrInvalidLayer;
2711 
2713 
2714  //unit type
2715  QGis::UnitType mapUnits = layer->crs().mapUnits();
2716  if ( ct )
2717  {
2718  mapUnits = ct->destCRS().mapUnits();
2719  }
2720 
2721  startRender( layer );
2722 
2723  //fetch features
2724  QgsFeature fet;
2725  QgsSymbolV2* featureSymbol = nullptr;
2726  while ( fit.nextFeature( fet ) )
2727  {
2728  if ( ct )
2729  {
2730  try
2731  {
2732  if ( fet.geometry() )
2733  {
2734  fet.geometry()->transform( *ct );
2735  }
2736  }
2737  catch ( QgsCsException &e )
2738  {
2739  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
2740  .arg( e.what() );
2741  QgsLogger::warning( msg );
2742  if ( errorMessage )
2743  *errorMessage = msg;
2744 
2745  return ErrProjection;
2746  }
2747  }
2748  mRenderContext.expressionContext().setFeature( fet );
2749 
2750  featureSymbol = renderer->symbolForFeature( fet, mRenderContext );
2751  if ( !featureSymbol )
2752  {
2753  continue;
2754  }
2755 
2756  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
2757  if ( it == features.end() )
2758  {
2759  it = features.insert( featureSymbol, QList<QgsFeature>() );
2760  }
2761  it.value().append( fet );
2762  }
2763 
2764  //find out order
2765  QgsSymbolV2LevelOrder levels;
2766  QgsSymbolV2List symbols = renderer->symbols( mRenderContext );
2767  for ( int i = 0; i < symbols.count(); i++ )
2768  {
2769  QgsSymbolV2* sym = symbols[i];
2770  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
2771  {
2772  int level = sym->symbolLayer( j )->renderingPass();
2773  if ( level < 0 || level >= 1000 ) // ignore invalid levels
2774  continue;
2775  QgsSymbolV2LevelItem item( sym, j );
2776  while ( level >= levels.count() ) // append new empty levels
2777  levels.append( QgsSymbolV2Level() );
2778  levels[level].append( item );
2779  }
2780  }
2781 
2782  int nErrors = 0;
2783  int nTotalFeatures = 0;
2784 
2785  //export symbol layers and symbology
2786  for ( int l = 0; l < levels.count(); l++ )
2787  {
2788  QgsSymbolV2Level& level = levels[l];
2789  for ( int i = 0; i < level.count(); i++ )
2790  {
2791  QgsSymbolV2LevelItem& item = level[i];
2792  QHash< QgsSymbolV2*, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
2793  if ( levelIt == features.end() )
2794  {
2795  ++nErrors;
2796  continue;
2797  }
2798 
2799  double mmsf = mmScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
2800  double musf = mapUnitScaleFactor( mSymbologyScaleDenominator, levelIt.key()->outputUnit(), mapUnits );
2801 
2802  int llayer = item.layer();
2803  QList<QgsFeature>& featureList = levelIt.value();
2804  QList<QgsFeature>::iterator featureIt = featureList.begin();
2805  for ( ; featureIt != featureList.end(); ++featureIt )
2806  {
2807  ++nTotalFeatures;
2808  OGRFeatureH ogrFeature = createFeature( *featureIt );
2809  if ( !ogrFeature )
2810  {
2811  ++nErrors;
2812  continue;
2813  }
2814 
2815  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
2816  if ( !styleString.isEmpty() )
2817  {
2818  OGR_F_SetStyleString( ogrFeature, styleString.toLocal8Bit().data() );
2819  if ( !writeFeature( mLayer, ogrFeature ) )
2820  {
2821  ++nErrors;
2822  }
2823  }
2824  OGR_F_Destroy( ogrFeature );
2825  }
2826  }
2827  }
2828 
2829  stopRender( layer );
2830 
2831  if ( nErrors > 0 && errorMessage )
2832  {
2833  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
2834  }
2835 
2837 }
2838 
2839 double QgsVectorFileWriter::mmScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
2840 {
2841  if ( symbolUnits == QgsSymbolV2::MM )
2842  {
2843  return 1.0;
2844  }
2845  else
2846  {
2847  //conversion factor map units -> mm
2848  if ( mapUnits == QGis::Meters )
2849  {
2850  return 1000 / scaleDenominator;
2851  }
2852 
2853  }
2854  return 1.0; //todo: map units
2855 }
2856 
2857 double QgsVectorFileWriter::mapUnitScaleFactor( double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits )
2858 {
2859  if ( symbolUnits == QgsSymbolV2::MapUnit )
2860  {
2861  return 1.0;
2862  }
2863  else
2864  {
2865  if ( symbolUnits == QgsSymbolV2::MM && mapUnits == QGis::Meters )
2866  {
2867  return scaleDenominator / 1000;
2868  }
2869  }
2870  return 1.0;
2871 }
2872 
2873 void QgsVectorFileWriter::startRender( QgsVectorLayer* vl )
2874 {
2875  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2876  if ( !renderer )
2877  {
2878  return;
2879  }
2880 
2881  renderer->startRender( mRenderContext, vl->fields() );
2882 }
2883 
2884 void QgsVectorFileWriter::stopRender( QgsVectorLayer* vl )
2885 {
2886  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2887  if ( !renderer )
2888  {
2889  return;
2890  }
2891 
2892  renderer->stopRender( mRenderContext );
2893 }
2894 
2895 QgsFeatureRendererV2* QgsVectorFileWriter::symbologyRenderer( QgsVectorLayer* vl ) const
2896 {
2897  if ( mSymbologyExport == NoSymbology )
2898  {
2899  return nullptr;
2900  }
2901  if ( !vl )
2902  {
2903  return nullptr;
2904  }
2905 
2906  return vl->rendererV2();
2907 }
2908 
2909 void QgsVectorFileWriter::addRendererAttributes( QgsVectorLayer* vl, QgsAttributeList& attList )
2910 {
2911  QgsFeatureRendererV2* renderer = symbologyRenderer( vl );
2912  if ( renderer )
2913  {
2914  QList<QString> rendererAttributes = renderer->usedAttributes();
2915  for ( int i = 0; i < rendererAttributes.size(); ++i )
2916  {
2917  int index = vl->fieldNameIndex( rendererAttributes.at( i ) );
2918  if ( index != -1 )
2919  {
2920  attList.push_back( vl->fieldNameIndex( rendererAttributes.at( i ) ) );
2921  }
2922  }
2923  }
2924 }
qlonglong toLongLong(bool *ok) const
Wrapper for iterator of features from vector data provider or vector layer.
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)
Write contents of vector layer to an (OGR supported) vector formt.
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
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.
QString cap(int nth) const
QGis::WkbType wkbType() const
Returns the WKBType or WKBUnknown in case of error.
QString & append(QChar ch)
iterator insert(const Key &key, const T &value)
QString toUpper() const
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
int size() const
Return number of items.
Definition: qgsfield.cpp:370
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
static OGRwkbGeometryType ogrTypeFromWkbType(QgsWKBTypes::Type type)
Get the ogr geometry type from an internal QGIS wkb type enum.
bool contains(const Key &key) const
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 the maximum value for an attribute column or an invalid variant in case of error...
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
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
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
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
QTime toTime() const
static QGis::WkbType fromNewWkbType(QgsWKBTypes::Type type)
Converts from new (post 2.10) WKB type (OGC) to old WKB type.
Definition: qgis.cpp:144
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:476
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
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
int precision() const
Gets the precision of the field.
Definition: qgsfield.cpp:104
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 the minimum value for an attribute column or an invalid variant in case of error...
int wkbSize() const
Returns the size of the WKB in asWkb().
int count() const
Return number of items.
Definition: qgsfield.cpp:365
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()
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
int second() const
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:385
int size() const
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
QString what() const
Definition: qgsexception.h:36
QgsFields fields() const
Returns the list of fields of this layer.
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.
int renderingPass() const
static QgsWKBTypes::Type fromOldWkbType(QGis::WkbType type)
Converts from old (pre 2.10) WKB type (OGR) to new WKB type.
Definition: qgis.cpp:104
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...
int toInt(bool *ok) const
bool isNull() const
#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
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
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Get the data source specification.
const_iterator constEnd() const
QGis::UnitType mapUnits() const
Returns the units for the projection used by the CRS.
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.
QList< int > QgsAttributeList
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:131
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
int year() const
QDir dir() const
bool usingSymbolLevels() 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)
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
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
QByteArray toLocal8Bit() const
iterator find(const Key &key)
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 QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
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
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.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
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.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
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)
const char * typeName() const
Class for storing a coordinate reference system (CRS)
QString toWkt() const
Returns a WKT representation of this CRS.
int length() const
Gets the length of the field.
Definition: qgsfield.cpp:99
const QgsCoordinateReferenceSystem & destCRS() const
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
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)
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.
QString providerType() const
Return the provider type for this layer.
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.
SymbologyExport symbologyExport() const
OGRGeometryH createEmptyGeometry(QgsWKBTypes::Type wkbType)
Represents a vector layer which manages a vector based data sets.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:89
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
int compare(const QString &other) const
bool exactMatch(const QString &str) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QString baseName() const
iterator begin()
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
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)