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