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