QGIS API Documentation  3.2.0-Bonn (bc43194)
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 "qgsfields.h"
21 #include "qgsfeature.h"
22 #include "qgsfeatureiterator.h"
23 #include "qgsgeometry.h"
24 #include "qgslogger.h"
25 #include "qgsmessagelog.h"
27 #include "qgsvectorfilewriter.h"
28 #include "qgsrenderer.h"
29 #include "qgssymbollayer.h"
30 #include "qgsvectordataprovider.h"
31 #include "qgsvectorlayer.h"
32 #include "qgslocalec.h"
33 #include "qgsexception.h"
34 #include "qgssettings.h"
35 #include "qgsgeometryengine.h"
36 
37 #include <QFile>
38 #include <QFileInfo>
39 #include <QDir>
40 #include <QTextCodec>
41 #include <QTextStream>
42 #include <QSet>
43 #include <QMetaType>
44 
45 #include <cassert>
46 #include <cstdlib> // size_t
47 #include <limits> // std::numeric_limits
48 
49 #include <ogr_srs_api.h>
50 #include <cpl_error.h>
51 #include <cpl_conv.h>
52 #include <cpl_string.h>
53 #include <gdal.h>
54 
55 // Thin wrapper around OGROpen() to workaround a bug in GDAL < 2.3.1
56 // where a existing BNA file is wrongly reported to be openable in update mode
57 // but attempting to add features in it crashes the BNA driver.
58 static OGRDataSourceH myOGROpen( const char *pszName, int bUpdate, OGRSFDriverH *phDriver )
59 {
60  OGRSFDriverH hDriver = nullptr;
61  OGRDataSourceH hDS = OGROpen( pszName, bUpdate, &hDriver );
62  if ( hDS && bUpdate )
63  {
64  QString drvName = OGR_Dr_GetName( hDriver );
65  if ( drvName == "BNA" )
66  {
67  OGR_DS_Destroy( hDS );
68  if ( phDriver )
69  *phDriver = nullptr;
70  return nullptr;
71  }
72  }
73  if ( phDriver )
74  *phDriver = hDriver;
75  return hDS;
76 }
77 
79 {
80  return field;
81 }
82 
83 QVariant QgsVectorFileWriter::FieldValueConverter::convert( int /*fieldIdxInLayer*/, const QVariant &value )
84 {
85  return value;
86 }
87 
89 {
90  return new FieldValueConverter( *this );
91 }
92 
94  const QString &vectorFileName,
95  const QString &fileEncoding,
96  const QgsFields &fields,
97  QgsWkbTypes::Type geometryType,
99  const QString &driverName,
100  const QStringList &datasourceOptions,
101  const QStringList &layerOptions,
102  QString *newFilename,
104 )
105  : mError( NoError )
106  , mWkbType( geometryType )
107  , mSymbologyExport( symbologyExport )
108  , mSymbologyScale( 1.0 )
109 {
110  init( vectorFileName, fileEncoding, fields, geometryType,
111  srs, driverName, datasourceOptions, layerOptions, newFilename, nullptr,
112  QString(), CreateOrOverwriteFile );
113 }
114 
115 QgsVectorFileWriter::QgsVectorFileWriter( const QString &vectorFileName,
116  const QString &fileEncoding,
117  const QgsFields &fields,
118  QgsWkbTypes::Type geometryType,
119  const QgsCoordinateReferenceSystem &srs,
120  const QString &driverName,
121  const QStringList &datasourceOptions,
122  const QStringList &layerOptions,
123  QString *newFilename,
125  FieldValueConverter *fieldValueConverter,
126  const QString &layerName,
127  ActionOnExistingFile action )
128  : mError( NoError )
129  , mWkbType( geometryType )
130  , mSymbologyExport( symbologyExport )
131  , mSymbologyScale( 1.0 )
132 {
133  init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName,
134  datasourceOptions, layerOptions, newFilename, fieldValueConverter,
135  layerName, action );
136 }
137 
138 bool QgsVectorFileWriter::supportsFeatureStyles( const QString &driverName )
139 {
140 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
141  GDALDriverH gdalDriver = GDALGetDriverByName( driverName.toLocal8Bit().constData() );
142  if ( !gdalDriver )
143  return false;
144 
145  char **driverMetadata = GDALGetMetadata( gdalDriver, nullptr );
146  if ( !driverMetadata )
147  return false;
148 
149  return CSLFetchBoolean( driverMetadata, GDAL_DCAP_FEATURE_STYLES, false );
150 #else
151  return driverName == QLatin1String( "DXF" ) || driverName == QLatin1String( "KML" ) || driverName == QLatin1String( "MapInfo File" ) || driverName == QLatin1String( "MapInfo MIF" );
152 #endif
153 }
154 
155 void QgsVectorFileWriter::init( QString vectorFileName,
156  QString fileEncoding,
157  const QgsFields &fields,
158  QgsWkbTypes::Type geometryType,
160  const QString &driverName,
161  QStringList datasourceOptions,
162  QStringList layerOptions,
163  QString *newFilename,
164  FieldValueConverter *fieldValueConverter,
165  const QString &layerNameIn,
166  ActionOnExistingFile action )
167 {
168  mRenderContext.setRendererScale( mSymbologyScale );
169 
170  if ( vectorFileName.isEmpty() )
171  {
172  mErrorMessage = QObject::tr( "Empty filename given" );
174  return;
175  }
176 
177  if ( driverName == QLatin1String( "MapInfo MIF" ) )
178  {
179  mOgrDriverName = QStringLiteral( "MapInfo File" );
180  }
181  else if ( driverName == QLatin1String( "SpatiaLite" ) )
182  {
183  mOgrDriverName = QStringLiteral( "SQLite" );
184  if ( !datasourceOptions.contains( QStringLiteral( "SPATIALITE=YES" ) ) )
185  {
186  datasourceOptions.append( QStringLiteral( "SPATIALITE=YES" ) );
187  }
188  }
189  else if ( driverName == QLatin1String( "DBF file" ) )
190  {
191  mOgrDriverName = QStringLiteral( "ESRI Shapefile" );
192  if ( !layerOptions.contains( QStringLiteral( "SHPT=NULL" ) ) )
193  {
194  layerOptions.append( QStringLiteral( "SHPT=NULL" ) );
195  }
197  }
198  else
199  {
200  mOgrDriverName = driverName;
201  }
202 
203  // find driver in OGR
204  OGRSFDriverH poDriver;
206 
207  poDriver = OGRGetDriverByName( mOgrDriverName.toLocal8Bit().constData() );
208 
209  if ( !poDriver )
210  {
211  mErrorMessage = QObject::tr( "OGR driver for '%1' not found (OGR error: %2)" )
212  .arg( driverName,
213  QString::fromUtf8( CPLGetLastErrorMsg() ) );
215  return;
216  }
217 
218  MetaData metadata;
219  bool metadataFound = driverMetadata( driverName, metadata );
220 
221  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
222  {
223  if ( layerOptions.join( QLatin1String( "" ) ).toUpper().indexOf( QLatin1String( "ENCODING=" ) ) == -1 )
224  {
225  layerOptions.append( "ENCODING=" + convertCodecNameForEncodingOption( fileEncoding ) );
226  }
227 
228  if ( driverName == QLatin1String( "ESRI Shapefile" ) && !vectorFileName.endsWith( QLatin1String( ".shp" ), Qt::CaseInsensitive ) )
229  {
230  vectorFileName += QLatin1String( ".shp" );
231  }
232  else if ( driverName == QLatin1String( "DBF file" ) && !vectorFileName.endsWith( QLatin1String( ".dbf" ), Qt::CaseInsensitive ) )
233  {
234  vectorFileName += QLatin1String( ".dbf" );
235  }
236 
237  if ( action == CreateOrOverwriteFile || action == CreateOrOverwriteLayer )
238  deleteShapeFile( vectorFileName );
239  }
240  else
241  {
242  if ( metadataFound )
243  {
244  QStringList allExts = metadata.ext.split( ' ', QString::SkipEmptyParts );
245  bool found = false;
246  Q_FOREACH ( const QString &ext, allExts )
247  {
248  if ( vectorFileName.endsWith( '.' + ext, Qt::CaseInsensitive ) )
249  {
250  found = true;
251  break;
252  }
253  }
254 
255  if ( !found )
256  {
257  vectorFileName += '.' + allExts[0];
258  }
259  }
260 
261  if ( action == CreateOrOverwriteFile )
262  {
263  if ( vectorFileName.endsWith( QLatin1String( ".gdb" ), Qt::CaseInsensitive ) )
264  {
265  QDir dir( vectorFileName );
266  if ( dir.exists() )
267  {
268  QFileInfoList fileList = dir.entryInfoList(
269  QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst );
270  Q_FOREACH ( const QFileInfo &info, fileList )
271  {
272  QFile::remove( info.absoluteFilePath() );
273  }
274  }
275  QDir().rmdir( vectorFileName );
276  }
277  else
278  {
279  QFile::remove( vectorFileName );
280  }
281  }
282  }
283 
284  if ( metadataFound && !metadata.compulsoryEncoding.isEmpty() )
285  {
286  if ( fileEncoding.compare( metadata.compulsoryEncoding, Qt::CaseInsensitive ) != 0 )
287  {
288  QgsDebugMsg( QString( "forced %1 encoding for %2" ).arg( metadata.compulsoryEncoding, driverName ) );
289  fileEncoding = metadata.compulsoryEncoding;
290  }
291 
292  }
293 
294  char **options = nullptr;
295  if ( !datasourceOptions.isEmpty() )
296  {
297  options = new char *[ datasourceOptions.size() + 1 ];
298  for ( int i = 0; i < datasourceOptions.size(); i++ )
299  {
300  QgsDebugMsg( QString( "-dsco=%1" ).arg( datasourceOptions[i] ) );
301  options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().constData() );
302  }
303  options[ datasourceOptions.size()] = nullptr;
304  }
305 
306  // create the data source
307  if ( action == CreateOrOverwriteFile )
308  mDS.reset( OGR_Dr_CreateDataSource( poDriver, vectorFileName.toUtf8().constData(), options ) );
309  else
310  mDS.reset( myOGROpen( vectorFileName.toUtf8().constData(), TRUE, nullptr ) );
311 
312  if ( options )
313  {
314  for ( int i = 0; i < datasourceOptions.size(); i++ )
315  CPLFree( options[i] );
316  delete [] options;
317  options = nullptr;
318  }
319 
320  if ( !mDS )
321  {
323  if ( action == CreateOrOverwriteFile )
324  mErrorMessage = QObject::tr( "Creation of data source failed (OGR error: %1)" )
325  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
326  else
327  mErrorMessage = QObject::tr( "Opening of data source in update mode failed (OGR error: %1)" )
328  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
329  return;
330  }
331 
332  QString layerName( layerNameIn );
333  if ( layerName.isEmpty() )
334  layerName = QFileInfo( vectorFileName ).baseName();
335 
336  if ( action == CreateOrOverwriteLayer )
337  {
338  const int layer_count = OGR_DS_GetLayerCount( mDS.get() );
339  for ( int i = 0; i < layer_count; i++ )
340  {
341  OGRLayerH hLayer = OGR_DS_GetLayer( mDS.get(), i );
342  if ( EQUAL( OGR_L_GetName( hLayer ), layerName.toUtf8().constData() ) )
343  {
344  if ( OGR_DS_DeleteLayer( mDS.get(), i ) != OGRERR_NONE )
345  {
347  mErrorMessage = QObject::tr( "Overwriting of existing layer failed (OGR error: %1)" )
348  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
349  return;
350  }
351  break;
352  }
353  }
354  }
355 
356  if ( action == CreateOrOverwriteFile )
357  {
358  QgsDebugMsg( "Created data source" );
359  }
360  else
361  {
362  QgsDebugMsg( "Opened data source in update mode" );
363  }
364 
365  // use appropriate codec
366  mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
367  if ( !mCodec )
368  {
369  QgsDebugMsg( "error finding QTextCodec for " + fileEncoding );
370 
371  QgsSettings settings;
372  QString enc = settings.value( QStringLiteral( "UI/encoding" ), "System" ).toString();
373  mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
374  if ( !mCodec )
375  {
376  QgsDebugMsg( "error finding QTextCodec for " + enc );
377  mCodec = QTextCodec::codecForLocale();
378  Q_ASSERT( mCodec );
379  }
380  }
381 
382  // consider spatial reference system of the layer
383  if ( srs.isValid() )
384  {
385  QString srsWkt = srs.toWkt();
386  QgsDebugMsg( "WKT to save as is " + srsWkt );
387  mOgrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().constData() );
388  }
389 
390  // datasource created, now create the output layer
391  OGRwkbGeometryType wkbType = ogrTypeFromWkbType( geometryType );
392 
393  // Remove FEATURE_DATASET layer option (used for ESRI File GDB driver) if its value is not set
394  int optIndex = layerOptions.indexOf( QStringLiteral( "FEATURE_DATASET=" ) );
395  if ( optIndex != -1 )
396  {
397  layerOptions.removeAt( optIndex );
398  }
399 
400  if ( !layerOptions.isEmpty() )
401  {
402  options = new char *[ layerOptions.size() + 1 ];
403  for ( int i = 0; i < layerOptions.size(); i++ )
404  {
405  QgsDebugMsg( QString( "-lco=%1" ).arg( layerOptions[i] ) );
406  options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().constData() );
407  }
408  options[ layerOptions.size()] = nullptr;
409  }
410 
411  // disable encoding conversion of OGR Shapefile layer
412  CPLSetConfigOption( "SHAPE_ENCODING", "" );
413 
414  if ( driverName == QLatin1String( "DGN" ) )
415  {
416  mLayer = OGR_DS_GetLayerByName( mDS.get(), "elements" );
417  }
418  else if ( action == CreateOrOverwriteFile || action == CreateOrOverwriteLayer )
419  {
420  mLayer = OGR_DS_CreateLayer( mDS.get(), layerName.toUtf8().constData(), mOgrRef, wkbType, options );
421  }
422  else
423  {
424  mLayer = OGR_DS_GetLayerByName( mDS.get(), layerName.toUtf8().constData() );
425  }
426 
427  if ( options )
428  {
429  for ( int i = 0; i < layerOptions.size(); i++ )
430  CPLFree( options[i] );
431  delete [] options;
432  options = nullptr;
433  }
434 
435  QgsSettings settings;
436  if ( !settings.value( QStringLiteral( "qgis/ignoreShapeEncoding" ), true ).toBool() )
437  {
438  CPLSetConfigOption( "SHAPE_ENCODING", nullptr );
439  }
440 
441  if ( srs.isValid() )
442  {
443  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
444  {
445  QString layerName = vectorFileName.left( vectorFileName.indexOf( QLatin1String( ".shp" ), Qt::CaseInsensitive ) );
446  QFile prjFile( layerName + ".qpj" );
447  if ( prjFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
448  {
449  QTextStream prjStream( &prjFile );
450  prjStream << srs.toWkt().toLocal8Bit().constData() << endl;
451  prjFile.close();
452  }
453  else
454  {
455  QgsDebugMsg( "Couldn't open file " + layerName + ".qpj" );
456  }
457  }
458  }
459 
460  if ( !mLayer )
461  {
462  if ( action == CreateOrOverwriteFile || action == CreateOrOverwriteLayer )
463  mErrorMessage = QObject::tr( "Creation of layer failed (OGR error: %1)" )
464  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
465  else
466  mErrorMessage = QObject::tr( "Opening of layer failed (OGR error: %1)" )
467  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
469  return;
470  }
471 
472  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( mLayer );
473 
474  QgsDebugMsg( "created layer" );
475 
476  // create the fields
477  QgsDebugMsg( "creating " + QString::number( fields.size() ) + " fields" );
478 
479  mFields = fields;
480  mAttrIdxToOgrIdx.clear();
481  QSet<int> existingIdxs;
482 
483  mFieldValueConverter = fieldValueConverter;
484 
485  for ( int fldIdx = 0; ( action == CreateOrOverwriteFile ||
486  action == CreateOrOverwriteLayer ||
487  action == AppendToLayerAddFields ) &&
488  fldIdx < fields.count(); ++fldIdx )
489  {
490  QgsField attrField = fields.at( fldIdx );
491 
492  if ( fieldValueConverter )
493  {
494  attrField = fieldValueConverter->fieldDefinition( fields.at( fldIdx ) );
495  }
496 
497  QString name( attrField.name() );
498  if ( action == AppendToLayerAddFields )
499  {
500  int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
501  if ( ogrIdx >= 0 )
502  {
503  mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
504  continue;
505  }
506  }
507 
508  OGRFieldType ogrType = OFTString; //default to string
509  int ogrWidth = attrField.length();
510  int ogrPrecision = attrField.precision();
511  if ( ogrPrecision > 0 )
512  ++ogrWidth;
513 
514  switch ( attrField.type() )
515  {
516  case QVariant::LongLong:
517  {
518  const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES, nullptr );
519  if ( pszDataTypes && strstr( pszDataTypes, "Integer64" ) )
520  ogrType = OFTInteger64;
521  else
522  ogrType = OFTReal;
523  ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
524  ogrPrecision = 0;
525  break;
526  }
527  case QVariant::String:
528  ogrType = OFTString;
529  if ( ogrWidth <= 0 || ogrWidth > 255 )
530  ogrWidth = 255;
531  break;
532 
533  case QVariant::Int:
534  ogrType = OFTInteger;
535  ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
536  ogrPrecision = 0;
537  break;
538 
539  case QVariant::Bool:
540  ogrType = OFTInteger;
541  ogrWidth = 1;
542  ogrPrecision = 0;
543  break;
544 
545  case QVariant::Double:
546  ogrType = OFTReal;
547  break;
548 
549  case QVariant::Date:
550  ogrType = OFTDate;
551  break;
552 
553  case QVariant::Time:
554  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
555  {
556  ogrType = OFTString;
557  ogrWidth = 12; // %02d:%02d:%06.3f
558  }
559  else
560  {
561  ogrType = OFTTime;
562  }
563  break;
564 
565  case QVariant::DateTime:
566  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
567  {
568  ogrType = OFTString;
569  ogrWidth = 24; // "%04d/%02d/%02d %02d:%02d:%06.3f"
570  }
571  else
572  {
573  ogrType = OFTDateTime;
574  }
575  break;
576 
577  default:
578  //assert(0 && "invalid variant type!");
579  mErrorMessage = QObject::tr( "Unsupported type for field %1" )
580  .arg( attrField.name() );
582  return;
583  }
584 
585  if ( mOgrDriverName == QLatin1String( "SQLite" ) && name.compare( QLatin1String( "ogc_fid" ), Qt::CaseInsensitive ) == 0 )
586  {
587  int i;
588  for ( i = 0; i < 10; i++ )
589  {
590  name = QStringLiteral( "ogc_fid%1" ).arg( i );
591 
592  int j;
593  for ( j = 0; j < fields.size() && name.compare( fields.at( j ).name(), Qt::CaseInsensitive ) != 0; j++ )
594  ;
595 
596  if ( j == fields.size() )
597  break;
598  }
599 
600  if ( i == 10 )
601  {
602  mErrorMessage = QObject::tr( "No available replacement for internal fieldname ogc_fid found" ).arg( attrField.name() );
604  return;
605  }
606 
607  QgsMessageLog::logMessage( QObject::tr( "Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr( "OGR" ) );
608  }
609 
610  // create field definition
611  gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( mCodec->fromUnicode( name ), ogrType ) );
612  if ( ogrWidth > 0 )
613  {
614  OGR_Fld_SetWidth( fld.get(), ogrWidth );
615  }
616 
617  if ( ogrPrecision >= 0 )
618  {
619  OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
620  }
621 
622  switch ( attrField.type() )
623  {
624  case QVariant::Bool:
625  OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
626  break;
627  default:
628  break;
629  }
630 
631  // create the field
632  QgsDebugMsg( "creating field " + attrField.name() +
633  " type " + QString( QVariant::typeToName( attrField.type() ) ) +
634  " width " + QString::number( ogrWidth ) +
635  " precision " + QString::number( ogrPrecision ) );
636  if ( OGR_L_CreateField( mLayer, fld.get(), true ) != OGRERR_NONE )
637  {
638  QgsDebugMsg( "error creating field " + attrField.name() );
639  mErrorMessage = QObject::tr( "Creation of field %1 failed (OGR error: %2)" )
640  .arg( attrField.name(),
641  QString::fromUtf8( CPLGetLastErrorMsg() ) );
643  return;
644  }
645 
646  int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
647  QgsDebugMsg( QString( "returned field index for %1: %2" ).arg( name ).arg( ogrIdx ) );
648  if ( ogrIdx < 0 || existingIdxs.contains( ogrIdx ) )
649  {
650  // GDAL 1.7 not just truncates, but launders more aggressivly.
651  ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
652 
653  if ( ogrIdx < 0 )
654  {
655  QgsDebugMsg( "error creating field " + attrField.name() );
656  mErrorMessage = QObject::tr( "Created field %1 not found (OGR error: %2)" )
657  .arg( attrField.name(),
658  QString::fromUtf8( CPLGetLastErrorMsg() ) );
660  return;
661  }
662  }
663 
664  existingIdxs.insert( ogrIdx );
665  mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
666  }
667 
668  if ( action == AppendToLayerNoNewFields )
669  {
670  for ( int fldIdx = 0; fldIdx < fields.count(); ++fldIdx )
671  {
672  QgsField attrField = fields.at( fldIdx );
673  QString name( attrField.name() );
674  int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
675  if ( ogrIdx >= 0 )
676  mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
677  }
678  }
679 
680  QgsDebugMsg( "Done creating fields" );
681 
682  mWkbType = geometryType;
683 
684  if ( newFilename )
685  *newFilename = vectorFileName;
686 
687  // enabling transaction on databases that support it
688  mUsingTransaction = true;
689  if ( OGRERR_NONE != OGR_L_StartTransaction( mLayer ) )
690  {
691  mUsingTransaction = false;
692  }
693 }
694 
696 {
697  return OGR_G_CreateGeometry( ogrTypeFromWkbType( wkbType ) );
698 }
699 
701 class QgsVectorFileWriterMetadataContainer
702 {
703  public:
704 
705  QgsVectorFileWriterMetadataContainer()
706  {
707  QMap<QString, QgsVectorFileWriter::Option *> datasetOptions;
708  QMap<QString, QgsVectorFileWriter::Option *> layerOptions;
709 
710  // Arc/Info ASCII Coverage
711  datasetOptions.clear();
712  layerOptions.clear();
713 
714  driverMetadata.insert( QStringLiteral( "AVCE00" ),
716  QStringLiteral( "Arc/Info ASCII Coverage" ),
717  QObject::tr( "Arc/Info ASCII Coverage" ),
718  QStringLiteral( "*.e00" ),
719  QStringLiteral( "e00" ),
720  datasetOptions,
721  layerOptions
722  )
723  );
724 
725  // Atlas BNA
726  datasetOptions.clear();
727  layerOptions.clear();
728 
729  datasetOptions.insert( QStringLiteral( "LINEFORMAT" ), new QgsVectorFileWriter::SetOption(
730  QObject::tr( "New BNA files are created by the "
731  "systems default line termination conventions. "
732  "This may be overridden here." ),
733  QStringList()
734  << QStringLiteral( "CRLF" )
735  << QStringLiteral( "LF" ),
736  QString(), // Default value
737  true // Allow None
738  ) );
739 
740  datasetOptions.insert( QStringLiteral( "MULTILINE" ), new QgsVectorFileWriter::BoolOption(
741  QObject::tr( "By default, BNA files are created in multi-line format. "
742  "For each record, the first line contains the identifiers and the "
743  "type/number of coordinates to follow. Each following line contains "
744  "a pair of coordinates." ),
745  true // Default value
746  ) );
747 
748  datasetOptions.insert( QStringLiteral( "NB_IDS" ), new QgsVectorFileWriter::SetOption(
749  QObject::tr( "BNA records may contain from 2 to 4 identifiers per record. "
750  "Some software packages only support a precise number of identifiers. "
751  "You can override the default value (2) by a precise value." ),
752  QStringList()
753  << QStringLiteral( "2" )
754  << QStringLiteral( "3" )
755  << QStringLiteral( "4" )
756  << QStringLiteral( "NB_SOURCE_FIELDS" ),
757  QStringLiteral( "2" ) // Default value
758  ) );
759 
760  datasetOptions.insert( QStringLiteral( "ELLIPSES_AS_ELLIPSES" ), new QgsVectorFileWriter::BoolOption(
761  QObject::tr( "The BNA writer will try to recognize ellipses and circles when writing a polygon. "
762  "This will only work if the feature has previously been read from a BNA file. "
763  "As some software packages do not support ellipses/circles in BNA data file, "
764  "it may be useful to tell the writer by specifying ELLIPSES_AS_ELLIPSES=NO not "
765  "to export them as such, but keep them as polygons." ),
766  true // Default value
767  ) );
768 
769  datasetOptions.insert( QStringLiteral( "NB_PAIRS_PER_LINE" ), new QgsVectorFileWriter::IntOption(
770  QObject::tr( "Limit the number of coordinate pairs per line in multiline format." ),
771  2 // Default value
772  ) );
773 
774  datasetOptions.insert( QStringLiteral( "COORDINATE_PRECISION" ), new QgsVectorFileWriter::IntOption(
775  QObject::tr( "Set the number of decimal for coordinates. Default value is 10." ),
776  10 // Default value
777  ) );
778 
779  driverMetadata.insert( QStringLiteral( "BNA" ),
781  QStringLiteral( "Atlas BNA" ),
782  QObject::tr( "Atlas BNA" ),
783  QStringLiteral( "*.bna" ),
784  QStringLiteral( "bna" ),
785  datasetOptions,
786  layerOptions
787  )
788  );
789 
790  // Comma Separated Value
791  datasetOptions.clear();
792  layerOptions.clear();
793 
794  layerOptions.insert( QStringLiteral( "LINEFORMAT" ), new QgsVectorFileWriter::SetOption(
795  QObject::tr( "By default when creating new .csv files they "
796  "are created with the line termination conventions "
797  "of the local platform (CR/LF on Win32 or LF on all other systems). "
798  "This may be overridden through the use of the LINEFORMAT option." ),
799  QStringList()
800  << QStringLiteral( "CRLF" )
801  << QStringLiteral( "LF" ),
802  QString(), // Default value
803  true // Allow None
804  ) );
805 
806  layerOptions.insert( QStringLiteral( "GEOMETRY" ), new QgsVectorFileWriter::SetOption(
807  QObject::tr( "By default, the geometry of a feature written to a .csv file is discarded. "
808  "It is possible to export the geometry in its WKT representation by "
809  "specifying GEOMETRY=AS_WKT. It is also possible to export point geometries "
810  "into their X,Y,Z components by specifying GEOMETRY=AS_XYZ, GEOMETRY=AS_XY "
811  "or GEOMETRY=AS_YX." ),
812  QStringList()
813  << QStringLiteral( "AS_WKT" )
814  << QStringLiteral( "AS_XYZ" )
815  << QStringLiteral( "AS_XY" )
816  << QStringLiteral( "AS_YX" ),
817  QString(), // Default value
818  true // Allow None
819  ) );
820 
821  layerOptions.insert( QStringLiteral( "CREATE_CSVT" ), new QgsVectorFileWriter::BoolOption(
822  QObject::tr( "Create the associated .csvt file to describe the type of each "
823  "column of the layer and its optional width and precision." ),
824  false // Default value
825  ) );
826 
827  layerOptions.insert( QStringLiteral( "SEPARATOR" ), new QgsVectorFileWriter::SetOption(
828  QObject::tr( "Field separator character." ),
829  QStringList()
830  << QStringLiteral( "COMMA" )
831  << QStringLiteral( "SEMICOLON" )
832  << QStringLiteral( "TAB" ),
833  QStringLiteral( "COMMA" ) // Default value
834  ) );
835 
836  layerOptions.insert( QStringLiteral( "WRITE_BOM" ), new QgsVectorFileWriter::BoolOption(
837  QObject::tr( "Write a UTF-8 Byte Order Mark (BOM) at the start of the file." ),
838  false // Default value
839  ) );
840 
841  driverMetadata.insert( QStringLiteral( "CSV" ),
843  QStringLiteral( "Comma Separated Value [CSV]" ),
844  QObject::tr( "Comma Separated Value [CSV]" ),
845  QStringLiteral( "*.csv" ),
846  QStringLiteral( "csv" ),
847  datasetOptions,
848  layerOptions
849  )
850  );
851 
852  // ESRI Shapefile
853  datasetOptions.clear();
854  layerOptions.clear();
855 
856  layerOptions.insert( QStringLiteral( "SHPT" ), new QgsVectorFileWriter::SetOption(
857  QObject::tr( "Override the type of shapefile created. "
858  "Can be one of NULL for a simple .dbf file with no .shp file, POINT, "
859  "ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or "
860  "MULTIPOINTZ for 3D;" ) +
861  QObject::tr( " POINTM, ARCM, POLYGONM or MULTIPOINTM for measured geometries"
862  " and POINTZM, ARCZM, POLYGONZM or MULTIPOINTZM for 3D measured"
863  " geometries." ) +
864 #if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
865  QObject::tr( " MULTIPATCH files are supported since GDAL 2.2." ) +
866 #endif
867  ""
868  , QStringList()
869  << QStringLiteral( "NULL" )
870  << QStringLiteral( "POINT" )
871  << QStringLiteral( "ARC" )
872  << QStringLiteral( "POLYGON" )
873  << QStringLiteral( "MULTIPOINT" )
874  << QStringLiteral( "POINTZ" )
875  << QStringLiteral( "ARCZ" )
876  << QStringLiteral( "POLYGONZ" )
877  << QStringLiteral( "MULTIPOINTZ" )
878  << QStringLiteral( "POINTM" )
879  << QStringLiteral( "ARCM" )
880  << QStringLiteral( "POLYGONM" )
881  << QStringLiteral( "MULTIPOINTM" )
882  << QStringLiteral( "POINTZM" )
883  << QStringLiteral( "ARCZM" )
884  << QStringLiteral( "POLYGONZM" )
885  << QStringLiteral( "MULTIPOINTZM" )
886 #if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
887  << QStringLiteral( "MULTIPATCH" )
888 #endif
889  << QStringLiteral( "" ),
890  QString(), // Default value
891  true // Allow None
892  ) );
893 
894  // there does not seem to be a reason to provide this option to the user again
895  // as we set encoding for shapefiles based on "fileEncoding" parameter passed to the writer
896 #if 0
897  layerOptions.insert( "ENCODING", new QgsVectorFileWriter::SetOption(
898  QObject::tr( "Set the encoding value in the DBF file. "
899  "The default value is LDID/87. It is not clear "
900  "what other values may be appropriate." ),
901  QStringList()
902  << "LDID/87",
903  "LDID/87" // Default value
904  ) );
905 #endif
906 
907  layerOptions.insert( QStringLiteral( "RESIZE" ), new QgsVectorFileWriter::BoolOption(
908  QObject::tr( "Set to YES to resize fields to their optimal size." ),
909  false // Default value
910  ) );
911 
912  driverMetadata.insert( QStringLiteral( "ESRI" ),
914  QStringLiteral( "ESRI Shapefile" ),
915  QObject::tr( "ESRI Shapefile" ),
916  QStringLiteral( "*.shp" ),
917  QStringLiteral( "shp" ),
918  datasetOptions,
919  layerOptions
920  )
921  );
922 
923  // DBF File
924  datasetOptions.clear();
925  layerOptions.clear();
926 
927  driverMetadata.insert( QStringLiteral( "DBF File" ),
929  QStringLiteral( "DBF File" ),
930  QObject::tr( "DBF File" ),
931  QStringLiteral( "*.dbf" ),
932  QStringLiteral( "dbf" ),
933  datasetOptions,
934  layerOptions
935  )
936  );
937 
938  // FMEObjects Gateway
939  datasetOptions.clear();
940  layerOptions.clear();
941 
942  driverMetadata.insert( QStringLiteral( "FMEObjects Gateway" ),
944  QStringLiteral( "FMEObjects Gateway" ),
945  QObject::tr( "FMEObjects Gateway" ),
946  QStringLiteral( "*.fdd" ),
947  QStringLiteral( "fdd" ),
948  datasetOptions,
949  layerOptions
950  )
951  );
952 
953  // GeoJSON
954  datasetOptions.clear();
955  layerOptions.clear();
956 
957  layerOptions.insert( QStringLiteral( "WRITE_BBOX" ), new QgsVectorFileWriter::BoolOption(
958  QObject::tr( "Set to YES to write a bbox property with the bounding box "
959  "of the geometries at the feature and feature collection level." ),
960  false // Default value
961  ) );
962 
963  layerOptions.insert( QStringLiteral( "COORDINATE_PRECISION" ), new QgsVectorFileWriter::IntOption(
964  QObject::tr( "Maximum number of figures after decimal separator to write in coordinates. "
965  "Default to 15. Truncation will occur to remove trailing zeros." ),
966  15 // Default value
967  ) );
968 
969  driverMetadata.insert( QStringLiteral( "GeoJSON" ),
971  QStringLiteral( "GeoJSON" ),
972  QObject::tr( "GeoJSON" ),
973  QStringLiteral( "*.geojson" ),
974  QStringLiteral( "geojson" ),
975  datasetOptions,
976  layerOptions,
977  QStringLiteral( "UTF-8" )
978  )
979  );
980 
981  // GeoRSS
982  datasetOptions.clear();
983  layerOptions.clear();
984 
985  datasetOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
986  QObject::tr( "whether the document must be in RSS 2.0 or Atom 1.0 format. "
987  "Default value : RSS" ),
988  QStringList()
989  << QStringLiteral( "RSS" )
990  << QStringLiteral( "ATOM" ),
991  QStringLiteral( "RSS" ) // Default value
992  ) );
993 
994  datasetOptions.insert( QStringLiteral( "GEOM_DIALECT" ), new QgsVectorFileWriter::SetOption(
995  QObject::tr( "The encoding of location information. Default value : SIMPLE. "
996  "W3C_GEO only supports point geometries. "
997  "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
998  QStringList()
999  << QStringLiteral( "SIMPLE" )
1000  << QStringLiteral( "GML" )
1001  << QStringLiteral( "W3C_GEO" ),
1002  QStringLiteral( "SIMPLE" ) // Default value
1003  ) );
1004 
1005  datasetOptions.insert( QStringLiteral( "USE_EXTENSIONS" ), new QgsVectorFileWriter::BoolOption(
1006  QObject::tr( "If defined to YES, extension fields will be written. "
1007  "If the field name not found in the base schema matches "
1008  "the foo_bar pattern, foo will be considered as the namespace "
1009  "of the element, and a <foo:bar> element will be written. "
1010  "Otherwise, elements will be written in the <ogr:> namespace." ),
1011  false // Default value
1012  ) );
1013 
1014  datasetOptions.insert( QStringLiteral( "WRITE_HEADER_AND_FOOTER" ), new QgsVectorFileWriter::BoolOption(
1015  QObject::tr( "If defined to NO, only <entry> or <item> elements will be written. "
1016  "The user will have to provide the appropriate header and footer of the document." ),
1017  true // Default value
1018  ) );
1019 
1020  datasetOptions.insert( QStringLiteral( "HEADER" ), new QgsVectorFileWriter::StringOption(
1021  QObject::tr( "XML content that will be put between the <channel> element and the "
1022  "first <item> element for a RSS document, or between the xml tag and "
1023  "the first <entry> element for an Atom document." ),
1024  QLatin1String( "" ) // Default value
1025  ) );
1026 
1027  datasetOptions.insert( QStringLiteral( "TITLE" ), new QgsVectorFileWriter::StringOption(
1028  QObject::tr( "Value put inside the <title> element in the header. "
1029  "If not provided, a dummy value will be used as that element is compulsory." ),
1030  QLatin1String( "" ) // Default value
1031  ) );
1032 
1033  datasetOptions.insert( QStringLiteral( "DESCRIPTION" ), new QgsVectorFileWriter::StringOption(
1034  QObject::tr( "Value put inside the <description> element in the header. "
1035  "If not provided, a dummy value will be used as that element is compulsory." ),
1036  QLatin1String( "" ) // Default value
1037  ) );
1038 
1039  datasetOptions.insert( QStringLiteral( "LINK" ), new QgsVectorFileWriter::StringOption(
1040  QObject::tr( "Value put inside the <link> element in the header. "
1041  "If not provided, a dummy value will be used as that element is compulsory." ),
1042  QLatin1String( "" ) // Default value
1043  ) );
1044 
1045  datasetOptions.insert( QStringLiteral( "UPDATED" ), new QgsVectorFileWriter::StringOption(
1046  QObject::tr( "Value put inside the <updated> element in the header. "
1047  "Should be formatted as a XML datetime. "
1048  "If not provided, a dummy value will be used as that element is compulsory." ),
1049  QLatin1String( "" ) // Default value
1050  ) );
1051 
1052  datasetOptions.insert( QStringLiteral( "AUTHOR_NAME" ), new QgsVectorFileWriter::StringOption(
1053  QObject::tr( "Value put inside the <author><name> element in the header. "
1054  "If not provided, a dummy value will be used as that element is compulsory." ),
1055  QLatin1String( "" ) // Default value
1056  ) );
1057 
1058  datasetOptions.insert( QStringLiteral( "ID" ), new QgsVectorFileWriter::StringOption(
1059  QObject::tr( "Value put inside the <id> element in the header. "
1060  "If not provided, a dummy value will be used as that element is compulsory." ),
1061  QLatin1String( "" ) // Default value
1062  ) );
1063 
1064  driverMetadata.insert( QStringLiteral( "GeoRSS" ),
1066  QStringLiteral( "GeoRSS" ),
1067  QObject::tr( "GeoRSS" ),
1068  QStringLiteral( "*.xml" ),
1069  QStringLiteral( "xml" ),
1070  datasetOptions,
1071  layerOptions,
1072  QStringLiteral( "UTF-8" )
1073  )
1074  );
1075 
1076  // Geography Markup Language [GML]
1077  datasetOptions.clear();
1078  layerOptions.clear();
1079 
1080  datasetOptions.insert( QStringLiteral( "XSISCHEMAURI" ), new QgsVectorFileWriter::StringOption(
1081  QObject::tr( "If provided, this URI will be inserted as the schema location. "
1082  "Note that the schema file isn't actually accessed by OGR, so it "
1083  "is up to the user to ensure it will match the schema of the OGR "
1084  "produced GML data file." ),
1085  QString() // Default value
1086  ) );
1087 
1088  datasetOptions.insert( QStringLiteral( "XSISCHEMA" ), new QgsVectorFileWriter::SetOption(
1089  QObject::tr( "This writes a GML application schema file to a corresponding "
1090  ".xsd file (with the same basename). If INTERNAL is used the "
1091  "schema is written within the GML file, but this is experimental "
1092  "and almost certainly not valid XML. "
1093  "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
1094  QStringList()
1095  << QStringLiteral( "EXTERNAL" )
1096  << QStringLiteral( "INTERNAL" )
1097  << QStringLiteral( "OFF" ),
1098  QStringLiteral( "EXTERNAL" ) // Default value
1099  ) );
1100 
1101  datasetOptions.insert( QStringLiteral( "PREFIX" ), new QgsVectorFileWriter::StringOption(
1102  QObject::tr( "This is the prefix for the application target namespace." ),
1103  QStringLiteral( "ogr" ) // Default value
1104  ) );
1105 
1106  datasetOptions.insert( QStringLiteral( "STRIP_PREFIX" ), new QgsVectorFileWriter::BoolOption(
1107  QObject::tr( "Can be set to TRUE to avoid writing the prefix of the "
1108  "application target namespace in the GML file." ),
1109  false // Default value
1110  ) );
1111 
1112  datasetOptions.insert( QStringLiteral( "TARGET_NAMESPACE" ), new QgsVectorFileWriter::StringOption(
1113  QObject::tr( "Defaults to 'http://ogr.maptools.org/'. "
1114  "This is the application target namespace." ),
1115  QStringLiteral( "http://ogr.maptools.org/" ) // Default value
1116  ) );
1117 
1118  datasetOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
1119  QObject::tr( "If not specified, GML2 will be used." ),
1120  QStringList()
1121  << QStringLiteral( "GML3" )
1122  << QStringLiteral( "GML3Deegree" )
1123  << QStringLiteral( "GML3.2" ),
1124  QLatin1String( "" ), // Default value
1125  true // Allow None
1126  ) );
1127 
1128  datasetOptions.insert( QStringLiteral( "GML3_LONGSRS" ), new QgsVectorFileWriter::BoolOption(
1129  QObject::tr( "Only valid when FORMAT=GML3/GML3Degree/GML3.2. Default to YES. " //needs review here
1130  "If YES, SRS with EPSG authority will be written with the "
1131  "'urn:ogc:def:crs:EPSG::' prefix. In the case the SRS is a "
1132  "geographic SRS without explicit AXIS order, but that the same "
1133  "SRS authority code imported with ImportFromEPSGA() should be "
1134  "treated as lat/long, then the function will take care of coordinate "
1135  "order swapping. If set to NO, SRS with EPSG authority will be "
1136  "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
1137  true // Default value
1138  ) );
1139 
1140  datasetOptions.insert( QStringLiteral( "WRITE_FEATURE_BOUNDED_BY" ), new QgsVectorFileWriter::BoolOption(
1141  QObject::tr( "only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
1142  "If set to NO, the <gml:boundedBy> element will not be written for "
1143  "each feature." ),
1144  true // Default value
1145  ) );
1146 
1147  datasetOptions.insert( QStringLiteral( "SPACE_INDENTATION" ), new QgsVectorFileWriter::BoolOption(
1148  QObject::tr( "Default to YES. If YES, the output will be indented with spaces "
1149  "for more readability, but at the expense of file size." ),
1150  true // Default value
1151  ) );
1152 
1153 
1154  driverMetadata.insert( QStringLiteral( "GML" ),
1156  QStringLiteral( "Geography Markup Language [GML]" ),
1157  QObject::tr( "Geography Markup Language [GML]" ),
1158  QStringLiteral( "*.gml" ),
1159  QStringLiteral( "gml" ),
1160  datasetOptions,
1161  layerOptions,
1162  QStringLiteral( "UTF-8" )
1163  )
1164  );
1165 
1166  // GeoPackage
1167  datasetOptions.clear();
1168  layerOptions.clear();
1169 
1170  layerOptions.insert( QStringLiteral( "IDENTIFIER" ), new QgsVectorFileWriter::StringOption(
1171  QObject::tr( "Human-readable identifier (e.g. short name) for the layer content" ),
1172  QLatin1String( "" ) // Default value
1173  ) );
1174 
1175  layerOptions.insert( QStringLiteral( "DESCRIPTION" ), new QgsVectorFileWriter::StringOption(
1176  QObject::tr( "Human-readable description for the layer content" ),
1177  QLatin1String( "" ) // Default value
1178  ) );
1179 
1180  layerOptions.insert( QStringLiteral( "FID" ), new QgsVectorFileWriter::StringOption(
1181  QObject::tr( "Name for the feature identifier column" ),
1182  QStringLiteral( "fid" ) // Default value
1183  ) );
1184 
1185  layerOptions.insert( QStringLiteral( "GEOMETRY_NAME" ), new QgsVectorFileWriter::StringOption(
1186  QObject::tr( "Name for the geometry column" ),
1187  QStringLiteral( "geom" ) // Default value
1188  ) );
1189 
1190  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::BoolOption(
1191  QObject::tr( "If a spatial index must be created." ),
1192  true // Default value
1193  ) );
1194 
1195  driverMetadata.insert( QStringLiteral( "GPKG" ),
1197  QStringLiteral( "GeoPackage" ),
1198  QObject::tr( "GeoPackage" ),
1199  QStringLiteral( "*.gpkg" ),
1200  QStringLiteral( "gpkg" ),
1201  datasetOptions,
1202  layerOptions,
1203  QStringLiteral( "UTF-8" )
1204  )
1205  );
1206 
1207  // Generic Mapping Tools [GMT]
1208  datasetOptions.clear();
1209  layerOptions.clear();
1210 
1211  driverMetadata.insert( QStringLiteral( "GMT" ),
1213  QStringLiteral( "Generic Mapping Tools [GMT]" ),
1214  QObject::tr( "Generic Mapping Tools [GMT]" ),
1215  QStringLiteral( "*.gmt" ),
1216  QStringLiteral( "gmt" ),
1217  datasetOptions,
1218  layerOptions
1219  )
1220  );
1221 
1222  // GPS eXchange Format [GPX]
1223  datasetOptions.clear();
1224  layerOptions.clear();
1225 
1226  layerOptions.insert( QStringLiteral( "FORCE_GPX_TRACK" ), new QgsVectorFileWriter::BoolOption(
1227  QObject::tr( "By default when writing a layer whose features are of "
1228  "type wkbLineString, the GPX driver chooses to write "
1229  "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1230  "they will be written as tracks." ),
1231  false // Default value
1232  ) );
1233 
1234  layerOptions.insert( QStringLiteral( "FORCE_GPX_ROUTE" ), new QgsVectorFileWriter::BoolOption(
1235  QObject::tr( "By default when writing a layer whose features are of "
1236  "type wkbMultiLineString, the GPX driver chooses to write "
1237  "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1238  "they will be written as routes, provided that the multilines "
1239  "are composed of only one single line." ),
1240  false // Default value
1241  ) );
1242 
1243  datasetOptions.insert( QStringLiteral( "GPX_USE_EXTENSIONS" ), new QgsVectorFileWriter::BoolOption(
1244  QObject::tr( "If GPX_USE_EXTENSIONS=YES is specified, "
1245  "extra fields will be written inside the <extensions> tag." ),
1246  false // Default value
1247  ) );
1248 
1249  datasetOptions.insert( QStringLiteral( "GPX_EXTENSIONS_NS" ), new QgsVectorFileWriter::StringOption(
1250  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1251  "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1252  QStringLiteral( "ogr" ) // Default value
1253  ) );
1254 
1255  datasetOptions.insert( QStringLiteral( "GPX_EXTENSIONS_NS_URL" ), new QgsVectorFileWriter::StringOption(
1256  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1257  "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1258  QStringLiteral( "http://osgeo.org/gdal" ) // Default value
1259  ) );
1260 
1261  datasetOptions.insert( QStringLiteral( "LINEFORMAT" ), new QgsVectorFileWriter::SetOption(
1262  QObject::tr( "By default files are created with the line termination "
1263  "conventions of the local platform (CR/LF on win32 or LF "
1264  "on all other systems). This may be overridden through use "
1265  "of the LINEFORMAT layer creation option which may have a value "
1266  "of CRLF (DOS format) or LF (Unix format)." ),
1267  QStringList()
1268  << QStringLiteral( "CRLF" )
1269  << QStringLiteral( "LF" ),
1270  QLatin1String( "" ), // Default value
1271  true // Allow None
1272  ) );
1273 
1274  driverMetadata.insert( QStringLiteral( "GPX" ),
1276  QStringLiteral( "GPS eXchange Format [GPX]" ),
1277  QObject::tr( "GPS eXchange Format [GPX]" ),
1278  QStringLiteral( "*.gpx" ),
1279  QStringLiteral( "gpx" ),
1280  datasetOptions,
1281  layerOptions,
1282  QStringLiteral( "UTF-8" )
1283  )
1284  );
1285 
1286  // INTERLIS 1
1287  datasetOptions.clear();
1288  layerOptions.clear();
1289 
1290  driverMetadata.insert( QStringLiteral( "Interlis 1" ),
1292  QStringLiteral( "INTERLIS 1" ),
1293  QObject::tr( "INTERLIS 1" ),
1294  QStringLiteral( "*.itf *.xml *.ili" ),
1295  QStringLiteral( "ili" ),
1296  datasetOptions,
1297  layerOptions
1298  )
1299  );
1300 
1301  // INTERLIS 2
1302  datasetOptions.clear();
1303  layerOptions.clear();
1304 
1305  driverMetadata.insert( QStringLiteral( "Interlis 2" ),
1307  QStringLiteral( "INTERLIS 2" ),
1308  QObject::tr( "INTERLIS 2" ),
1309  QStringLiteral( "*.xtf *.xml *.ili" ),
1310  QStringLiteral( "ili" ),
1311  datasetOptions,
1312  layerOptions
1313  )
1314  );
1315 
1316  // Keyhole Markup Language [KML]
1317  datasetOptions.clear();
1318  layerOptions.clear();
1319 
1320  datasetOptions.insert( QStringLiteral( "NameField" ), new QgsVectorFileWriter::StringOption(
1321  QObject::tr( "Allows you to specify the field to use for the KML <name> element." ),
1322  QStringLiteral( "Name" ) // Default value
1323  ) );
1324 
1325  datasetOptions.insert( QStringLiteral( "DescriptionField" ), new QgsVectorFileWriter::StringOption(
1326  QObject::tr( "Allows you to specify the field to use for the KML <description> element." ),
1327  QStringLiteral( "Description" ) // Default value
1328  ) );
1329 
1330  datasetOptions.insert( QStringLiteral( "AltitudeMode" ), new QgsVectorFileWriter::SetOption(
1331  QObject::tr( "Allows you to specify the AltitudeMode to use for KML geometries. "
1332  "This will only affect 3D geometries and must be one of the valid KML options." ),
1333  QStringList()
1334  << QStringLiteral( "clampToGround" )
1335  << QStringLiteral( "relativeToGround" )
1336  << QStringLiteral( "absolute" ),
1337  QStringLiteral( "relativeToGround" ) // Default value
1338  ) );
1339 
1340 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
1341  datasetOptions.insert( QStringLiteral( "DOCUMENT_ID" ), new QgsVectorFileWriter::StringOption(
1342  QObject::tr( "The DOCUMENT_ID datasource creation option can be used to specified "
1343  "the id of the root <Document> node. The default value is root_doc." ),
1344  QStringLiteral( "root_doc" ) // Default value
1345  ) );
1346 #endif
1347 
1348  driverMetadata.insert( QStringLiteral( "KML" ),
1350  QStringLiteral( "Keyhole Markup Language [KML]" ),
1351  QObject::tr( "Keyhole Markup Language [KML]" ),
1352  QStringLiteral( "*.kml" ),
1353  QStringLiteral( "kml" ),
1354  datasetOptions,
1355  layerOptions,
1356  QStringLiteral( "UTF-8" )
1357  )
1358  );
1359 
1360  // Mapinfo
1361  datasetOptions.clear();
1362  layerOptions.clear();
1363 
1364  auto insertMapInfoOptions = []( QMap<QString, QgsVectorFileWriter::Option *> &datasetOptions, QMap<QString, QgsVectorFileWriter::Option *> &layerOptions )
1365  {
1366  datasetOptions.insert( QStringLiteral( "SPATIAL_INDEX_MODE" ), new QgsVectorFileWriter::SetOption(
1367  QObject::tr( "Use this to turn on 'quick spatial index mode'. "
1368  "In this mode writing files can be about 5 times faster, "
1369  "but spatial queries can be up to 30 times slower." ),
1370  QStringList()
1371  << QStringLiteral( "QUICK" )
1372  << QStringLiteral( "OPTIMIZED" ),
1373  QStringLiteral( "QUICK" ), // Default value
1374  true // Allow None
1375  ) );
1376 
1377  datasetOptions.insert( QStringLiteral( "BLOCK_SIZE" ), new QgsVectorFileWriter::IntOption(
1378  QObject::tr( "(multiples of 512): Block size for .map files. Defaults "
1379  "to 512. MapInfo 15.2 and above creates .tab files with a "
1380  "blocksize of 16384 bytes. Any MapInfo version should be "
1381  "able to handle block sizes from 512 to 32256." ),
1382  512
1383  ) );
1384  layerOptions.insert( QStringLiteral( "BOUNDS" ), new QgsVectorFileWriter::StringOption(
1385  QObject::tr( "xmin,ymin,xmax,ymax: Define custom layer bounds to increase the "
1386  "accuracy of the coordinates. Note: the geometry of written "
1387  "features must be within the defined box." ),
1388  QLatin1String( "" ) // Default value
1389  ) );
1390  };
1391  insertMapInfoOptions( datasetOptions, layerOptions );
1392 
1393  driverMetadata.insert( QStringLiteral( "MapInfo File" ),
1395  QStringLiteral( "Mapinfo" ),
1396  QObject::tr( "Mapinfo TAB" ),
1397  QStringLiteral( "*.tab" ),
1398  QStringLiteral( "tab" ),
1399  datasetOptions,
1400  layerOptions
1401  )
1402  );
1403  datasetOptions.clear();
1404  layerOptions.clear();
1405  insertMapInfoOptions( datasetOptions, layerOptions );
1406 
1407  // QGIS internal alias for MIF files
1408  driverMetadata.insert( QStringLiteral( "MapInfo MIF" ),
1410  QStringLiteral( "Mapinfo" ),
1411  QObject::tr( "Mapinfo MIF" ),
1412  QStringLiteral( "*.mif" ),
1413  QStringLiteral( "mif" ),
1414  datasetOptions,
1415  layerOptions
1416  )
1417  );
1418 
1419  // Microstation DGN
1420  datasetOptions.clear();
1421  layerOptions.clear();
1422 
1423  datasetOptions.insert( QStringLiteral( "3D" ), new QgsVectorFileWriter::BoolOption(
1424  QObject::tr( "Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1425  "seed file should be used. This option is ignored if the SEED option is provided." ),
1426  false // Default value
1427  ) );
1428 
1429  datasetOptions.insert( QStringLiteral( "SEED" ), new QgsVectorFileWriter::StringOption(
1430  QObject::tr( "Override the seed file to use." ),
1431  QLatin1String( "" ) // Default value
1432  ) );
1433 
1434  datasetOptions.insert( QStringLiteral( "COPY_WHOLE_SEED_FILE" ), new QgsVectorFileWriter::BoolOption(
1435  QObject::tr( "Indicate whether the whole seed file should be copied. "
1436  "If not, only the first three elements will be copied." ),
1437  false // Default value
1438  ) );
1439 
1440  datasetOptions.insert( QStringLiteral( "COPY_SEED_FILE_COLOR_TABLE" ), new QgsVectorFileWriter::BoolOption(
1441  QObject::tr( "Indicates whether the color table should be copied from the seed file." ),
1442  false // Default value
1443  ) );
1444 
1445  datasetOptions.insert( QStringLiteral( "MASTER_UNIT_NAME" ), new QgsVectorFileWriter::StringOption(
1446  QObject::tr( "Override the master unit name from the seed file with "
1447  "the provided one or two character unit name." ),
1448  QLatin1String( "" ) // Default value
1449  ) );
1450 
1451  datasetOptions.insert( QStringLiteral( "SUB_UNIT_NAME" ), new QgsVectorFileWriter::StringOption(
1452  QObject::tr( "Override the sub unit name from the seed file with the provided "
1453  "one or two character unit name." ),
1454  QLatin1String( "" ) // Default value
1455  ) );
1456 
1457  datasetOptions.insert( QStringLiteral( "SUB_UNITS_PER_MASTER_UNIT" ), new QgsVectorFileWriter::IntOption(
1458  QObject::tr( "Override the number of subunits per master unit. "
1459  "By default the seed file value is used." ),
1460  0 // Default value
1461  ) );
1462 
1463  datasetOptions.insert( QStringLiteral( "UOR_PER_SUB_UNIT" ), new QgsVectorFileWriter::IntOption(
1464  QObject::tr( "Override the number of UORs (Units of Resolution) "
1465  "per sub unit. By default the seed file value is used." ),
1466  0 // Default value
1467  ) );
1468 
1469  datasetOptions.insert( QStringLiteral( "ORIGIN" ), new QgsVectorFileWriter::StringOption(
1470  QObject::tr( "ORIGIN=x,y,z: Override the origin of the design plane. "
1471  "By default the origin from the seed file is used." ),
1472  QLatin1String( "" ) // Default value
1473  ) );
1474 
1475  driverMetadata.insert( QStringLiteral( "DGN" ),
1477  QStringLiteral( "Microstation DGN" ),
1478  QObject::tr( "Microstation DGN" ),
1479  QStringLiteral( "*.dgn" ),
1480  QStringLiteral( "dgn" ),
1481  datasetOptions,
1482  layerOptions
1483  )
1484  );
1485 
1486  // S-57 Base file
1487  datasetOptions.clear();
1488  layerOptions.clear();
1489 
1490  datasetOptions.insert( QStringLiteral( "UPDATES" ), new QgsVectorFileWriter::SetOption(
1491  QObject::tr( "Should update files be incorporated into the base data on the fly." ),
1492  QStringList()
1493  << QStringLiteral( "APPLY" )
1494  << QStringLiteral( "IGNORE" ),
1495  QStringLiteral( "APPLY" ) // Default value
1496  ) );
1497 
1498  datasetOptions.insert( QStringLiteral( "SPLIT_MULTIPOINT" ), new QgsVectorFileWriter::BoolOption(
1499  QObject::tr( "Should multipoint soundings be split into many single point sounding features. "
1500  "Multipoint geometries are not well handled by many formats, "
1501  "so it can be convenient to split single sounding features with many points "
1502  "into many single point features." ),
1503  false // Default value
1504  ) );
1505 
1506  datasetOptions.insert( QStringLiteral( "ADD_SOUNDG_DEPTH" ), new QgsVectorFileWriter::BoolOption(
1507  QObject::tr( "Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1508  "of the sounding. This should only be enabled when SPLIT_MULTIPOINT is "
1509  "also enabled." ),
1510  false // Default value
1511  ) );
1512 
1513  datasetOptions.insert( QStringLiteral( "RETURN_PRIMITIVES" ), new QgsVectorFileWriter::BoolOption(
1514  QObject::tr( "Should all the low level geometry primitives be returned as special "
1515  "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1516  false // Default value
1517  ) );
1518 
1519  datasetOptions.insert( QStringLiteral( "PRESERVE_EMPTY_NUMBERS" ), new QgsVectorFileWriter::BoolOption(
1520  QObject::tr( "If enabled, numeric attributes assigned an empty string as a value will "
1521  "be preserved as a special numeric value. This option should not generally "
1522  "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1523  false // Default value
1524  ) );
1525 
1526  datasetOptions.insert( QStringLiteral( "LNAM_REFS" ), new QgsVectorFileWriter::BoolOption(
1527  QObject::tr( "Should LNAM and LNAM_REFS fields be attached to features capturing "
1528  "the feature to feature relationships in the FFPT group of the S-57 file." ),
1529  true // Default value
1530  ) );
1531 
1532  datasetOptions.insert( QStringLiteral( "RETURN_LINKAGES" ), new QgsVectorFileWriter::BoolOption(
1533  QObject::tr( "Should additional attributes relating features to their underlying "
1534  "geometric primitives be attached. These are the values of the FSPT group, "
1535  "and are primarily needed when doing S-57 to S-57 translations." ),
1536  false // Default value
1537  ) );
1538 
1539  datasetOptions.insert( QStringLiteral( "RECODE_BY_DSSI" ), new QgsVectorFileWriter::BoolOption(
1540  QObject::tr( "Should attribute values be recoded to UTF-8 from the character encoding "
1541  "specified in the S57 DSSI record." ),
1542  false // Default value
1543  ) );
1544 
1545  // set OGR_S57_OPTIONS = "RETURN_PRIMITIVES=ON,RETURN_LINKAGES=ON,LNAM_REFS=ON"
1546 
1547  driverMetadata.insert( QStringLiteral( "S57" ),
1549  QStringLiteral( "S-57 Base file" ),
1550  QObject::tr( "S-57 Base file" ),
1551  QStringLiteral( "*.000" ),
1552  QStringLiteral( "000" ),
1553  datasetOptions,
1554  layerOptions
1555  )
1556  );
1557 
1558  // Spatial Data Transfer Standard [SDTS]
1559  datasetOptions.clear();
1560  layerOptions.clear();
1561 
1562  driverMetadata.insert( QStringLiteral( "SDTS" ),
1564  QStringLiteral( "Spatial Data Transfer Standard [SDTS]" ),
1565  QObject::tr( "Spatial Data Transfer Standard [SDTS]" ),
1566  QStringLiteral( "*catd.ddf" ),
1567  QStringLiteral( "ddf" ),
1568  datasetOptions,
1569  layerOptions
1570  )
1571  );
1572 
1573  // SQLite
1574  datasetOptions.clear();
1575  layerOptions.clear();
1576 
1577  datasetOptions.insert( QStringLiteral( "METADATA" ), new QgsVectorFileWriter::BoolOption(
1578  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1579  "tables in a new database. By default these metadata tables are created "
1580  "when a new database is created." ),
1581  true // Default value
1582  ) );
1583 
1584  // Will handle the SpatiaLite alias
1585  datasetOptions.insert( QStringLiteral( "SPATIALITE" ), new QgsVectorFileWriter::HiddenOption(
1586  QStringLiteral( "NO" )
1587  ) );
1588 
1589 
1590  datasetOptions.insert( QStringLiteral( "INIT_WITH_EPSG" ), new QgsVectorFileWriter::HiddenOption(
1591  QStringLiteral( "NO" )
1592  ) );
1593 
1594  layerOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
1595  QObject::tr( "Controls the format used for the geometry column. Defaults to WKB. "
1596  "This is generally more space and processing efficient, but harder "
1597  "to inspect or use in simple applications than WKT (Well Known Text)." ),
1598  QStringList()
1599  << QStringLiteral( "WKB" )
1600  << QStringLiteral( "WKT" ),
1601  QStringLiteral( "WKB" ) // Default value
1602  ) );
1603 
1604  layerOptions.insert( QStringLiteral( "LAUNDER" ), new QgsVectorFileWriter::BoolOption(
1605  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1606  "in SQLite. Laundered names will be converted to lower case and some special "
1607  "characters(' - #) will be changed to underscores." ),
1608  true // Default value
1609  ) );
1610 
1611  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::HiddenOption(
1612  QStringLiteral( "NO" )
1613  ) );
1614 
1615  layerOptions.insert( QStringLiteral( "COMPRESS_GEOM" ), new QgsVectorFileWriter::HiddenOption(
1616  QStringLiteral( "NO" )
1617  ) );
1618 
1619  layerOptions.insert( QStringLiteral( "SRID" ), new QgsVectorFileWriter::HiddenOption(
1620  QLatin1String( "" )
1621  ) );
1622 
1623  layerOptions.insert( QStringLiteral( "COMPRESS_COLUMNS" ), new QgsVectorFileWriter::StringOption(
1624  QObject::tr( "column_name1[,column_name2, ...] A list of (String) columns that "
1625  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1626  "for databases that have big string blobs. However, use with care, since "
1627  "the value of such columns will be seen as compressed binary content with "
1628  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1629  "modifying or querying compressed columns, compression/decompression is "
1630  "done transparently. However, such columns cannot be (easily) queried with "
1631  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1632  "have the 'VARCHAR_deflate' declaration type." ),
1633  QLatin1String( "" ) // Default value
1634  ) );
1635 
1636  driverMetadata.insert( QStringLiteral( "SQLite" ),
1638  QStringLiteral( "SQLite" ),
1639  QObject::tr( "SQLite" ),
1640  QStringLiteral( "*.sqlite" ),
1641  QStringLiteral( "sqlite" ),
1642  datasetOptions,
1643  layerOptions,
1644  QStringLiteral( "UTF-8" )
1645  )
1646  );
1647 
1648  // SpatiaLite
1649  datasetOptions.clear();
1650  layerOptions.clear();
1651 
1652  datasetOptions.insert( QStringLiteral( "METADATA" ), new QgsVectorFileWriter::BoolOption(
1653  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1654  "tables in a new database. By default these metadata tables are created "
1655  "when a new database is created." ),
1656  true // Default value
1657  ) );
1658 
1659  datasetOptions.insert( QStringLiteral( "SPATIALITE" ), new QgsVectorFileWriter::HiddenOption(
1660  QStringLiteral( "YES" )
1661  ) );
1662 
1663  datasetOptions.insert( QStringLiteral( "INIT_WITH_EPSG" ), new QgsVectorFileWriter::BoolOption(
1664  QObject::tr( "Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
1665  "Set to NO for regular SQLite databases." ),
1666  true // Default value
1667  ) );
1668 
1669  layerOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::HiddenOption(
1670  QStringLiteral( "SPATIALITE" )
1671  ) );
1672 
1673  layerOptions.insert( QStringLiteral( "LAUNDER" ), new QgsVectorFileWriter::BoolOption(
1674  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1675  "in SQLite. Laundered names will be converted to lower case and some special "
1676  "characters(' - #) will be changed to underscores." ),
1677  true // Default value
1678  ) );
1679 
1680  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::BoolOption(
1681  QObject::tr( "If the database is of the SpatiaLite flavor, and if OGR is linked "
1682  "against libspatialite, this option can be used to control if a spatial "
1683  "index must be created." ),
1684  true // Default value
1685  ) );
1686 
1687  layerOptions.insert( QStringLiteral( "COMPRESS_GEOM" ), new QgsVectorFileWriter::BoolOption(
1688  QObject::tr( "If the format of the geometry BLOB is of the SpatiaLite flavor, "
1689  "this option can be used to control if the compressed format for "
1690  "geometries (LINESTRINGs, POLYGONs) must be used." ),
1691  false // Default value
1692  ) );
1693 
1694  layerOptions.insert( QStringLiteral( "SRID" ), new QgsVectorFileWriter::StringOption(
1695  QObject::tr( "Used to force the SRID number of the SRS associated with the layer. "
1696  "When this option isn't specified and that a SRS is associated with the "
1697  "layer, a search is made in the spatial_ref_sys to find a match for the "
1698  "SRS, and, if there is no match, a new entry is inserted for the SRS in "
1699  "the spatial_ref_sys table. When the SRID option is specified, this "
1700  "search (and the eventual insertion of a new entry) will not be done: "
1701  "the specified SRID is used as such." ),
1702  QLatin1String( "" ) // Default value
1703  ) );
1704 
1705  layerOptions.insert( QStringLiteral( "COMPRESS_COLUMNS" ), new QgsVectorFileWriter::StringOption(
1706  QObject::tr( "column_name1[,column_name2, ...] A list of (String) columns that "
1707  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1708  "for databases that have big string blobs. However, use with care, since "
1709  "the value of such columns will be seen as compressed binary content with "
1710  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1711  "modifying or queryings compressed columns, compression/decompression is "
1712  "done transparently. However, such columns cannot be (easily) queried with "
1713  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1714  "have the 'VARCHAR_deflate' declaration type." ),
1715  QLatin1String( "" ) // Default value
1716  ) );
1717 
1718  driverMetadata.insert( QStringLiteral( "SpatiaLite" ),
1720  QStringLiteral( "SpatiaLite" ),
1721  QObject::tr( "SpatiaLite" ),
1722  QStringLiteral( "*.sqlite" ),
1723  QStringLiteral( "sqlite" ),
1724  datasetOptions,
1725  layerOptions,
1726  QStringLiteral( "UTF-8" )
1727  )
1728  );
1729  // AutoCAD DXF
1730  datasetOptions.clear();
1731  layerOptions.clear();
1732 
1733  datasetOptions.insert( QStringLiteral( "HEADER" ), new QgsVectorFileWriter::StringOption(
1734  QObject::tr( "Override the header file used - in place of header.dxf." ),
1735  QLatin1String( "" ) // Default value
1736  ) );
1737 
1738  datasetOptions.insert( QStringLiteral( "TRAILER" ), new QgsVectorFileWriter::StringOption(
1739  QObject::tr( "Override the trailer file used - in place of trailer.dxf." ),
1740  QLatin1String( "" ) // Default value
1741  ) );
1742 
1743  driverMetadata.insert( QStringLiteral( "DXF" ),
1745  QStringLiteral( "AutoCAD DXF" ),
1746  QObject::tr( "AutoCAD DXF" ),
1747  QStringLiteral( "*.dxf" ),
1748  QStringLiteral( "dxf" ),
1749  datasetOptions,
1750  layerOptions
1751  )
1752  );
1753 
1754  // Geoconcept
1755  datasetOptions.clear();
1756  layerOptions.clear();
1757 
1758  datasetOptions.insert( QStringLiteral( "EXTENSION" ), new QgsVectorFileWriter::SetOption(
1759  QObject::tr( "Indicates the GeoConcept export file extension. "
1760  "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
1761  QStringList()
1762  << QStringLiteral( "GXT" )
1763  << QStringLiteral( "TXT" ),
1764  QStringLiteral( "GXT" ) // Default value
1765  ) );
1766 
1767  datasetOptions.insert( QStringLiteral( "CONFIG" ), new QgsVectorFileWriter::StringOption(
1768  QObject::tr( "Path to the GCT: the GCT file describes the GeoConcept types definitions: "
1769  "In this file, every line must start with //# followed by a keyword. "
1770  "Lines starting with // are comments." ),
1771  QLatin1String( "" ) // Default value
1772  ) );
1773 
1774  datasetOptions.insert( QStringLiteral( "FEATURETYPE" ), new QgsVectorFileWriter::StringOption(
1775  QObject::tr( "Defines the feature to be created. The TYPE corresponds to one of the Name "
1776  "found in the GCT file for a type section. The SUBTYPE corresponds to one of "
1777  "the Name found in the GCT file for a sub-type section within the previous "
1778  "type section." ),
1779  QLatin1String( "" ) // Default value
1780  ) );
1781 
1782  driverMetadata.insert( QStringLiteral( "Geoconcept" ),
1784  QStringLiteral( "Geoconcept" ),
1785  QObject::tr( "Geoconcept" ),
1786  QStringLiteral( "*.gxt *.txt" ),
1787  QStringLiteral( "gxt" ),
1788  datasetOptions,
1789  layerOptions
1790  )
1791  );
1792 
1793  // ESRI FileGDB
1794  datasetOptions.clear();
1795  layerOptions.clear();
1796 
1797  layerOptions.insert( QStringLiteral( "FEATURE_DATASET" ), new QgsVectorFileWriter::StringOption(
1798  QObject::tr( "When this option is set, the new layer will be created inside the named "
1799  "FeatureDataset folder. If the folder does not already exist, it will be created." ),
1800  QLatin1String( "" ) // Default value
1801  ) );
1802 
1803  layerOptions.insert( QStringLiteral( "GEOMETRY_NAME" ), new QgsVectorFileWriter::StringOption(
1804  QObject::tr( "Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
1805  QStringLiteral( "SHAPE" ) // Default value
1806  ) );
1807 
1808  layerOptions.insert( QStringLiteral( "FID" ), new QgsVectorFileWriter::StringOption(
1809  QObject::tr( "Name of the OID column to create. Defaults to 'OBJECTID'." ),
1810  QStringLiteral( "OBJECTID" ) // Default value
1811  ) );
1812 
1813  driverMetadata.insert( QStringLiteral( "FileGDB" ),
1815  QStringLiteral( "ESRI FileGDB" ),
1816  QObject::tr( "ESRI FileGDB" ),
1817  QStringLiteral( "*.gdb" ),
1818  QStringLiteral( "gdb" ),
1819  datasetOptions,
1820  layerOptions,
1821  QStringLiteral( "UTF-8" )
1822  )
1823  );
1824 
1825  // XLSX
1826  datasetOptions.clear();
1827  layerOptions.clear();
1828 
1829  layerOptions.insert( QStringLiteral( "OGR_XLSX_FIELD_TYPES" ), new QgsVectorFileWriter::SetOption(
1830  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
1831  "to STRING, all fields will be of String type." ),
1832  QStringList()
1833  << QStringLiteral( "AUTO" )
1834  << QStringLiteral( "STRING" ),
1835  QStringLiteral( "AUTO" ), // Default value
1836  false // Allow None
1837  ) );
1838 
1839  layerOptions.insert( QStringLiteral( "OGR_XLSX_HEADERS" ), new QgsVectorFileWriter::SetOption(
1840  QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
1841  "if the first line might be the name of columns. If set to FORCE, the driver "
1842  "will consider the first line as the header line. If set to "
1843  "DISABLE, it will be considered as the first feature. Otherwise "
1844  "auto-detection will occur." ),
1845  QStringList()
1846  << QStringLiteral( "FORCE" )
1847  << QStringLiteral( "DISABLE" )
1848  << QStringLiteral( "AUTO" ),
1849  QStringLiteral( "AUTO" ), // Default value
1850  false // Allow None
1851  ) );
1852 
1853  driverMetadata.insert( QStringLiteral( "XLSX" ),
1855  QStringLiteral( "MS Office Open XML spreadsheet" ),
1856  QObject::tr( "MS Office Open XML spreadsheet [XLSX]" ),
1857  QStringLiteral( "*.xlsx" ),
1858  QStringLiteral( "xlsx" ),
1859  datasetOptions,
1860  layerOptions,
1861  QStringLiteral( "UTF-8" )
1862  )
1863  );
1864 
1865  // ODS
1866  datasetOptions.clear();
1867  layerOptions.clear();
1868 
1869  layerOptions.insert( QStringLiteral( "OGR_ODS_FIELD_TYPES" ), new QgsVectorFileWriter::SetOption(
1870  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
1871  "to STRING, all fields will be of String type." ),
1872  QStringList()
1873  << QStringLiteral( "AUTO" )
1874  << QStringLiteral( "STRING" ),
1875  QStringLiteral( "AUTO" ), // Default value
1876  false // Allow None
1877  ) );
1878 
1879  layerOptions.insert( QStringLiteral( "OGR_ODS_HEADERS" ), new QgsVectorFileWriter::SetOption(
1880  QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
1881  "if the first line might be the name of columns. If set to FORCE, the driver "
1882  "will consider the first line as the header line. If set to "
1883  "DISABLE, it will be considered as the first feature. Otherwise "
1884  "auto-detection will occur." ),
1885  QStringList()
1886  << QStringLiteral( "FORCE" )
1887  << QStringLiteral( "DISABLE" )
1888  << QStringLiteral( "AUTO" ),
1889  QStringLiteral( "AUTO" ), // Default value
1890  false // Allow None
1891  ) );
1892 
1893  driverMetadata.insert( QStringLiteral( "ODS" ),
1895  QStringLiteral( "Open Document Spreadsheet" ),
1896  QObject::tr( "Open Document Spreadsheet [ODS]" ),
1897  QStringLiteral( "*.ods" ),
1898  QStringLiteral( "ods" ),
1899  datasetOptions,
1900  layerOptions,
1901  QStringLiteral( "UTF-8" )
1902  )
1903  );
1904  }
1905 
1906  QgsVectorFileWriterMetadataContainer( const QgsVectorFileWriterMetadataContainer &other ) = delete;
1907  QgsVectorFileWriterMetadataContainer &operator=( const QgsVectorFileWriterMetadataContainer &other ) = delete;
1908  ~QgsVectorFileWriterMetadataContainer()
1909  {
1910  for ( auto it = driverMetadata.constBegin(); it != driverMetadata.constEnd(); ++it )
1911  {
1912  for ( auto optionIt = it.value().driverOptions.constBegin(); optionIt != it.value().driverOptions.constEnd(); ++optionIt )
1913  delete optionIt.value();
1914  for ( auto optionIt = it.value().layerOptions.constBegin(); optionIt != it.value().layerOptions.constEnd(); ++optionIt )
1915  delete optionIt.value();
1916  }
1917  }
1918 
1919  QMap<QString, QgsVectorFileWriter::MetaData> driverMetadata;
1920 
1921 };
1923 
1925 {
1926  static QgsVectorFileWriterMetadataContainer sDriverMetadata;
1927  QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.driverMetadata.constBegin();
1928 
1929  for ( ; it != sDriverMetadata.driverMetadata.constEnd(); ++it )
1930  {
1931  if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
1932  {
1933  driverMetadata = it.value();
1934  return true;
1935  }
1936  }
1937 
1938  return false;
1939 }
1940 
1941 QStringList QgsVectorFileWriter::defaultDatasetOptions( const QString &driverName )
1942 {
1943  MetaData metadata;
1944  bool ok = driverMetadata( driverName, metadata );
1945  if ( !ok )
1946  return QStringList();
1947  return concatenateOptions( metadata.driverOptions );
1948 }
1949 
1950 QStringList QgsVectorFileWriter::defaultLayerOptions( const QString &driverName )
1951 {
1952  MetaData metadata;
1953  bool ok = driverMetadata( driverName, metadata );
1954  if ( !ok )
1955  return QStringList();
1956  return concatenateOptions( metadata.layerOptions );
1957 }
1958 
1960 {
1961 
1962  OGRwkbGeometryType ogrType = static_cast<OGRwkbGeometryType>( type );
1963 
1964  if ( type >= QgsWkbTypes::PointZ && type <= QgsWkbTypes::GeometryCollectionZ )
1965  {
1966  ogrType = static_cast<OGRwkbGeometryType>( QgsWkbTypes::to25D( type ) );
1967  }
1968  return ogrType;
1969 }
1970 
1972 {
1973  return mError;
1974 }
1975 
1977 {
1978  return mErrorMessage;
1979 }
1980 
1981 bool QgsVectorFileWriter::addFeature( QgsFeature &feature, QgsFeatureSink::Flags )
1982 {
1983  return addFeatureWithStyle( feature, nullptr, QgsUnitTypes::DistanceMeters );
1984 }
1985 
1986 bool QgsVectorFileWriter::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags )
1987 {
1988  QgsFeatureList::iterator fIt = features.begin();
1989  bool result = true;
1990  for ( ; fIt != features.end(); ++fIt )
1991  {
1992  result = result && addFeatureWithStyle( *fIt, nullptr, QgsUnitTypes::DistanceMeters );
1993  }
1994  return result;
1995 }
1996 
1998 {
1999  // create the feature
2000  gdal::ogr_feature_unique_ptr poFeature = createFeature( feature );
2001  if ( !poFeature )
2002  return false;
2003 
2004  //add OGR feature style type
2005  if ( mSymbologyExport != NoSymbology && renderer )
2006  {
2007  mRenderContext.expressionContext().setFeature( feature );
2008  //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
2009  QgsSymbolList symbols = renderer->symbolsForFeature( feature, mRenderContext );
2010  QString styleString;
2011  QString currentStyle;
2012 
2013  QgsSymbolList::const_iterator symbolIt = symbols.constBegin();
2014  for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
2015  {
2016  int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
2017  for ( int i = 0; i < nSymbolLayers; ++i )
2018  {
2019 #if 0
2020  QMap< QgsSymbolLayer *, QString >::const_iterator it = mSymbolLayerTable.find( ( *symbolIt )->symbolLayer( i ) );
2021  if ( it == mSymbolLayerTable.constEnd() )
2022  {
2023  continue;
2024  }
2025 #endif
2026  double mmsf = mmScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2027  double musf = mapUnitScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2028 
2029  currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
2030 
2032  {
2033  if ( symbolIt != symbols.constBegin() || i != 0 )
2034  {
2035  styleString.append( ';' );
2036  }
2037  styleString.append( currentStyle );
2038  }
2039  else if ( mSymbologyExport == SymbolLayerSymbology )
2040  {
2041  OGR_F_SetStyleString( poFeature.get(), currentStyle.toLocal8Bit().constData() );
2042  if ( !writeFeature( mLayer, poFeature.get() ) )
2043  {
2044  return false;
2045  }
2046  }
2047  }
2048  }
2049  OGR_F_SetStyleString( poFeature.get(), styleString.toLocal8Bit().constData() );
2050  }
2051 
2053  {
2054  if ( !writeFeature( mLayer, poFeature.get() ) )
2055  {
2056  return false;
2057  }
2058  }
2059 
2060  return true;
2061 }
2062 
2063 gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeature &feature )
2064 {
2065  QgsLocaleNumC l; // Make sure the decimal delimiter is a dot
2066  Q_UNUSED( l );
2067 
2068  gdal::ogr_feature_unique_ptr poFeature( OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) ) );
2069 
2070  qint64 fid = FID_TO_NUMBER( feature.id() );
2071  if ( fid > std::numeric_limits<int>::max() )
2072  {
2073  QgsDebugMsg( QString( "feature id %1 too large." ).arg( fid ) );
2074  OGRErr err = OGR_F_SetFID( poFeature.get(), static_cast<long>( fid ) );
2075  if ( err != OGRERR_NONE )
2076  {
2077  QgsDebugMsg( QString( "Failed to set feature id to %1: %2 (OGR error: %3)" )
2078  .arg( feature.id() )
2079  .arg( err ).arg( CPLGetLastErrorMsg() )
2080  );
2081  }
2082  }
2083 
2084  // attribute handling
2085  for ( QMap<int, int>::const_iterator it = mAttrIdxToOgrIdx.constBegin(); it != mAttrIdxToOgrIdx.constEnd(); ++it )
2086  {
2087  int fldIdx = it.key();
2088  int ogrField = it.value();
2089 
2090  QVariant attrValue = feature.attribute( fldIdx );
2091 
2092  if ( !attrValue.isValid() || attrValue.isNull() )
2093  {
2094 // Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
2095 // whereas previously there was only unset fields. For a GeoJSON output,
2096 // leaving a field unset will cause it to not appear at all in the output
2097 // feature.
2098 // When all features of a layer have a field unset, this would cause the
2099 // field to not be present at all in the output, and thus on reading to
2100 // have disappeared. #16812
2101 #ifdef OGRNullMarker
2102  OGR_F_SetFieldNull( poFeature.get(), ogrField );
2103 #endif
2104  continue;
2105  }
2106 
2107  if ( mFieldValueConverter )
2108  {
2109  attrValue = mFieldValueConverter->convert( fldIdx, attrValue );
2110  }
2111 
2112  switch ( attrValue.type() )
2113  {
2114  case QVariant::Int:
2115  case QVariant::UInt:
2116  OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2117  break;
2118  case QVariant::LongLong:
2119  case QVariant::ULongLong:
2120  OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
2121  break;
2122  case QVariant::Bool:
2123  OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2124  break;
2125  case QVariant::String:
2126  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toString() ).constData() );
2127  break;
2128  case QVariant::Double:
2129  OGR_F_SetFieldDouble( poFeature.get(), ogrField, attrValue.toDouble() );
2130  break;
2131  case QVariant::Date:
2132  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2133  attrValue.toDate().year(),
2134  attrValue.toDate().month(),
2135  attrValue.toDate().day(),
2136  0, 0, 0, 0 );
2137  break;
2138  case QVariant::DateTime:
2139  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
2140  {
2141  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toDateTime().toString( QStringLiteral( "yyyy/MM/dd hh:mm:ss.zzz" ) ) ).constData() );
2142  }
2143  else
2144  {
2145  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2146  attrValue.toDateTime().date().year(),
2147  attrValue.toDateTime().date().month(),
2148  attrValue.toDateTime().date().day(),
2149  attrValue.toDateTime().time().hour(),
2150  attrValue.toDateTime().time().minute(),
2151  attrValue.toDateTime().time().second(),
2152  0 );
2153  }
2154  break;
2155  case QVariant::Time:
2156  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
2157  {
2158  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toString() ).constData() );
2159  }
2160  else
2161  {
2162  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2163  0, 0, 0,
2164  attrValue.toTime().hour(),
2165  attrValue.toTime().minute(),
2166  attrValue.toTime().second(),
2167  0 );
2168  }
2169  break;
2170  case QVariant::Invalid:
2171  break;
2172  default:
2173  mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
2174  .arg( mFields.at( fldIdx ).name() )
2175  .arg( ogrField )
2176  .arg( attrValue.typeName(),
2177  attrValue.toString() );
2178  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2180  return nullptr;
2181  }
2182  }
2183 
2185  {
2186  if ( feature.hasGeometry() )
2187  {
2188  // build geometry from WKB
2189  QgsGeometry geom = feature.geometry();
2190 
2191  // turn single geometry to multi geometry if needed
2194  {
2195  geom.convertToMultiType();
2196  }
2197 
2198  if ( geom.wkbType() != mWkbType )
2199  {
2200  OGRGeometryH mGeom2 = nullptr;
2201 
2202  // If requested WKB type is 25D and geometry WKB type is 3D,
2203  // we must force the use of 25D.
2205  {
2206  //ND: I suspect there's a bug here, in that this is NOT converting the geometry's WKB type,
2207  //so the exported WKB has a different type to what the OGRGeometry is expecting.
2208  //possibly this is handled already in OGR, but it should be fixed regardless by actually converting
2209  //geom to the correct WKB type
2210  QgsWkbTypes::Type wkbType = geom.wkbType();
2211  if ( wkbType >= QgsWkbTypes::PointZ && wkbType <= QgsWkbTypes::MultiPolygonZ )
2212  {
2214  mGeom2 = createEmptyGeometry( wkbType25d );
2215  }
2216  }
2217 
2218  if ( !mGeom2 )
2219  {
2220  // there's a problem when layer type is set as wkbtype Polygon
2221  // although there are also features of type MultiPolygon
2222  // (at least in OGR provider)
2223  // If the feature's wkbtype is different from the layer's wkbtype,
2224  // try to export it too.
2225  //
2226  // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
2227  // i.e. Polygons can't be imported to OGRMultiPolygon
2228  mGeom2 = createEmptyGeometry( geom.wkbType() );
2229  }
2230 
2231  if ( !mGeom2 )
2232  {
2233  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2234  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2236  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2237  return nullptr;
2238  }
2239 
2240  QByteArray wkb( geom.asWkb() );
2241  OGRErr err = OGR_G_ImportFromWkb( mGeom2, reinterpret_cast<unsigned char *>( const_cast<char *>( wkb.constData() ) ), wkb.length() );
2242  if ( err != OGRERR_NONE )
2243  {
2244  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2245  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2247  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2248  return nullptr;
2249  }
2250 
2251  // pass ownership to geometry
2252  OGR_F_SetGeometryDirectly( poFeature.get(), mGeom2 );
2253  }
2254  else // wkb type matches
2255  {
2256  QByteArray wkb( geom.asWkb() );
2257  OGRGeometryH ogrGeom = createEmptyGeometry( mWkbType );
2258  OGRErr err = OGR_G_ImportFromWkb( ogrGeom, reinterpret_cast<unsigned char *>( const_cast<char *>( wkb.constData() ) ), wkb.length() );
2259  if ( err != OGRERR_NONE )
2260  {
2261  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2262  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2264  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2265  return nullptr;
2266  }
2267 
2268  // set geometry (ownership is passed to OGR)
2269  OGR_F_SetGeometryDirectly( poFeature.get(), ogrGeom );
2270  }
2271  }
2272  else
2273  {
2274  OGR_F_SetGeometryDirectly( poFeature.get(), createEmptyGeometry( mWkbType ) );
2275  }
2276  }
2277  return poFeature;
2278 }
2279 
2280 void QgsVectorFileWriter::resetMap( const QgsAttributeList &attributes )
2281 {
2282  QMap<int, int> omap( mAttrIdxToOgrIdx );
2283  mAttrIdxToOgrIdx.clear();
2284  for ( int i = 0; i < attributes.size(); i++ )
2285  {
2286  if ( omap.find( i ) != omap.end() )
2287  mAttrIdxToOgrIdx.insert( attributes[i], omap[i] );
2288  }
2289 }
2290 
2291 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
2292 {
2293  if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
2294  {
2295  mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2297  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2298  return false;
2299  }
2300  return true;
2301 }
2302 
2304 {
2305  if ( mUsingTransaction )
2306  {
2307  if ( OGRERR_NONE != OGR_L_CommitTransaction( mLayer ) )
2308  {
2309  QgsDebugMsg( "Error while committing transaction on OGRLayer." );
2310  }
2311  }
2312 
2313  mDS.reset();
2314 
2315  if ( mOgrRef )
2316  {
2317  OSRDestroySpatialReference( mOgrRef );
2318  }
2319 }
2320 
2323  const QString &fileName,
2324  const QString &fileEncoding,
2325  const QgsCoordinateReferenceSystem &destCRS,
2326  const QString &driverName,
2327  bool onlySelected,
2328  QString *errorMessage,
2329  const QStringList &datasourceOptions,
2330  const QStringList &layerOptions,
2331  bool skipAttributeCreation,
2332  QString *newFilename,
2334  double symbologyScale,
2335  const QgsRectangle *filterExtent,
2336  QgsWkbTypes::Type overrideGeometryType,
2337  bool forceMulti,
2338  bool includeZ,
2339  const QgsAttributeList &attributes,
2340  FieldValueConverter *fieldValueConverter )
2341 {
2343  if ( destCRS.isValid() && layer )
2344  {
2346  ct = QgsCoordinateTransform( layer->crs(), destCRS );
2348  }
2349 
2350  QgsVectorFileWriter::WriterError error = writeAsVectorFormat( layer, fileName, fileEncoding, ct, driverName, onlySelected,
2351  errorMessage, datasourceOptions, layerOptions, skipAttributeCreation,
2352  newFilename, symbologyExport, symbologyScale, filterExtent,
2353  overrideGeometryType, forceMulti, includeZ, attributes,
2354  fieldValueConverter );
2355  return error;
2356 }
2357 
2359  const QString &fileName,
2360  const QString &fileEncoding,
2361  const QgsCoordinateTransform &ct,
2362  const QString &driverName,
2363  bool onlySelected,
2364  QString *errorMessage,
2365  const QStringList &datasourceOptions,
2366  const QStringList &layerOptions,
2367  bool skipAttributeCreation,
2368  QString *newFilename,
2370  double symbologyScale,
2371  const QgsRectangle *filterExtent,
2372  QgsWkbTypes::Type overrideGeometryType,
2373  bool forceMulti,
2374  bool includeZ,
2375  const QgsAttributeList &attributes,
2376  FieldValueConverter *fieldValueConverter )
2377 {
2378  SaveVectorOptions options;
2379  options.fileEncoding = fileEncoding;
2380  options.ct = ct;
2381  options.driverName = driverName;
2382  options.onlySelectedFeatures = onlySelected;
2383  options.datasourceOptions = datasourceOptions;
2384  options.layerOptions = layerOptions;
2385  options.skipAttributeCreation = skipAttributeCreation;
2386  options.symbologyExport = symbologyExport;
2387  options.symbologyScale = symbologyScale;
2388  if ( filterExtent )
2389  options.filterExtent = *filterExtent;
2390  options.overrideGeometryType = overrideGeometryType;
2391  options.forceMulti = forceMulti;
2392  options.includeZ = includeZ;
2393  options.attributes = attributes;
2394  options.fieldValueConverter = fieldValueConverter;
2395  return writeAsVectorFormat( layer, fileName, options, newFilename, errorMessage );
2396 }
2397 
2398 
2400  : driverName( QStringLiteral( "GPKG" ) )
2401 {
2402 }
2403 
2404 
2405 
2406 QgsVectorFileWriter::WriterError QgsVectorFileWriter::prepareWriteAsVectorFormat( QgsVectorLayer *layer, const QgsVectorFileWriter::SaveVectorOptions &options, QgsVectorFileWriter::PreparedWriterDetails &details )
2407 {
2408  if ( !layer )
2409  {
2410  return ErrInvalidLayer;
2411  }
2412 
2413 
2414  if ( layer->renderer() )
2415  details.renderer.reset( layer->renderer()->clone() );
2416  details.sourceCrs = layer->crs();
2417  details.sourceWkbType = layer->wkbType();
2418  details.sourceFields = layer->fields();
2419  details.providerType = layer->providerType();
2420  details.featureCount = options.onlySelectedFeatures ? layer->selectedFeatureCount() : layer->featureCount();
2421  if ( layer->dataProvider() )
2422  details.dataSourceUri = layer->dataProvider()->dataSourceUri();
2423  details.storageType = layer->storageType();
2424  details.selectedFeatureIds = layer->selectedFeatureIds();
2425 
2426  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) )
2427  {
2428  QgsFeatureRequest req;
2429  if ( options.onlySelectedFeatures )
2430  {
2431  req.setFilterFids( details.selectedFeatureIds );
2432  }
2434  details.geometryTypeScanIterator = layer->getFeatures( req );
2435  }
2436 
2437  details.expressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
2438  details.renderContext.setExpressionContext( details.expressionContext );
2439  details.renderContext.setRendererScale( options.symbologyScale );
2440 
2441  details.shallTransform = false;
2442  if ( options.ct.isValid() )
2443  {
2444  // This means we should transform
2445  details.outputCrs = options.ct.destinationCrs();
2446  details.shallTransform = true;
2447  }
2448  else
2449  {
2450  // This means we shouldn't transform, use source CRS as output (if defined)
2451  details.outputCrs = details.sourceCrs;
2452  }
2453 
2454  details.destWkbType = details.sourceWkbType;
2455  if ( options.overrideGeometryType != QgsWkbTypes::Unknown )
2456  {
2457  details.destWkbType = QgsWkbTypes::flatType( options.overrideGeometryType );
2458  if ( QgsWkbTypes::hasZ( options.overrideGeometryType ) || options.includeZ )
2459  details.destWkbType = QgsWkbTypes::addZ( details.destWkbType );
2460  }
2461  if ( options.forceMulti )
2462  {
2463  details.destWkbType = QgsWkbTypes::multiType( details.destWkbType );
2464  }
2465 
2466  details.attributes = options.attributes;
2467  if ( options.skipAttributeCreation )
2468  details.attributes.clear();
2469  else if ( details.attributes.isEmpty() )
2470  {
2471  const QgsAttributeList allAttributes = details.sourceFields.allAttributesList();
2472  for ( int idx : allAttributes )
2473  {
2474  QgsField fld = details.sourceFields.at( idx );
2475  if ( details.providerType == QLatin1String( "oracle" ) && fld.typeName().contains( QLatin1String( "SDO_GEOMETRY" ) ) )
2476  continue;
2477  details.attributes.append( idx );
2478  }
2479  }
2480 
2481  if ( !details.attributes.isEmpty() )
2482  {
2483  for ( int attrIdx : qgis::as_const( details.attributes ) )
2484  {
2485  details.outputFields.append( details.sourceFields.at( attrIdx ) );
2486  }
2487  }
2488 
2489  // not ideal - would be nice to avoid this happening in the preparation step if possible,
2490  // but currently requires access to the layer's minimumValue/maximumValue methods
2491  if ( details.providerType == QLatin1String( "spatialite" ) )
2492  {
2493  for ( int i = 0; i < details.outputFields.size(); i++ )
2494  {
2495  if ( details.outputFields.at( i ).type() == QVariant::LongLong )
2496  {
2497  QVariant min = layer->minimumValue( i );
2498  QVariant max = layer->maximumValue( i );
2499  if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < std::numeric_limits<int>::max() )
2500  {
2501  details.outputFields[i].setType( QVariant::Int );
2502  }
2503  }
2504  }
2505  }
2506 
2507 
2508  //add possible attributes needed by renderer
2509  addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
2510 
2511  QgsFeatureRequest req;
2512  req.setSubsetOfAttributes( details.attributes );
2513  if ( options.onlySelectedFeatures )
2514  req.setFilterFids( details.selectedFeatureIds );
2515 
2516  if ( !options.filterExtent.isNull() )
2517  {
2518  QgsRectangle filterRect = options.filterExtent;
2519  bool useFilterRect = true;
2520  if ( details.shallTransform )
2521  {
2522  try
2523  {
2524  // map filter rect back from destination CRS to layer CRS
2525  filterRect = options.ct.transformBoundingBox( filterRect, QgsCoordinateTransform::ReverseTransform );
2526  }
2527  catch ( QgsCsException & )
2528  {
2529  useFilterRect = false;
2530  }
2531  }
2532  if ( useFilterRect )
2533  {
2534  req.setFilterRect( filterRect );
2535  }
2536  details.filterRectGeometry = QgsGeometry::fromRect( options.filterExtent );
2537  details.filterRectEngine.reset( QgsGeometry::createGeometryEngine( details.filterRectGeometry.constGet() ) );
2538  details.filterRectEngine->prepareGeometry();
2539  }
2540  details.sourceFeatureIterator = layer->getFeatures( req );
2541 
2542  return NoError;
2543 }
2544 
2545 QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( PreparedWriterDetails &details, const QString &fileName, const QgsVectorFileWriter::SaveVectorOptions &options, QString *newFilename, QString *errorMessage )
2546 {
2547 
2548  QgsWkbTypes::Type destWkbType = details.destWkbType;
2549 
2550  int lastProgressReport = 0;
2551  long total = details.featureCount;
2552 
2553  if ( details.providerType == QLatin1String( "ogr" ) && !details.dataSourceUri.isEmpty() )
2554  {
2555  QStringList theURIParts = details.dataSourceUri.split( '|' );
2556  QString srcFileName = theURIParts[0];
2557 
2558  if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2559  {
2560  if ( errorMessage )
2561  *errorMessage = QObject::tr( "Cannot overwrite a OGR layer in place" );
2562  return ErrCreateDataSource;
2563  }
2564 
2565  // Shapefiles might contain multi types although wkbType() only reports singles
2566  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) && !QgsWkbTypes::isMultiType( destWkbType ) )
2567  {
2568  QgsFeatureIterator fit = details.geometryTypeScanIterator;
2569  QgsFeature fet;
2570  long scanned = 0;
2571  while ( fit.nextFeature( fet ) )
2572  {
2573  if ( options.feedback && options.feedback->isCanceled() )
2574  {
2575  return Canceled;
2576  }
2577  if ( options.feedback )
2578  {
2579  //dedicate first 5% of progress bar to this scan
2580  int newProgress = ( 5.0 * scanned ) / total;
2581  if ( newProgress != lastProgressReport )
2582  {
2583  lastProgressReport = newProgress;
2584  options.feedback->setProgress( lastProgressReport );
2585  }
2586  }
2587 
2588  if ( fet.hasGeometry() && QgsWkbTypes::isMultiType( fet.geometry().wkbType() ) )
2589  {
2590  destWkbType = QgsWkbTypes::multiType( destWkbType );
2591  break;
2592  }
2593  scanned++;
2594  }
2595  }
2596  }
2597 
2598  std::unique_ptr< QgsVectorFileWriter > writer =
2599  qgis::make_unique< QgsVectorFileWriter >( fileName,
2600  options.fileEncoding, details.outputFields, destWkbType,
2601  details.outputCrs, options.driverName,
2602  options.datasourceOptions,
2603  options.layerOptions,
2604  newFilename,
2605  options.symbologyExport,
2606  options.fieldValueConverter,
2607  options.layerName,
2608  options.actionOnExistingFile );
2609  writer->setSymbologyScale( options.symbologyScale );
2610 
2611  if ( newFilename )
2612  {
2613  QgsDebugMsg( "newFilename = " + *newFilename );
2614  }
2615 
2616  // check whether file creation was successful
2617  WriterError err = writer->hasError();
2618  if ( err != NoError )
2619  {
2620  if ( errorMessage )
2621  *errorMessage = writer->errorMessage();
2622  return err;
2623  }
2624 
2625  if ( errorMessage )
2626  {
2627  errorMessage->clear();
2628  }
2629 
2630  QgsFeature fet;
2631 
2632  //create symbol table if needed
2633  if ( writer->symbologyExport() != NoSymbology )
2634  {
2635  //writer->createSymbolLayerTable( layer, writer->mDS );
2636  }
2637 
2638  if ( writer->symbologyExport() == SymbolLayerSymbology )
2639  {
2640  QgsFeatureRenderer *r = details.renderer.get();
2642  && r->usingSymbolLevels() )
2643  {
2644  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( details, details.sourceFeatureIterator, options.ct, errorMessage );
2645  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
2646  }
2647  }
2648 
2649  int n = 0, errors = 0;
2650 
2651  //unit type
2652  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
2653  if ( options.ct.isValid() )
2654  {
2655  mapUnits = options.ct.destinationCrs().mapUnits();
2656  }
2657 
2658  writer->startRender( details.renderer.get(), details.sourceFields );
2659 
2660  writer->resetMap( details.attributes );
2661  // Reset mFields to layer fields, and not just exported fields
2662  writer->mFields = details.sourceFields;
2663 
2664  // write all features
2665  long saved = 0;
2666  int initialProgress = lastProgressReport;
2667  while ( details.sourceFeatureIterator.nextFeature( fet ) )
2668  {
2669  if ( options.feedback && options.feedback->isCanceled() )
2670  {
2671  return Canceled;
2672  }
2673 
2674  saved++;
2675  if ( options.feedback )
2676  {
2677  //avoid spamming progress reports
2678  int newProgress = initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total;
2679  if ( newProgress < 100 && newProgress != lastProgressReport )
2680  {
2681  lastProgressReport = newProgress;
2682  options.feedback->setProgress( lastProgressReport );
2683  }
2684  }
2685 
2686  if ( details.shallTransform )
2687  {
2688  try
2689  {
2690  if ( fet.hasGeometry() )
2691  {
2692  QgsGeometry g = fet.geometry();
2693  g.transform( options.ct );
2694  fet.setGeometry( g );
2695  }
2696  }
2697  catch ( QgsCsException &e )
2698  {
2699  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
2700  .arg( fet.id() ).arg( e.what() );
2701  QgsLogger::warning( msg );
2702  if ( errorMessage )
2703  *errorMessage = msg;
2704 
2705  return ErrProjection;
2706  }
2707  }
2708 
2709  if ( fet.hasGeometry() && details.filterRectEngine && !details.filterRectEngine->intersects( fet.geometry().constGet() ) )
2710  continue;
2711 
2712  if ( details.attributes.empty() && options.skipAttributeCreation )
2713  {
2714  fet.initAttributes( 0 );
2715  }
2716 
2717  if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
2718  {
2719  WriterError err = writer->hasError();
2720  if ( err != NoError && errorMessage )
2721  {
2722  if ( errorMessage->isEmpty() )
2723  {
2724  *errorMessage = QObject::tr( "Feature write errors:" );
2725  }
2726  *errorMessage += '\n' + writer->errorMessage();
2727  }
2728  errors++;
2729 
2730  if ( errors > 1000 )
2731  {
2732  if ( errorMessage )
2733  {
2734  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
2735  }
2736 
2737  n = -1;
2738  break;
2739  }
2740  }
2741  n++;
2742  }
2743 
2744  writer->stopRender();
2745 
2746  if ( errors > 0 && errorMessage && n > 0 )
2747  {
2748  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
2749  }
2750 
2751  return errors == 0 ? NoError : ErrFeatureWriteFailed;
2752 }
2753 
2756  const QString &fileName,
2757  const SaveVectorOptions &options,
2758  QString *newFilename,
2759  QString *errorMessage )
2760 {
2761  QgsVectorFileWriter::PreparedWriterDetails details;
2762  WriterError err = prepareWriteAsVectorFormat( layer, options, details );
2763  if ( err != NoError )
2764  return err;
2765 
2766  return writeAsVectorFormat( details, fileName, options, newFilename, errorMessage );
2767 }
2768 
2769 
2770 bool QgsVectorFileWriter::deleteShapeFile( const QString &fileName )
2771 {
2772  QFileInfo fi( fileName );
2773  QDir dir = fi.dir();
2774 
2775  QStringList filter;
2776  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
2777  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
2778  {
2779  filter << fi.completeBaseName() + suffixes[i];
2780  }
2781 
2782  bool ok = true;
2783  Q_FOREACH ( const QString &file, dir.entryList( filter ) )
2784  {
2785  QFile f( dir.canonicalPath() + '/' + file );
2786  if ( !f.remove() )
2787  {
2788  QgsDebugMsg( QString( "Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
2789  ok = false;
2790  }
2791  }
2792 
2793  return ok;
2794 }
2795 
2797 {
2798  mSymbologyScale = d;
2799  mRenderContext.setRendererScale( mSymbologyScale );
2800 }
2801 
2802 QList< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
2803 {
2804  QList< FilterFormatDetails > results;
2805 
2807  int const drvCount = OGRGetDriverCount();
2808 
2809  for ( int i = 0; i < drvCount; ++i )
2810  {
2811  OGRSFDriverH drv = OGRGetDriver( i );
2812  if ( drv )
2813  {
2814  QString drvName = OGR_Dr_GetName( drv );
2815 
2816 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
2817  GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
2818  char **metadata = nullptr;
2819  if ( gdalDriver )
2820  {
2821  metadata = GDALGetMetadata( gdalDriver, nullptr );
2822  }
2823 
2824  bool nonSpatialFormat = CSLFetchBoolean( metadata, GDAL_DCAP_NONSPATIAL, false );
2825 #else
2826  bool nonSpatialFormat = ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) );
2827 #endif
2828 
2829  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2830  {
2831  if ( options & SkipNonSpatialFormats )
2832  {
2833  // skip non-spatial formats
2834  if ( nonSpatialFormat )
2835  continue;
2836  }
2837 
2838  QString filterString = filterForDriver( drvName );
2839  if ( filterString.isEmpty() )
2840  continue;
2841 
2842  MetaData metadata;
2843  QStringList globs;
2844  if ( driverMetadata( drvName, metadata ) && !metadata.glob.isEmpty() )
2845  {
2846  globs = metadata.glob.toLower().split( ' ' );
2847  }
2848 
2849  FilterFormatDetails details;
2850  details.driverName = drvName;
2851  details.filterString = filterString;
2852  details.globs = globs;
2853 
2854  results << details;
2855  }
2856  }
2857  }
2858 
2859  std::sort( results.begin(), results.end(), [options]( const FilterFormatDetails & a, const FilterFormatDetails & b ) -> bool
2860  {
2861  if ( options & SortRecommended )
2862  {
2863  if ( a.driverName == QLatin1String( "GPKG" ) )
2864  return true; // Make https://twitter.com/shapefiIe a sad little fellow
2865  else if ( b.driverName == QLatin1String( "GPKG" ) )
2866  return false;
2867  else if ( a.driverName == QLatin1String( "ESRI Shapefile" ) )
2868  return true;
2869  else if ( b.driverName == QLatin1String( "ESRI Shapefile" ) )
2870  return false;
2871  }
2872 
2873  return a.filterString.toLower().localeAwareCompare( b.filterString.toLower() ) < 0;
2874  } );
2875 
2876  return results;
2877 }
2878 
2879 QStringList QgsVectorFileWriter::supportedFormatExtensions( const VectorFormatOptions options )
2880 {
2881  const auto formats = supportedFiltersAndFormats( options );
2882  QSet< QString > extensions;
2883 
2884  const QRegularExpression rx( QStringLiteral( "\\*\\.(.*)$" ) );
2885 
2886  for ( const FilterFormatDetails &format : formats )
2887  {
2888  for ( const QString &glob : format.globs )
2889  {
2890  const QRegularExpressionMatch match = rx.match( glob );
2891  if ( !match.hasMatch() )
2892  continue;
2893 
2894  const QString matched = match.captured( 1 );
2895  extensions.insert( matched );
2896  }
2897  }
2898 
2899  QStringList extensionList = extensions.toList();
2900 
2901  std::sort( extensionList.begin(), extensionList.end(), [options]( const QString & a, const QString & b ) -> bool
2902  {
2903  if ( options & SortRecommended )
2904  {
2905  if ( a == QLatin1String( "gpkg" ) )
2906  return true; // Make https://twitter.com/shapefiIe a sad little fellow
2907  else if ( b == QLatin1String( "gpkg" ) )
2908  return false;
2909  else if ( a == QLatin1String( "shp" ) )
2910  return true;
2911  else if ( b == QLatin1String( "shp" ) )
2912  return false;
2913  }
2914 
2915  return a.toLower().localeAwareCompare( b.toLower() ) < 0;
2916  } );
2917 
2918  return extensionList;
2919 }
2920 
2921 QList< QgsVectorFileWriter::DriverDetails > QgsVectorFileWriter::ogrDriverList( const VectorFormatOptions options )
2922 {
2923  QList< QgsVectorFileWriter::DriverDetails > results;
2924 
2926  const int drvCount = OGRGetDriverCount();
2927 
2928  QStringList writableDrivers;
2929  for ( int i = 0; i < drvCount; ++i )
2930  {
2931  OGRSFDriverH drv = OGRGetDriver( i );
2932  if ( drv )
2933  {
2934  QString drvName = OGR_Dr_GetName( drv );
2935 
2936  if ( options & SkipNonSpatialFormats )
2937  {
2938  // skip non-spatial formats
2939  // TODO - use GDAL metadata to determine this, when support exists in GDAL
2940  if ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) )
2941  continue;
2942  }
2943 
2944  if ( drvName == QLatin1String( "ESRI Shapefile" ) )
2945  {
2946  writableDrivers << QStringLiteral( "DBF file" );
2947  }
2948  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2949  {
2950  // Add separate format for Mapinfo MIF (MITAB is OGR default)
2951  if ( drvName == QLatin1String( "MapInfo File" ) )
2952  {
2953  writableDrivers << QStringLiteral( "MapInfo MIF" );
2954  }
2955  else if ( drvName == QLatin1String( "SQLite" ) )
2956  {
2957  // Unfortunately it seems that there is no simple way to detect if
2958  // OGR SQLite driver is compiled with SpatiaLite support.
2959  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
2960  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
2961  // -> test if creation failes
2962  QString option = QStringLiteral( "SPATIALITE=YES" );
2963  char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ), nullptr };
2964  OGRSFDriverH poDriver;
2966  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
2967  if ( poDriver )
2968  {
2969  gdal::ogr_datasource_unique_ptr ds( OGR_Dr_CreateDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData(), options ) );
2970  if ( ds )
2971  {
2972  writableDrivers << QStringLiteral( "SpatiaLite" );
2973  OGR_Dr_DeleteDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData() );
2974  }
2975  }
2976  CPLFree( options[0] );
2977  }
2978  writableDrivers << drvName;
2979  }
2980  }
2981  }
2982 
2983  results.reserve( writableDrivers.count() );
2984  for ( const QString &drvName : qgis::as_const( writableDrivers ) )
2985  {
2986  MetaData metadata;
2987  if ( driverMetadata( drvName, metadata ) && !metadata.trLongName.isEmpty() )
2988  {
2989  DriverDetails details;
2990  details.driverName = drvName;
2991  details.longName = metadata.trLongName;
2992  results << details;
2993  }
2994  }
2995 
2996  std::sort( results.begin(), results.end(), [options]( const DriverDetails & a, const DriverDetails & b ) -> bool
2997  {
2998  if ( options & SortRecommended )
2999  {
3000  if ( a.driverName == QLatin1String( "GPKG" ) )
3001  return true; // Make https://twitter.com/shapefiIe a sad little fellow
3002  else if ( b.driverName == QLatin1String( "GPKG" ) )
3003  return false;
3004  else if ( a.driverName == QLatin1String( "ESRI Shapefile" ) )
3005  return true;
3006  else if ( b.driverName == QLatin1String( "ESRI Shapefile" ) )
3007  return false;
3008  }
3009 
3010  return a.longName.toLower().localeAwareCompare( b.longName.toLower() ) < 0;
3011  } );
3012  return results;
3013 }
3014 
3015 QString QgsVectorFileWriter::driverForExtension( const QString &extension )
3016 {
3017  QString ext = extension.trimmed();
3018  if ( ext.isEmpty() )
3019  return QString();
3020 
3021  if ( ext.startsWith( '.' ) )
3022  ext.remove( 0, 1 );
3023 
3024  GDALAllRegister();
3025  int const drvCount = GDALGetDriverCount();
3026 
3027  for ( int i = 0; i < drvCount; ++i )
3028  {
3029  GDALDriverH drv = GDALGetDriver( i );
3030  if ( drv )
3031  {
3032  char **driverMetadata = GDALGetMetadata( drv, nullptr );
3033  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) && CSLFetchBoolean( driverMetadata, GDAL_DCAP_VECTOR, false ) )
3034  {
3035  QString drvName = GDALGetDriverShortName( drv );
3036  QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
3037 
3038  Q_FOREACH ( const QString &driver, driverExtensions )
3039  {
3040  if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
3041  return drvName;
3042  }
3043  }
3044  }
3045  }
3046  return QString();
3047 }
3048 
3049 QString QgsVectorFileWriter::fileFilterString( const VectorFormatOptions options )
3050 {
3051  QString filterString;
3052  const auto driverFormats = supportedFiltersAndFormats( options );
3053  for ( const FilterFormatDetails &details : driverFormats )
3054  {
3055  if ( !filterString.isEmpty() )
3056  filterString += QLatin1String( ";;" );
3057 
3058  filterString += details.filterString;
3059  }
3060  return filterString;
3061 }
3062 
3063 QString QgsVectorFileWriter::filterForDriver( const QString &driverName )
3064 {
3065  MetaData metadata;
3066  if ( !driverMetadata( driverName, metadata ) || metadata.trLongName.isEmpty() || metadata.glob.isEmpty() )
3067  return QString();
3068 
3069  return QStringLiteral( "%1 (%2 %3)" ).arg( metadata.trLongName,
3070  metadata.glob.toLower(),
3071  metadata.glob.toUpper() );
3072 }
3073 
3075 {
3076  if ( codecName == QLatin1String( "System" ) )
3077  return QStringLiteral( "LDID/0" );
3078 
3079  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
3080  if ( re.exactMatch( codecName ) )
3081  {
3082  QString c = re.cap( 2 ).remove( '-' );
3083  bool isNumber;
3084  c.toInt( &isNumber );
3085  if ( isNumber )
3086  return c;
3087  }
3088  return codecName;
3089 }
3090 
3091 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer *vl, const QgsCoordinateTransform &ct, OGRDataSourceH ds )
3092 {
3093  if ( !vl || !ds )
3094  {
3095  return;
3096  }
3097 
3098  QgsFeatureRenderer *renderer = vl->renderer();
3099  if ( !renderer )
3100  {
3101  return;
3102  }
3103 
3104  //unit type
3105  QgsUnitTypes::DistanceUnit mapUnits = vl->crs().mapUnits();
3106  if ( ct.isValid() )
3107  {
3108  mapUnits = ct.destinationCrs().mapUnits();
3109  }
3110 
3111  mSymbolLayerTable.clear();
3112  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
3113  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
3114 
3115  //get symbols
3116  int nTotalLevels = 0;
3117  QgsSymbolList symbolList = renderer->symbols( mRenderContext );
3118  QgsSymbolList::iterator symbolIt = symbolList.begin();
3119  for ( ; symbolIt != symbolList.end(); ++symbolIt )
3120  {
3121  double mmsf = mmScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3122  double musf = mapUnitScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3123 
3124  int nLevels = ( *symbolIt )->symbolLayerCount();
3125  for ( int i = 0; i < nLevels; ++i )
3126  {
3127  mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
3128  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
3129  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
3130  ++nTotalLevels;
3131  }
3132  }
3133  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
3134 }
3135 
3136 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( const PreparedWriterDetails &details, QgsFeatureIterator &fit,
3137  const QgsCoordinateTransform &ct, QString *errorMessage )
3138 {
3139  if ( !details.renderer )
3140  return ErrInvalidLayer;
3141 
3142  mRenderContext.expressionContext() = details.expressionContext;
3143 
3144  QHash< QgsSymbol *, QList<QgsFeature> > features;
3145 
3146  //unit type
3147  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
3148  if ( ct.isValid() )
3149  {
3150  mapUnits = ct.destinationCrs().mapUnits();
3151  }
3152 
3153  startRender( details.renderer.get(), details.sourceFields );
3154 
3155  //fetch features
3156  QgsFeature fet;
3157  QgsSymbol *featureSymbol = nullptr;
3158  while ( fit.nextFeature( fet ) )
3159  {
3160  if ( ct.isValid() )
3161  {
3162  try
3163  {
3164  if ( fet.hasGeometry() )
3165  {
3166  QgsGeometry g = fet.geometry();
3167  g.transform( ct );
3168  fet.setGeometry( g );
3169  }
3170  }
3171  catch ( QgsCsException &e )
3172  {
3173  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
3174  .arg( e.what() );
3175  QgsLogger::warning( msg );
3176  if ( errorMessage )
3177  *errorMessage = msg;
3178 
3179  return ErrProjection;
3180  }
3181  }
3182  mRenderContext.expressionContext().setFeature( fet );
3183 
3184  featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
3185  if ( !featureSymbol )
3186  {
3187  continue;
3188  }
3189 
3190  QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
3191  if ( it == features.end() )
3192  {
3193  it = features.insert( featureSymbol, QList<QgsFeature>() );
3194  }
3195  it.value().append( fet );
3196  }
3197 
3198  //find out order
3199  QgsSymbolLevelOrder levels;
3200  QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
3201  for ( int i = 0; i < symbols.count(); i++ )
3202  {
3203  QgsSymbol *sym = symbols[i];
3204  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
3205  {
3206  int level = sym->symbolLayer( j )->renderingPass();
3207  if ( level < 0 || level >= 1000 ) // ignore invalid levels
3208  continue;
3209  QgsSymbolLevelItem item( sym, j );
3210  while ( level >= levels.count() ) // append new empty levels
3211  levels.append( QgsSymbolLevel() );
3212  levels[level].append( item );
3213  }
3214  }
3215 
3216  int nErrors = 0;
3217  int nTotalFeatures = 0;
3218 
3219  //export symbol layers and symbology
3220  for ( int l = 0; l < levels.count(); l++ )
3221  {
3222  QgsSymbolLevel &level = levels[l];
3223  for ( int i = 0; i < level.count(); i++ )
3224  {
3225  QgsSymbolLevelItem &item = level[i];
3226  QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
3227  if ( levelIt == features.end() )
3228  {
3229  ++nErrors;
3230  continue;
3231  }
3232 
3233  double mmsf = mmScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3234  double musf = mapUnitScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3235 
3236  int llayer = item.layer();
3237  QList<QgsFeature> &featureList = levelIt.value();
3238  QList<QgsFeature>::iterator featureIt = featureList.begin();
3239  for ( ; featureIt != featureList.end(); ++featureIt )
3240  {
3241  ++nTotalFeatures;
3242  gdal::ogr_feature_unique_ptr ogrFeature = createFeature( *featureIt );
3243  if ( !ogrFeature )
3244  {
3245  ++nErrors;
3246  continue;
3247  }
3248 
3249  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
3250  if ( !styleString.isEmpty() )
3251  {
3252  OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
3253  if ( !writeFeature( mLayer, ogrFeature.get() ) )
3254  {
3255  ++nErrors;
3256  }
3257  }
3258  }
3259  }
3260  }
3261 
3262  stopRender();
3263 
3264  if ( nErrors > 0 && errorMessage )
3265  {
3266  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
3267  }
3268 
3270 }
3271 
3272 double QgsVectorFileWriter::mmScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3273 {
3274  if ( symbolUnits == QgsUnitTypes::RenderMillimeters )
3275  {
3276  return 1.0;
3277  }
3278  else
3279  {
3280  //conversion factor map units -> mm
3281  if ( mapUnits == QgsUnitTypes::DistanceMeters )
3282  {
3283  return 1000 / scale;
3284  }
3285 
3286  }
3287  return 1.0; //todo: map units
3288 }
3289 
3290 double QgsVectorFileWriter::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3291 {
3292  if ( symbolUnits == QgsUnitTypes::RenderMapUnits )
3293  {
3294  return 1.0;
3295  }
3296  else
3297  {
3298  if ( symbolUnits == QgsUnitTypes::RenderMillimeters && mapUnits == QgsUnitTypes::DistanceMeters )
3299  {
3300  return scale / 1000;
3301  }
3302  }
3303  return 1.0;
3304 }
3305 
3306 void QgsVectorFileWriter::startRender( QgsFeatureRenderer *sourceRenderer, const QgsFields &fields )
3307 {
3308  mRenderer = createSymbologyRenderer( sourceRenderer );
3309  if ( !mRenderer )
3310  {
3311  return;
3312  }
3313 
3314  mRenderer->startRender( mRenderContext, fields );
3315 }
3316 
3317 void QgsVectorFileWriter::stopRender()
3318 {
3319  if ( !mRenderer )
3320  {
3321  return;
3322  }
3323 
3324  mRenderer->stopRender( mRenderContext );
3325 }
3326 
3327 std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer( QgsFeatureRenderer *sourceRenderer ) const
3328 {
3329  if ( mSymbologyExport == NoSymbology )
3330  {
3331  return nullptr;
3332  }
3333  if ( !sourceRenderer )
3334  {
3335  return nullptr;
3336  }
3337 
3338  return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->clone() );
3339 }
3340 
3341 void QgsVectorFileWriter::addRendererAttributes( QgsFeatureRenderer *renderer, QgsRenderContext &context, const QgsFields &fields, QgsAttributeList &attList )
3342 {
3343  if ( renderer )
3344  {
3345  const QSet<QString> rendererAttributes = renderer->usedAttributes( context );
3346  for ( const QString &attr : rendererAttributes )
3347  {
3348  int index = fields.lookupField( attr );
3349  if ( index != -1 )
3350  {
3351  attList.append( index );
3352  }
3353  }
3354  }
3355 }
3356 
3357 QStringList QgsVectorFileWriter::concatenateOptions( const QMap<QString, QgsVectorFileWriter::Option *> &options )
3358 {
3359  QStringList list;
3360  QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
3361 
3362  for ( it = options.constBegin(); it != options.constEnd(); ++it )
3363  {
3364  QgsVectorFileWriter::Option *option = it.value();
3365  switch ( option->type )
3366  {
3368  {
3369  QgsVectorFileWriter::IntOption *opt = dynamic_cast<QgsVectorFileWriter::IntOption *>( option );
3370  if ( opt )
3371  {
3372  list.append( QStringLiteral( "%1=%2" ).arg( it.key() ).arg( opt->defaultValue ) );
3373  }
3374  break;
3375  }
3376 
3378  {
3379  QgsVectorFileWriter::SetOption *opt = dynamic_cast<QgsVectorFileWriter::SetOption *>( option );
3380  if ( opt && !opt->defaultValue.isEmpty() )
3381  {
3382  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3383  }
3384  break;
3385  }
3386 
3388  {
3390  if ( opt && !opt->defaultValue.isNull() )
3391  {
3392  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3393  }
3394  break;
3395  }
3396 
3399  if ( opt )
3400  {
3401  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->mValue ) );
3402  }
3403  break;
3404  }
3405  }
3406 
3407  return list;
3408 }
3409 
3410 QgsVectorFileWriter::EditionCapabilities QgsVectorFileWriter::editionCapabilities( const QString &datasetName )
3411 {
3412  OGRSFDriverH hDriver = nullptr;
3413  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3414  if ( !hDS )
3415  return nullptr;
3416  QString drvName = OGR_Dr_GetName( hDriver );
3417  QgsVectorFileWriter::EditionCapabilities caps = nullptr;
3418  if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
3419  {
3420  // Shapefile driver returns True for a "foo.shp" dataset name,
3421  // creating "bar.shp" new layer, but this would be a bit confusing
3422  // for the user, so pretent that it does not support that
3423  if ( !( drvName == QLatin1String( "ESRI Shapefile" ) && QFile::exists( datasetName ) ) )
3424  caps |= CanAddNewLayer;
3425  }
3426  if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
3427  {
3428  caps |= CanDeleteLayer;
3429  }
3430  int layer_count = OGR_DS_GetLayerCount( hDS.get() );
3431  if ( layer_count )
3432  {
3433  OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
3434  if ( hLayer )
3435  {
3436  if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
3437  {
3438  caps |= CanAppendToExistingLayer;
3439  if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
3440  {
3442  }
3443  }
3444  }
3445  }
3446  return caps;
3447 }
3448 
3449 bool QgsVectorFileWriter::targetLayerExists( const QString &datasetName,
3450  const QString &layerNameIn )
3451 {
3452  OGRSFDriverH hDriver = nullptr;
3453  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3454  if ( !hDS )
3455  return false;
3456 
3457  QString layerName( layerNameIn );
3458  if ( layerName.isEmpty() )
3459  layerName = QFileInfo( datasetName ).baseName();
3460 
3461  return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3462 }
3463 
3464 
3465 bool QgsVectorFileWriter::areThereNewFieldsToCreate( const QString &datasetName,
3466  const QString &layerName,
3467  QgsVectorLayer *layer,
3468  const QgsAttributeList &attributes )
3469 {
3470  OGRSFDriverH hDriver = nullptr;
3471  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3472  if ( !hDS )
3473  return false;
3474  OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3475  if ( !hLayer )
3476  {
3477  return false;
3478  }
3479  bool ret = false;
3480  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
3481  Q_FOREACH ( int idx, attributes )
3482  {
3483  QgsField fld = layer->fields().at( idx );
3484  if ( OGR_FD_GetFieldIndex( defn, fld.name().toUtf8().constData() ) < 0 )
3485  {
3486  ret = true;
3487  break;
3488  }
3489  }
3490  return ret;
3491 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:299
QgsFeatureId id
Definition: qgsfeature.h:71
Append features to existing layer, but do not create new fields.
Wrapper for iterator of features from vector data provider or vector layer.
Flag to indicate that a new layer can be added to the dataset.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
QgsVectorFileWriter::OptionType type
Details of available driver formats.
static Type to25D(Type type)
Will convert the 25D version of the flat type if supported or Unknown if not supported.
Definition: qgswkbtypes.h:954
static Type singleType(Type type)
Returns the single type for a WKB type.
Definition: qgswkbtypes.h:152
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:296
int size() const
Returns number of items.
Definition: qgsfields.cpp:120
QString name
Definition: qgsfield.h:57
QStringList globs
Matching glob patterns for format, e.g.
Flag to indicate that new features can be added to an existing layer.
int precision
Definition: qgsfield.h:54
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
WriterError mError
Contains error value if construction was not successful.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:557
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
bool forceMulti
Sets to true to force creation of multi* geometries.
Details of available filters and formats.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsVectorFileWriter & operator=(const QgsVectorFileWriter &rh)=delete
QgsVectorFileWriter cannot be copied.
QString filterString
Filter string for file picker dialogs.
Filter out any formats which do not have spatial support (e.g. those which cannot save geometries) ...
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:549
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
SymbologyExport mSymbologyExport
virtual QVariant convert(int fieldIdxInLayer, const QVariant &value)
Convert the provided value, for field fieldIdxInLayer.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:121
QVariant minimumValue(int index) const override
Returns the minimum value for an attribute column or an invalid variant in case of error...
QgsAttributeList attributes
Attributes to export (empty means all unless skipAttributeCreation is set)
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
void setRendererScale(double scale)
Sets the renderer map scale.
bool addFeatureWithStyle(QgsFeature &feature, QgsFeatureRenderer *renderer, QgsUnitTypes::DistanceUnit outputUnit=QgsUnitTypes::DistanceMeters)
Adds a feature to the currently opened data source, using the style from a specified renderer...
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:538
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
QMap< QgsSymbolLayer *, QString > mSymbolLayerTable
static void registerOgrDrivers()
Register OGR drivers ensuring this only happens once.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
int symbolLayerCount() const
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:143
static QString driverForExtension(const QString &extension)
Returns the OGR driver name for a specified file extension.
QStringList layerOptions
List of OGR layer creation options.
static bool supportsFeatureStyles(const QString &driverName)
Returns true if the specified driverName supports feature styles.
FieldValueConverter()=default
Constructor.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
gdal::ogr_datasource_unique_ptr mDS
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:190
int count() const
Returns number of items.
Definition: qgsfields.cpp:115
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:768
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
static QgsVectorFileWriter::EditionCapabilities editionCapabilities(const QString &datasetName)
Returns edition capabilities for an existing dataset name.
QString what() const
Definition: qgsexception.h:48
QgsWkbTypes::Type overrideGeometryType
Set to a valid geometry type to override the default geometry type for the layer. ...
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:145
QList< QgsSymbolLevel > QgsSymbolLevelOrder
Definition: qgsrenderer.h:77
int length
Definition: qgsfield.h:53
QgsVectorFileWriter::SymbologyExport symbologyExport
Symbology to export.
QgsVectorFileWriter::SymbologyExport symbologyExport() const
~QgsVectorFileWriter() override
Close opened shapefile for writing.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Flag to indicate that new fields can be added to an existing layer. Imply CanAppendToExistingLayer.
bool onlySelectedFeatures
Write only selected features of layer.
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const =0
Returns a list of attributes required by this renderer.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Options to pass to writeAsVectorFormat()
virtual QgsVectorFileWriter::FieldValueConverter * clone() const
Creates a clone of the FieldValueConverter.
void setSymbologyScale(double scale)
Set reference scale for output.
int renderingPass() const
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:43
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) override
Adds a single feature to the sink.
QgsFields fields() const override
Returns the list of fields of this layer.
std::unique_ptr< std::remove_pointer< OGRFeatureH >::type, OGRFeatureDeleter > ogr_feature_unique_ptr
Scoped OGR feature.
Definition: qgsogrutils.h:129
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:104
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
#define FID_TO_NUMBER(fid)
Definition: qgsfeature.h:51
static bool areThereNewFieldsToCreate(const QString &datasetName, const QString &layerName, QgsVectorLayer *layer, const QgsAttributeList &attributes)
Returns whether there are among the attributes specified some that do not exist yet in the layer...
QString driverName
Unique driver name.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:195
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
QgsWkbTypes::Type wkbType() const override
Returns the WKBType or WKBUnknown in case of error.
QStringList datasourceOptions
List of OGR data source creation options.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:864
static OGRwkbGeometryType ogrTypeFromWkbType(QgsWkbTypes::Type type)
Gets the ogr geometry type from an internal QGIS wkb type enum.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
OGRGeometryH createEmptyGeometry(QgsWkbTypes::Type wkbType)
FieldValueConverter * mFieldValueConverter
Field value converter.
QgsVectorFileWriter(const QString &vectorFileName, const QString &fileEncoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &srs=QgsCoordinateReferenceSystem(), const QString &driverName="GPKG", const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QString *newFilename=nullptr, QgsVectorFileWriter::SymbologyExport symbologyExport=QgsVectorFileWriter::NoSymbology)
Create a new vector file writer.
static QStringList supportedFormatExtensions(VectorFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats, e.g "shp", "gpkg".
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QMap< QString, QgsVectorFileWriter::Option * > layerOptions
ActionOnExistingFile
Combination of CanAddNewLayer, CanAppendToExistingLayer, CanAddNewFieldsToExistingLayer or CanDeleteL...
QgsFeatureRenderer * renderer()
Returns renderer.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
QgsSymbolLayer * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
Definition: qgssymbol.cpp:332
QMap< int, int > mAttrIdxToOgrIdx
Map attribute indizes to OGR field indexes.
QgsRectangle filterExtent
If not empty, only features intersecting the extent will be saved.
OGRSpatialReferenceH mOgrRef
QByteArray asWkb() const
Export the geometry to WKB.
double symbologyScale() const
Returns the reference scale for output.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
Append features to existing layer, and create new fields if needed.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Rendering with symbol levels (i.e. implements symbols(), symbolForFeature())
Definition: qgsrenderer.h:242
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:43
QString compulsoryEncoding
Some formats require a compulsory encoding, typically UTF-8. If no compulsory encoding, empty string.
QString errorMessage()
Retrieves error message.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:539
QVariant maximumValue(int index) const override
Returns the maximum value for an attribute column or an invalid variant in case of error...
static QString fileFilterString(VectorFormatOptions options=SortRecommended)
Returns filter string that can be used for dialogs.
Contains information about the context of a rendering operation.
bool usingSymbolLevels() const
Definition: qgsrenderer.h:271
static QString convertCodecNameForEncodingOption(const QString &codecName)
Converts codec name to string passed to ENCODING layer creation option of OGR Shapefile.
virtual QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const
Returns list of symbols used for rendering the feature.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QgsVectorFileWriter::WriterError hasError()
Checks whether there were any errors in constructor.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Transform from destination to source CRS.
QList< QgsSymbolLevelItem > QgsSymbolLevel
Definition: qgsrenderer.h:73
bool skipAttributeCreation
Only write geometries.
double symbologyScale
Scale of symbology.
virtual QgsSymbolList symbols(QgsRenderContext &context) const
Returns list of symbols used by the renderer.
static QgsVectorFileWriter::WriterError writeAsVectorFormat(QgsVectorLayer *layer, const QString &fileName, const QString &fileEncoding, const QgsCoordinateReferenceSystem &destCRS=QgsCoordinateReferenceSystem(), const QString &driverName="GPKG", bool onlySelected=false, QString *errorMessage=nullptr, const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), bool skipAttributeCreation=false, QString *newFilename=nullptr, QgsVectorFileWriter::SymbologyExport symbologyExport=QgsVectorFileWriter::NoSymbology, double symbologyScale=1.0, const QgsRectangle *filterExtent=nullptr, QgsWkbTypes::Type overrideGeometryType=QgsWkbTypes::Unknown, bool forceMulti=false, bool includeZ=false, const QgsAttributeList &attributes=QgsAttributeList(), QgsVectorFileWriter::FieldValueConverter *fieldValueConverter=nullptr)
Write contents of vector layer to an (OGR supported) vector formt.
static QList< QgsVectorFileWriter::DriverDetails > ogrDriverList(VectorFormatOptions options=SortRecommended)
Returns the driver list that can be used for dialogs.
double mSymbologyScale
Scale for symbology export (e.g. for symbols units in map units)
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
This class represents a coordinate reference system (CRS).
QString toWkt() const
Returns a WKT representation of this CRS.
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
Definition: qgsogrutils.h:124
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
QMap< QString, QgsVectorFileWriter::Option * > driverOptions
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:429
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
Class for doing transforms between two map coordinate systems.
static bool deleteShapeFile(const QString &fileName)
Delete a shapefile (and its accompanying shx / dbf / prf)
Flag to indicate that an existing layer can be deleted.
QgsCoordinateTransform ct
Transform to reproject exported geometries with, or invalid transform for no transformation.
Interface to convert raw field values to their user-friendly value.
bool includeZ
Sets to true to include z dimension in output. This option is only valid if overrideGeometryType is s...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
static QList< QgsVectorFileWriter::FilterFormatDetails > supportedFiltersAndFormats(VectorFormatOptions options=SortRecommended)
Returns a list or pairs, with format filter string as first element and OGR format key as second elem...
QList< int > QgsAttributeList
Definition: qgsfield.h:27
static bool targetLayerExists(const QString &datasetName, const QString &layerName)
Returns whether the target layer already exists.
QString providerType() const
Returns the provider type for this layer.
QgsVectorFileWriter::FieldValueConverter * fieldValueConverter
Field value converter.
QString layerName
Layer name. If let empty, it will be derived from the filename.
bool nextFeature(QgsFeature &f)
virtual QgsField fieldDefinition(const QgsField &field)
Returns a possibly modified field definition.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Definition: qgsogrutils.h:114
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features to the sink.
QgsFeedback * feedback
Optional feedback object allowing cancelation of layer save.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:255
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
Writing was interrupted by manual cancelation.
QgsSymbol * symbol()
Definition: qgsrenderer.h:65
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
QVariant::Type type
Definition: qgsfield.h:55
QgsWkbTypes::Type mWkbType
Geometry type which is being used.
virtual QgsFeatureRenderer::Capabilities capabilities()
Returns details about internals of this renderer.
Definition: qgsrenderer.h:262
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:100
QString longName
Descriptive, user friendly name for the driver.
Use recommended sort order, with extremely commonly used formats listed first.
static bool driverMetadata(const QString &driverName, MetaData &driverMetadata)
bool isValid() const
Returns whether this CRS is correctly initialized and usable.