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