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