QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  driverMetadata.insert( QStringLiteral( "GeoJSON" ),
1084  QStringLiteral( "GeoJSON" ),
1085  QObject::tr( "GeoJSON" ),
1086  QStringLiteral( "*.geojson" ),
1087  QStringLiteral( "geojson" ),
1088  datasetOptions,
1089  layerOptions,
1090  QStringLiteral( "UTF-8" )
1091  )
1092  );
1093 
1094  // GeoJSONSeq
1095  datasetOptions.clear();
1096  layerOptions.clear();
1097 
1098  layerOptions.insert( QStringLiteral( "COORDINATE_PRECISION" ), new QgsVectorFileWriter::IntOption(
1099  QObject::tr( "Maximum number of figures after decimal separator to write in coordinates. "
1100  "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1101  15 // Default value
1102  ) );
1103 
1104  layerOptions.insert( QStringLiteral( "RS" ), new QgsVectorFileWriter::BoolOption(
1105  QObject::tr( "Whether to start records with the RS=0x1E character (RFC 8142 standard). "
1106  "Defaults to NO: Newline Delimited JSON (geojsonl). \n"
1107  "If set to YES: RFC 8142 standard: GeoJSON Text Sequences (geojsons)." ),
1108  false // Default value = NO
1109  ) );
1110 
1111  driverMetadata.insert( QStringLiteral( "GeoJSONSeq" ),
1113  QStringLiteral( "GeoJSON - Newline Delimited" ),
1114  QObject::tr( "GeoJSON - Newline Delimited" ),
1115  QStringLiteral( "*.geojsonl *.geojsons *.json" ),
1116  QStringLiteral( "json" ), // add json for now
1117  datasetOptions,
1118  layerOptions,
1119  QStringLiteral( "UTF-8" )
1120  )
1121  );
1122 
1123  // GeoRSS
1124  datasetOptions.clear();
1125  layerOptions.clear();
1126 
1127  datasetOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
1128  QObject::tr( "whether the document must be in RSS 2.0 or Atom 1.0 format. "
1129  "Default value : RSS" ),
1130  QStringList()
1131  << QStringLiteral( "RSS" )
1132  << QStringLiteral( "ATOM" ),
1133  QStringLiteral( "RSS" ) // Default value
1134  ) );
1135 
1136  datasetOptions.insert( QStringLiteral( "GEOM_DIALECT" ), new QgsVectorFileWriter::SetOption(
1137  QObject::tr( "The encoding of location information. Default value : SIMPLE. "
1138  "W3C_GEO only supports point geometries. "
1139  "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
1140  QStringList()
1141  << QStringLiteral( "SIMPLE" )
1142  << QStringLiteral( "GML" )
1143  << QStringLiteral( "W3C_GEO" ),
1144  QStringLiteral( "SIMPLE" ) // Default value
1145  ) );
1146 
1147  datasetOptions.insert( QStringLiteral( "USE_EXTENSIONS" ), new QgsVectorFileWriter::BoolOption(
1148  QObject::tr( "If defined to YES, extension fields will be written. "
1149  "If the field name not found in the base schema matches "
1150  "the foo_bar pattern, foo will be considered as the namespace "
1151  "of the element, and a <foo:bar> element will be written. "
1152  "Otherwise, elements will be written in the <ogr:> namespace." ),
1153  false // Default value
1154  ) );
1155 
1156  datasetOptions.insert( QStringLiteral( "WRITE_HEADER_AND_FOOTER" ), new QgsVectorFileWriter::BoolOption(
1157  QObject::tr( "If defined to NO, only <entry> or <item> elements will be written. "
1158  "The user will have to provide the appropriate header and footer of the document." ),
1159  true // Default value
1160  ) );
1161 
1162  datasetOptions.insert( QStringLiteral( "HEADER" ), new QgsVectorFileWriter::StringOption(
1163  QObject::tr( "XML content that will be put between the <channel> element and the "
1164  "first <item> element for a RSS document, or between the xml tag and "
1165  "the first <entry> element for an Atom document." ),
1166  QString() // Default value
1167  ) );
1168 
1169  datasetOptions.insert( QStringLiteral( "TITLE" ), new QgsVectorFileWriter::StringOption(
1170  QObject::tr( "Value put inside the <title> element in the header. "
1171  "If not provided, a dummy value will be used as that element is compulsory." ),
1172  QString() // Default value
1173  ) );
1174 
1175  datasetOptions.insert( QStringLiteral( "DESCRIPTION" ), new QgsVectorFileWriter::StringOption(
1176  QObject::tr( "Value put inside the <description> element in the header. "
1177  "If not provided, a dummy value will be used as that element is compulsory." ),
1178  QString() // Default value
1179  ) );
1180 
1181  datasetOptions.insert( QStringLiteral( "LINK" ), new QgsVectorFileWriter::StringOption(
1182  QObject::tr( "Value put inside the <link> element in the header. "
1183  "If not provided, a dummy value will be used as that element is compulsory." ),
1184  QString() // Default value
1185  ) );
1186 
1187  datasetOptions.insert( QStringLiteral( "UPDATED" ), new QgsVectorFileWriter::StringOption(
1188  QObject::tr( "Value put inside the <updated> element in the header. "
1189  "Should be formatted as a XML datetime. "
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( "AUTHOR_NAME" ), new QgsVectorFileWriter::StringOption(
1195  QObject::tr( "Value put inside the <author><name> element in the header. "
1196  "If not provided, a dummy value will be used as that element is compulsory." ),
1197  QString() // Default value
1198  ) );
1199 
1200  datasetOptions.insert( QStringLiteral( "ID" ), new QgsVectorFileWriter::StringOption(
1201  QObject::tr( "Value put inside the <id> element in the header. "
1202  "If not provided, a dummy value will be used as that element is compulsory." ),
1203  QString() // Default value
1204  ) );
1205 
1206  driverMetadata.insert( QStringLiteral( "GeoRSS" ),
1208  QStringLiteral( "GeoRSS" ),
1209  QObject::tr( "GeoRSS" ),
1210  QStringLiteral( "*.xml" ),
1211  QStringLiteral( "xml" ),
1212  datasetOptions,
1213  layerOptions,
1214  QStringLiteral( "UTF-8" )
1215  )
1216  );
1217 
1218  // Geography Markup Language [GML]
1219  datasetOptions.clear();
1220  layerOptions.clear();
1221 
1222  datasetOptions.insert( QStringLiteral( "XSISCHEMAURI" ), new QgsVectorFileWriter::StringOption(
1223  QObject::tr( "If provided, this URI will be inserted as the schema location. "
1224  "Note that the schema file isn't actually accessed by OGR, so it "
1225  "is up to the user to ensure it will match the schema of the OGR "
1226  "produced GML data file." ),
1227  QString() // Default value
1228  ) );
1229 
1230  datasetOptions.insert( QStringLiteral( "XSISCHEMA" ), new QgsVectorFileWriter::SetOption(
1231  QObject::tr( "This writes a GML application schema file to a corresponding "
1232  ".xsd file (with the same basename). If INTERNAL is used the "
1233  "schema is written within the GML file, but this is experimental "
1234  "and almost certainly not valid XML. "
1235  "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
1236  QStringList()
1237  << QStringLiteral( "EXTERNAL" )
1238  << QStringLiteral( "INTERNAL" )
1239  << QStringLiteral( "OFF" ),
1240  QStringLiteral( "EXTERNAL" ) // Default value
1241  ) );
1242 
1243  datasetOptions.insert( QStringLiteral( "PREFIX" ), new QgsVectorFileWriter::StringOption(
1244  QObject::tr( "This is the prefix for the application target namespace." ),
1245  QStringLiteral( "ogr" ) // Default value
1246  ) );
1247 
1248  datasetOptions.insert( QStringLiteral( "STRIP_PREFIX" ), new QgsVectorFileWriter::BoolOption(
1249  QObject::tr( "Can be set to TRUE to avoid writing the prefix of the "
1250  "application target namespace in the GML file." ),
1251  false // Default value
1252  ) );
1253 
1254  datasetOptions.insert( QStringLiteral( "TARGET_NAMESPACE" ), new QgsVectorFileWriter::StringOption(
1255  QObject::tr( "Defaults to 'http://ogr.maptools.org/'. "
1256  "This is the application target namespace." ),
1257  QStringLiteral( "http://ogr.maptools.org/" ) // Default value
1258  ) );
1259 
1260  datasetOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
1261  QObject::tr( "If not specified, GML2 will be used." ),
1262  QStringList()
1263  << QStringLiteral( "GML3" )
1264  << QStringLiteral( "GML3Deegree" )
1265  << QStringLiteral( "GML3.2" ),
1266  QString(), // Default value
1267  true // Allow None
1268  ) );
1269 
1270  datasetOptions.insert( QStringLiteral( "GML3_LONGSRS" ), new QgsVectorFileWriter::BoolOption(
1271  QObject::tr( "Only valid when FORMAT=GML3/GML3Degree/GML3.2. Default to YES. " //needs review here
1272  "If YES, SRS with EPSG authority will be written with the "
1273  "'urn:ogc:def:crs:EPSG::' prefix. In the case the SRS is a "
1274  "geographic SRS without explicit AXIS order, but that the same "
1275  "SRS authority code imported with ImportFromEPSGA() should be "
1276  "treated as lat/long, then the function will take care of coordinate "
1277  "order swapping. If set to NO, SRS with EPSG authority will be "
1278  "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
1279  true // Default value
1280  ) );
1281 
1282  datasetOptions.insert( QStringLiteral( "WRITE_FEATURE_BOUNDED_BY" ), new QgsVectorFileWriter::BoolOption(
1283  QObject::tr( "only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
1284  "If set to NO, the <gml:boundedBy> element will not be written for "
1285  "each feature." ),
1286  true // Default value
1287  ) );
1288 
1289  datasetOptions.insert( QStringLiteral( "SPACE_INDENTATION" ), new QgsVectorFileWriter::BoolOption(
1290  QObject::tr( "Default to YES. If YES, the output will be indented with spaces "
1291  "for more readability, but at the expense of file size." ),
1292  true // Default value
1293  ) );
1294 
1295 
1296  driverMetadata.insert( QStringLiteral( "GML" ),
1298  QStringLiteral( "Geography Markup Language [GML]" ),
1299  QObject::tr( "Geography Markup Language [GML]" ),
1300  QStringLiteral( "*.gml" ),
1301  QStringLiteral( "gml" ),
1302  datasetOptions,
1303  layerOptions,
1304  QStringLiteral( "UTF-8" )
1305  )
1306  );
1307 
1308  // GeoPackage
1309  datasetOptions.clear();
1310  layerOptions.clear();
1311 
1312  layerOptions.insert( QStringLiteral( "IDENTIFIER" ), new QgsVectorFileWriter::StringOption(
1313  QObject::tr( "Human-readable identifier (e.g. short name) for the layer content" ),
1314  QString() // Default value
1315  ) );
1316 
1317  layerOptions.insert( QStringLiteral( "DESCRIPTION" ), new QgsVectorFileWriter::StringOption(
1318  QObject::tr( "Human-readable description for the layer content" ),
1319  QString() // Default value
1320  ) );
1321 
1322  layerOptions.insert( QStringLiteral( "FID" ), new QgsVectorFileWriter::StringOption(
1323  QObject::tr( "Name for the feature identifier column" ),
1324  QStringLiteral( "fid" ) // Default value
1325  ) );
1326 
1327  layerOptions.insert( QStringLiteral( "GEOMETRY_NAME" ), new QgsVectorFileWriter::StringOption(
1328  QObject::tr( "Name for the geometry column" ),
1329  QStringLiteral( "geom" ) // Default value
1330  ) );
1331 
1332  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::BoolOption(
1333  QObject::tr( "If a spatial index must be created." ),
1334  true // Default value
1335  ) );
1336 
1337  driverMetadata.insert( QStringLiteral( "GPKG" ),
1339  QStringLiteral( "GeoPackage" ),
1340  QObject::tr( "GeoPackage" ),
1341  QStringLiteral( "*.gpkg" ),
1342  QStringLiteral( "gpkg" ),
1343  datasetOptions,
1344  layerOptions,
1345  QStringLiteral( "UTF-8" )
1346  )
1347  );
1348 
1349  // Generic Mapping Tools [GMT]
1350  datasetOptions.clear();
1351  layerOptions.clear();
1352 
1353  driverMetadata.insert( QStringLiteral( "GMT" ),
1355  QStringLiteral( "Generic Mapping Tools [GMT]" ),
1356  QObject::tr( "Generic Mapping Tools [GMT]" ),
1357  QStringLiteral( "*.gmt" ),
1358  QStringLiteral( "gmt" ),
1359  datasetOptions,
1360  layerOptions
1361  )
1362  );
1363 
1364  // GPS eXchange Format [GPX]
1365  datasetOptions.clear();
1366  layerOptions.clear();
1367 
1368  layerOptions.insert( QStringLiteral( "FORCE_GPX_TRACK" ), new QgsVectorFileWriter::BoolOption(
1369  QObject::tr( "By default when writing a layer whose features are of "
1370  "type wkbLineString, the GPX driver chooses to write "
1371  "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1372  "they will be written as tracks." ),
1373  false // Default value
1374  ) );
1375 
1376  layerOptions.insert( QStringLiteral( "FORCE_GPX_ROUTE" ), new QgsVectorFileWriter::BoolOption(
1377  QObject::tr( "By default when writing a layer whose features are of "
1378  "type wkbMultiLineString, the GPX driver chooses to write "
1379  "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1380  "they will be written as routes, provided that the multilines "
1381  "are composed of only one single line." ),
1382  false // Default value
1383  ) );
1384 
1385  datasetOptions.insert( QStringLiteral( "GPX_USE_EXTENSIONS" ), new QgsVectorFileWriter::BoolOption(
1386  QObject::tr( "If GPX_USE_EXTENSIONS=YES is specified, "
1387  "extra fields will be written inside the <extensions> tag." ),
1388  false // Default value
1389  ) );
1390 
1391  datasetOptions.insert( QStringLiteral( "GPX_EXTENSIONS_NS" ), new QgsVectorFileWriter::StringOption(
1392  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1393  "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1394  QStringLiteral( "ogr" ) // Default value
1395  ) );
1396 
1397  datasetOptions.insert( QStringLiteral( "GPX_EXTENSIONS_NS_URL" ), new QgsVectorFileWriter::StringOption(
1398  QObject::tr( "Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1399  "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1400  QStringLiteral( "http://osgeo.org/gdal" ) // Default value
1401  ) );
1402 
1403  datasetOptions.insert( QStringLiteral( "LINEFORMAT" ), new QgsVectorFileWriter::SetOption(
1404  QObject::tr( "By default files are created with the line termination "
1405  "conventions of the local platform (CR/LF on win32 or LF "
1406  "on all other systems). This may be overridden through use "
1407  "of the LINEFORMAT layer creation option which may have a value "
1408  "of CRLF (DOS format) or LF (Unix format)." ),
1409  QStringList()
1410  << QStringLiteral( "CRLF" )
1411  << QStringLiteral( "LF" ),
1412  QString(), // Default value
1413  true // Allow None
1414  ) );
1415 
1416  driverMetadata.insert( QStringLiteral( "GPX" ),
1418  QStringLiteral( "GPS eXchange Format [GPX]" ),
1419  QObject::tr( "GPS eXchange Format [GPX]" ),
1420  QStringLiteral( "*.gpx" ),
1421  QStringLiteral( "gpx" ),
1422  datasetOptions,
1423  layerOptions,
1424  QStringLiteral( "UTF-8" )
1425  )
1426  );
1427 
1428  // INTERLIS 1
1429  datasetOptions.clear();
1430  layerOptions.clear();
1431 
1432  driverMetadata.insert( QStringLiteral( "Interlis 1" ),
1434  QStringLiteral( "INTERLIS 1" ),
1435  QObject::tr( "INTERLIS 1" ),
1436  QStringLiteral( "*.itf *.xml *.ili" ),
1437  QStringLiteral( "ili" ),
1438  datasetOptions,
1439  layerOptions
1440  )
1441  );
1442 
1443  // INTERLIS 2
1444  datasetOptions.clear();
1445  layerOptions.clear();
1446 
1447  driverMetadata.insert( QStringLiteral( "Interlis 2" ),
1449  QStringLiteral( "INTERLIS 2" ),
1450  QObject::tr( "INTERLIS 2" ),
1451  QStringLiteral( "*.xtf *.xml *.ili" ),
1452  QStringLiteral( "ili" ),
1453  datasetOptions,
1454  layerOptions
1455  )
1456  );
1457 
1458  // Keyhole Markup Language [KML]
1459  datasetOptions.clear();
1460  layerOptions.clear();
1461 
1462  datasetOptions.insert( QStringLiteral( "NameField" ), new QgsVectorFileWriter::StringOption(
1463  QObject::tr( "Allows you to specify the field to use for the KML <name> element." ),
1464  QStringLiteral( "Name" ) // Default value
1465  ) );
1466 
1467  datasetOptions.insert( QStringLiteral( "DescriptionField" ), new QgsVectorFileWriter::StringOption(
1468  QObject::tr( "Allows you to specify the field to use for the KML <description> element." ),
1469  QStringLiteral( "Description" ) // Default value
1470  ) );
1471 
1472  datasetOptions.insert( QStringLiteral( "AltitudeMode" ), new QgsVectorFileWriter::SetOption(
1473  QObject::tr( "Allows you to specify the AltitudeMode to use for KML geometries. "
1474  "This will only affect 3D geometries and must be one of the valid KML options." ),
1475  QStringList()
1476  << QStringLiteral( "clampToGround" )
1477  << QStringLiteral( "relativeToGround" )
1478  << QStringLiteral( "absolute" ),
1479  QStringLiteral( "relativeToGround" ) // Default value
1480  ) );
1481 
1482 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
1483  datasetOptions.insert( QStringLiteral( "DOCUMENT_ID" ), new QgsVectorFileWriter::StringOption(
1484  QObject::tr( "The DOCUMENT_ID datasource creation option can be used to specified "
1485  "the id of the root <Document> node. The default value is root_doc." ),
1486  QStringLiteral( "root_doc" ) // Default value
1487  ) );
1488 #endif
1489 
1490  driverMetadata.insert( QStringLiteral( "KML" ),
1492  QStringLiteral( "Keyhole Markup Language [KML]" ),
1493  QObject::tr( "Keyhole Markup Language [KML]" ),
1494  QStringLiteral( "*.kml" ),
1495  QStringLiteral( "kml" ),
1496  datasetOptions,
1497  layerOptions,
1498  QStringLiteral( "UTF-8" )
1499  )
1500  );
1501 
1502  // Mapinfo
1503  datasetOptions.clear();
1504  layerOptions.clear();
1505 
1506  auto insertMapInfoOptions = []( QMap<QString, QgsVectorFileWriter::Option *> &datasetOptions, QMap<QString, QgsVectorFileWriter::Option *> &layerOptions )
1507  {
1508  datasetOptions.insert( QStringLiteral( "SPATIAL_INDEX_MODE" ), new QgsVectorFileWriter::SetOption(
1509  QObject::tr( "Use this to turn on 'quick spatial index mode'. "
1510  "In this mode writing files can be about 5 times faster, "
1511  "but spatial queries can be up to 30 times slower." ),
1512  QStringList()
1513  << QStringLiteral( "QUICK" )
1514  << QStringLiteral( "OPTIMIZED" ),
1515  QStringLiteral( "QUICK" ), // Default value
1516  true // Allow None
1517  ) );
1518 
1519  datasetOptions.insert( QStringLiteral( "BLOCK_SIZE" ), new QgsVectorFileWriter::IntOption(
1520  QObject::tr( "(multiples of 512): Block size for .map files. Defaults "
1521  "to 512. MapInfo 15.2 and above creates .tab files with a "
1522  "blocksize of 16384 bytes. Any MapInfo version should be "
1523  "able to handle block sizes from 512 to 32256." ),
1524  512
1525  ) );
1526  layerOptions.insert( QStringLiteral( "BOUNDS" ), new QgsVectorFileWriter::StringOption(
1527  QObject::tr( "xmin,ymin,xmax,ymax: Define custom layer bounds to increase the "
1528  "accuracy of the coordinates. Note: the geometry of written "
1529  "features must be within the defined box." ),
1530  QString() // Default value
1531  ) );
1532  };
1533  insertMapInfoOptions( datasetOptions, layerOptions );
1534 
1535  driverMetadata.insert( QStringLiteral( "MapInfo File" ),
1537  QStringLiteral( "Mapinfo" ),
1538  QObject::tr( "Mapinfo TAB" ),
1539  QStringLiteral( "*.tab" ),
1540  QStringLiteral( "tab" ),
1541  datasetOptions,
1542  layerOptions
1543  )
1544  );
1545  datasetOptions.clear();
1546  layerOptions.clear();
1547  insertMapInfoOptions( datasetOptions, layerOptions );
1548 
1549  // QGIS internal alias for MIF files
1550  driverMetadata.insert( QStringLiteral( "MapInfo MIF" ),
1552  QStringLiteral( "Mapinfo" ),
1553  QObject::tr( "Mapinfo MIF" ),
1554  QStringLiteral( "*.mif" ),
1555  QStringLiteral( "mif" ),
1556  datasetOptions,
1557  layerOptions
1558  )
1559  );
1560 
1561  // Microstation DGN
1562  datasetOptions.clear();
1563  layerOptions.clear();
1564 
1565  datasetOptions.insert( QStringLiteral( "3D" ), new QgsVectorFileWriter::BoolOption(
1566  QObject::tr( "Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1567  "seed file should be used. This option is ignored if the SEED option is provided." ),
1568  false // Default value
1569  ) );
1570 
1571  datasetOptions.insert( QStringLiteral( "SEED" ), new QgsVectorFileWriter::StringOption(
1572  QObject::tr( "Override the seed file to use." ),
1573  QString() // Default value
1574  ) );
1575 
1576  datasetOptions.insert( QStringLiteral( "COPY_WHOLE_SEED_FILE" ), new QgsVectorFileWriter::BoolOption(
1577  QObject::tr( "Indicate whether the whole seed file should be copied. "
1578  "If not, only the first three elements will be copied." ),
1579  false // Default value
1580  ) );
1581 
1582  datasetOptions.insert( QStringLiteral( "COPY_SEED_FILE_COLOR_TABLE" ), new QgsVectorFileWriter::BoolOption(
1583  QObject::tr( "Indicates whether the color table should be copied from the seed file." ),
1584  false // Default value
1585  ) );
1586 
1587  datasetOptions.insert( QStringLiteral( "MASTER_UNIT_NAME" ), new QgsVectorFileWriter::StringOption(
1588  QObject::tr( "Override the master unit name from the seed file with "
1589  "the provided one or two character unit name." ),
1590  QString() // Default value
1591  ) );
1592 
1593  datasetOptions.insert( QStringLiteral( "SUB_UNIT_NAME" ), new QgsVectorFileWriter::StringOption(
1594  QObject::tr( "Override the sub unit name from the seed file with the provided "
1595  "one or two character unit name." ),
1596  QString() // Default value
1597  ) );
1598 
1599  datasetOptions.insert( QStringLiteral( "SUB_UNITS_PER_MASTER_UNIT" ), new QgsVectorFileWriter::IntOption(
1600  QObject::tr( "Override the number of subunits per master unit. "
1601  "By default the seed file value is used." ),
1602  0 // Default value
1603  ) );
1604 
1605  datasetOptions.insert( QStringLiteral( "UOR_PER_SUB_UNIT" ), new QgsVectorFileWriter::IntOption(
1606  QObject::tr( "Override the number of UORs (Units of Resolution) "
1607  "per sub unit. By default the seed file value is used." ),
1608  0 // Default value
1609  ) );
1610 
1611  datasetOptions.insert( QStringLiteral( "ORIGIN" ), new QgsVectorFileWriter::StringOption(
1612  QObject::tr( "ORIGIN=x,y,z: Override the origin of the design plane. "
1613  "By default the origin from the seed file is used." ),
1614  QString() // Default value
1615  ) );
1616 
1617  driverMetadata.insert( QStringLiteral( "DGN" ),
1619  QStringLiteral( "Microstation DGN" ),
1620  QObject::tr( "Microstation DGN" ),
1621  QStringLiteral( "*.dgn" ),
1622  QStringLiteral( "dgn" ),
1623  datasetOptions,
1624  layerOptions
1625  )
1626  );
1627 
1628  // S-57 Base file
1629  datasetOptions.clear();
1630  layerOptions.clear();
1631 
1632  datasetOptions.insert( QStringLiteral( "UPDATES" ), new QgsVectorFileWriter::SetOption(
1633  QObject::tr( "Should update files be incorporated into the base data on the fly." ),
1634  QStringList()
1635  << QStringLiteral( "APPLY" )
1636  << QStringLiteral( "IGNORE" ),
1637  QStringLiteral( "APPLY" ) // Default value
1638  ) );
1639 
1640  datasetOptions.insert( QStringLiteral( "SPLIT_MULTIPOINT" ), new QgsVectorFileWriter::BoolOption(
1641  QObject::tr( "Should multipoint soundings be split into many single point sounding features. "
1642  "Multipoint geometries are not well handled by many formats, "
1643  "so it can be convenient to split single sounding features with many points "
1644  "into many single point features." ),
1645  false // Default value
1646  ) );
1647 
1648  datasetOptions.insert( QStringLiteral( "ADD_SOUNDG_DEPTH" ), new QgsVectorFileWriter::BoolOption(
1649  QObject::tr( "Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1650  "of the sounding. This should only be enabled when SPLIT_MULTIPOINT is "
1651  "also enabled." ),
1652  false // Default value
1653  ) );
1654 
1655  datasetOptions.insert( QStringLiteral( "RETURN_PRIMITIVES" ), new QgsVectorFileWriter::BoolOption(
1656  QObject::tr( "Should all the low level geometry primitives be returned as special "
1657  "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1658  false // Default value
1659  ) );
1660 
1661  datasetOptions.insert( QStringLiteral( "PRESERVE_EMPTY_NUMBERS" ), new QgsVectorFileWriter::BoolOption(
1662  QObject::tr( "If enabled, numeric attributes assigned an empty string as a value will "
1663  "be preserved as a special numeric value. This option should not generally "
1664  "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1665  false // Default value
1666  ) );
1667 
1668  datasetOptions.insert( QStringLiteral( "LNAM_REFS" ), new QgsVectorFileWriter::BoolOption(
1669  QObject::tr( "Should LNAM and LNAM_REFS fields be attached to features capturing "
1670  "the feature to feature relationships in the FFPT group of the S-57 file." ),
1671  true // Default value
1672  ) );
1673 
1674  datasetOptions.insert( QStringLiteral( "RETURN_LINKAGES" ), new QgsVectorFileWriter::BoolOption(
1675  QObject::tr( "Should additional attributes relating features to their underlying "
1676  "geometric primitives be attached. These are the values of the FSPT group, "
1677  "and are primarily needed when doing S-57 to S-57 translations." ),
1678  false // Default value
1679  ) );
1680 
1681  datasetOptions.insert( QStringLiteral( "RECODE_BY_DSSI" ), new QgsVectorFileWriter::BoolOption(
1682  QObject::tr( "Should attribute values be recoded to UTF-8 from the character encoding "
1683  "specified in the S57 DSSI record." ),
1684  false // Default value
1685  ) );
1686 
1687  // set OGR_S57_OPTIONS = "RETURN_PRIMITIVES=ON,RETURN_LINKAGES=ON,LNAM_REFS=ON"
1688 
1689  driverMetadata.insert( QStringLiteral( "S57" ),
1691  QStringLiteral( "S-57 Base file" ),
1692  QObject::tr( "S-57 Base file" ),
1693  QStringLiteral( "*.000" ),
1694  QStringLiteral( "000" ),
1695  datasetOptions,
1696  layerOptions
1697  )
1698  );
1699 
1700  // Spatial Data Transfer Standard [SDTS]
1701  datasetOptions.clear();
1702  layerOptions.clear();
1703 
1704  driverMetadata.insert( QStringLiteral( "SDTS" ),
1706  QStringLiteral( "Spatial Data Transfer Standard [SDTS]" ),
1707  QObject::tr( "Spatial Data Transfer Standard [SDTS]" ),
1708  QStringLiteral( "*catd.ddf" ),
1709  QStringLiteral( "ddf" ),
1710  datasetOptions,
1711  layerOptions
1712  )
1713  );
1714 
1715  // SQLite
1716  datasetOptions.clear();
1717  layerOptions.clear();
1718 
1719  datasetOptions.insert( QStringLiteral( "METADATA" ), new QgsVectorFileWriter::BoolOption(
1720  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1721  "tables in a new database. By default these metadata tables are created "
1722  "when a new database is created." ),
1723  true // Default value
1724  ) );
1725 
1726  // Will handle the SpatiaLite alias
1727  datasetOptions.insert( QStringLiteral( "SPATIALITE" ), new QgsVectorFileWriter::HiddenOption(
1728  QStringLiteral( "NO" )
1729  ) );
1730 
1731 
1732  datasetOptions.insert( QStringLiteral( "INIT_WITH_EPSG" ), new QgsVectorFileWriter::HiddenOption(
1733  QStringLiteral( "NO" )
1734  ) );
1735 
1736  layerOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::SetOption(
1737  QObject::tr( "Controls the format used for the geometry column. Defaults to WKB. "
1738  "This is generally more space and processing efficient, but harder "
1739  "to inspect or use in simple applications than WKT (Well Known Text)." ),
1740  QStringList()
1741  << QStringLiteral( "WKB" )
1742  << QStringLiteral( "WKT" ),
1743  QStringLiteral( "WKB" ) // Default value
1744  ) );
1745 
1746  layerOptions.insert( QStringLiteral( "LAUNDER" ), new QgsVectorFileWriter::BoolOption(
1747  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1748  "in SQLite. Laundered names will be converted to lower case and some special "
1749  "characters(' - #) will be changed to underscores." ),
1750  true // Default value
1751  ) );
1752 
1753  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::HiddenOption(
1754  QStringLiteral( "NO" )
1755  ) );
1756 
1757  layerOptions.insert( QStringLiteral( "COMPRESS_GEOM" ), new QgsVectorFileWriter::HiddenOption(
1758  QStringLiteral( "NO" )
1759  ) );
1760 
1761  layerOptions.insert( QStringLiteral( "SRID" ), new QgsVectorFileWriter::HiddenOption(
1762  QString()
1763  ) );
1764 
1765  layerOptions.insert( QStringLiteral( "COMPRESS_COLUMNS" ), new QgsVectorFileWriter::StringOption(
1766  QObject::tr( "column_name1[,column_name2, …] A list of (String) columns that "
1767  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1768  "for databases that have big string blobs. However, use with care, since "
1769  "the value of such columns will be seen as compressed binary content with "
1770  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1771  "modifying or querying compressed columns, compression/decompression is "
1772  "done transparently. However, such columns cannot be (easily) queried with "
1773  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1774  "have the 'VARCHAR_deflate' declaration type." ),
1775  QString() // Default value
1776  ) );
1777 
1778  driverMetadata.insert( QStringLiteral( "SQLite" ),
1780  QStringLiteral( "SQLite" ),
1781  QObject::tr( "SQLite" ),
1782  QStringLiteral( "*.sqlite" ),
1783  QStringLiteral( "sqlite" ),
1784  datasetOptions,
1785  layerOptions,
1786  QStringLiteral( "UTF-8" )
1787  )
1788  );
1789 
1790  // SpatiaLite
1791  datasetOptions.clear();
1792  layerOptions.clear();
1793 
1794  datasetOptions.insert( QStringLiteral( "METADATA" ), new QgsVectorFileWriter::BoolOption(
1795  QObject::tr( "Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1796  "tables in a new database. By default these metadata tables are created "
1797  "when a new database is created." ),
1798  true // Default value
1799  ) );
1800 
1801  datasetOptions.insert( QStringLiteral( "SPATIALITE" ), new QgsVectorFileWriter::HiddenOption(
1802  QStringLiteral( "YES" )
1803  ) );
1804 
1805  datasetOptions.insert( QStringLiteral( "INIT_WITH_EPSG" ), new QgsVectorFileWriter::BoolOption(
1806  QObject::tr( "Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
1807  "Set to NO for regular SQLite databases." ),
1808  true // Default value
1809  ) );
1810 
1811  layerOptions.insert( QStringLiteral( "FORMAT" ), new QgsVectorFileWriter::HiddenOption(
1812  QStringLiteral( "SPATIALITE" )
1813  ) );
1814 
1815  layerOptions.insert( QStringLiteral( "LAUNDER" ), new QgsVectorFileWriter::BoolOption(
1816  QObject::tr( "Controls whether layer and field names will be laundered for easier use "
1817  "in SQLite. Laundered names will be converted to lower case and some special "
1818  "characters(' - #) will be changed to underscores." ),
1819  true // Default value
1820  ) );
1821 
1822  layerOptions.insert( QStringLiteral( "SPATIAL_INDEX" ), new QgsVectorFileWriter::BoolOption(
1823  QObject::tr( "If the database is of the SpatiaLite flavor, and if OGR is linked "
1824  "against libspatialite, this option can be used to control if a spatial "
1825  "index must be created." ),
1826  true // Default value
1827  ) );
1828 
1829  layerOptions.insert( QStringLiteral( "COMPRESS_GEOM" ), new QgsVectorFileWriter::BoolOption(
1830  QObject::tr( "If the format of the geometry BLOB is of the SpatiaLite flavor, "
1831  "this option can be used to control if the compressed format for "
1832  "geometries (LINESTRINGs, POLYGONs) must be used." ),
1833  false // Default value
1834  ) );
1835 
1836  layerOptions.insert( QStringLiteral( "SRID" ), new QgsVectorFileWriter::StringOption(
1837  QObject::tr( "Used to force the SRID number of the SRS associated with the layer. "
1838  "When this option isn't specified and that a SRS is associated with the "
1839  "layer, a search is made in the spatial_ref_sys to find a match for the "
1840  "SRS, and, if there is no match, a new entry is inserted for the SRS in "
1841  "the spatial_ref_sys table. When the SRID option is specified, this "
1842  "search (and the eventual insertion of a new entry) will not be done: "
1843  "the specified SRID is used as such." ),
1844  QString() // Default value
1845  ) );
1846 
1847  layerOptions.insert( QStringLiteral( "COMPRESS_COLUMNS" ), new QgsVectorFileWriter::StringOption(
1848  QObject::tr( "column_name1[,column_name2, …] A list of (String) columns that "
1849  "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1850  "for databases that have big string blobs. However, use with care, since "
1851  "the value of such columns will be seen as compressed binary content with "
1852  "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1853  "modifying or queryings compressed columns, compression/decompression is "
1854  "done transparently. However, such columns cannot be (easily) queried with "
1855  "an attribute filter or WHERE clause. Note: in table definition, such columns "
1856  "have the 'VARCHAR_deflate' declaration type." ),
1857  QString() // Default value
1858  ) );
1859 
1860  driverMetadata.insert( QStringLiteral( "SpatiaLite" ),
1862  QStringLiteral( "SpatiaLite" ),
1863  QObject::tr( "SpatiaLite" ),
1864  QStringLiteral( "*.sqlite" ),
1865  QStringLiteral( "sqlite" ),
1866  datasetOptions,
1867  layerOptions,
1868  QStringLiteral( "UTF-8" )
1869  )
1870  );
1871  // AutoCAD DXF
1872  datasetOptions.clear();
1873  layerOptions.clear();
1874 
1875  datasetOptions.insert( QStringLiteral( "HEADER" ), new QgsVectorFileWriter::StringOption(
1876  QObject::tr( "Override the header file used - in place of header.dxf." ),
1877  QString() // Default value
1878  ) );
1879 
1880  datasetOptions.insert( QStringLiteral( "TRAILER" ), new QgsVectorFileWriter::StringOption(
1881  QObject::tr( "Override the trailer file used - in place of trailer.dxf." ),
1882  QString() // Default value
1883  ) );
1884 
1885  driverMetadata.insert( QStringLiteral( "DXF" ),
1887  QStringLiteral( "AutoCAD DXF" ),
1888  QObject::tr( "AutoCAD DXF" ),
1889  QStringLiteral( "*.dxf" ),
1890  QStringLiteral( "dxf" ),
1891  datasetOptions,
1892  layerOptions
1893  )
1894  );
1895 
1896  // Geoconcept
1897  datasetOptions.clear();
1898  layerOptions.clear();
1899 
1900  datasetOptions.insert( QStringLiteral( "EXTENSION" ), new QgsVectorFileWriter::SetOption(
1901  QObject::tr( "Indicates the GeoConcept export file extension. "
1902  "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
1903  QStringList()
1904  << QStringLiteral( "GXT" )
1905  << QStringLiteral( "TXT" ),
1906  QStringLiteral( "GXT" ) // Default value
1907  ) );
1908 
1909  datasetOptions.insert( QStringLiteral( "CONFIG" ), new QgsVectorFileWriter::StringOption(
1910  QObject::tr( "Path to the GCT: the GCT file describes the GeoConcept types definitions: "
1911  "In this file, every line must start with //# followed by a keyword. "
1912  "Lines starting with // are comments." ),
1913  QString() // Default value
1914  ) );
1915 
1916  datasetOptions.insert( QStringLiteral( "FEATURETYPE" ), new QgsVectorFileWriter::StringOption(
1917  QObject::tr( "Defines the feature to be created. The TYPE corresponds to one of the Name "
1918  "found in the GCT file for a type section. The SUBTYPE corresponds to one of "
1919  "the Name found in the GCT file for a sub-type section within the previous "
1920  "type section." ),
1921  QString() // Default value
1922  ) );
1923 
1924  driverMetadata.insert( QStringLiteral( "Geoconcept" ),
1926  QStringLiteral( "Geoconcept" ),
1927  QObject::tr( "Geoconcept" ),
1928  QStringLiteral( "*.gxt *.txt" ),
1929  QStringLiteral( "gxt" ),
1930  datasetOptions,
1931  layerOptions
1932  )
1933  );
1934 
1935  // ESRI FileGDB
1936  datasetOptions.clear();
1937  layerOptions.clear();
1938 
1939  layerOptions.insert( QStringLiteral( "FEATURE_DATASET" ), new QgsVectorFileWriter::StringOption(
1940  QObject::tr( "When this option is set, the new layer will be created inside the named "
1941  "FeatureDataset folder. If the folder does not already exist, it will be created." ),
1942  QString() // Default value
1943  ) );
1944 
1945  layerOptions.insert( QStringLiteral( "GEOMETRY_NAME" ), new QgsVectorFileWriter::StringOption(
1946  QObject::tr( "Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
1947  QStringLiteral( "SHAPE" ) // Default value
1948  ) );
1949 
1950  layerOptions.insert( QStringLiteral( "FID" ), new QgsVectorFileWriter::StringOption(
1951  QObject::tr( "Name of the OID column to create. Defaults to 'OBJECTID'." ),
1952  QStringLiteral( "OBJECTID" ) // Default value
1953  ) );
1954 
1955  driverMetadata.insert( QStringLiteral( "FileGDB" ),
1957  QStringLiteral( "ESRI FileGDB" ),
1958  QObject::tr( "ESRI FileGDB" ),
1959  QStringLiteral( "*.gdb" ),
1960  QStringLiteral( "gdb" ),
1961  datasetOptions,
1962  layerOptions,
1963  QStringLiteral( "UTF-8" )
1964  )
1965  );
1966 
1967  // XLSX
1968  datasetOptions.clear();
1969  layerOptions.clear();
1970 
1971  layerOptions.insert( QStringLiteral( "OGR_XLSX_FIELD_TYPES" ), new QgsVectorFileWriter::SetOption(
1972  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
1973  "to STRING, all fields will be of String type." ),
1974  QStringList()
1975  << QStringLiteral( "AUTO" )
1976  << QStringLiteral( "STRING" ),
1977  QStringLiteral( "AUTO" ), // Default value
1978  false // Allow None
1979  ) );
1980 
1981  layerOptions.insert( QStringLiteral( "OGR_XLSX_HEADERS" ), new QgsVectorFileWriter::SetOption(
1982  QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
1983  "if the first line might be the name of columns. If set to FORCE, the driver "
1984  "will consider the first line as the header line. If set to "
1985  "DISABLE, it will be considered as the first feature. Otherwise "
1986  "auto-detection will occur." ),
1987  QStringList()
1988  << QStringLiteral( "FORCE" )
1989  << QStringLiteral( "DISABLE" )
1990  << QStringLiteral( "AUTO" ),
1991  QStringLiteral( "AUTO" ), // Default value
1992  false // Allow None
1993  ) );
1994 
1995  driverMetadata.insert( QStringLiteral( "XLSX" ),
1997  QStringLiteral( "MS Office Open XML spreadsheet" ),
1998  QObject::tr( "MS Office Open XML spreadsheet [XLSX]" ),
1999  QStringLiteral( "*.xlsx" ),
2000  QStringLiteral( "xlsx" ),
2001  datasetOptions,
2002  layerOptions,
2003  QStringLiteral( "UTF-8" )
2004  )
2005  );
2006 
2007  // ODS
2008  datasetOptions.clear();
2009  layerOptions.clear();
2010 
2011  layerOptions.insert( QStringLiteral( "OGR_ODS_FIELD_TYPES" ), new QgsVectorFileWriter::SetOption(
2012  QObject::tr( "By default, the driver will try to detect the data type of fields. If set "
2013  "to STRING, all fields will be of String type." ),
2014  QStringList()
2015  << QStringLiteral( "AUTO" )
2016  << QStringLiteral( "STRING" ),
2017  QStringLiteral( "AUTO" ), // Default value
2018  false // Allow None
2019  ) );
2020 
2021  layerOptions.insert( QStringLiteral( "OGR_ODS_HEADERS" ), new QgsVectorFileWriter::SetOption(
2022  QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
2023  "if the first line might be the name of columns. If set to FORCE, the driver "
2024  "will consider the first line as the header line. If set to "
2025  "DISABLE, it will be considered as the first feature. Otherwise "
2026  "auto-detection will occur." ),
2027  QStringList()
2028  << QStringLiteral( "FORCE" )
2029  << QStringLiteral( "DISABLE" )
2030  << QStringLiteral( "AUTO" ),
2031  QStringLiteral( "AUTO" ), // Default value
2032  false // Allow None
2033  ) );
2034 
2035  driverMetadata.insert( QStringLiteral( "ODS" ),
2037  QStringLiteral( "Open Document Spreadsheet" ),
2038  QObject::tr( "Open Document Spreadsheet [ODS]" ),
2039  QStringLiteral( "*.ods" ),
2040  QStringLiteral( "ods" ),
2041  datasetOptions,
2042  layerOptions,
2043  QStringLiteral( "UTF-8" )
2044  )
2045  );
2046  }
2047 
2048  QgsVectorFileWriterMetadataContainer( const QgsVectorFileWriterMetadataContainer &other ) = delete;
2049  QgsVectorFileWriterMetadataContainer &operator=( const QgsVectorFileWriterMetadataContainer &other ) = delete;
2050  ~QgsVectorFileWriterMetadataContainer()
2051  {
2052  for ( auto it = driverMetadata.constBegin(); it != driverMetadata.constEnd(); ++it )
2053  {
2054  for ( auto optionIt = it.value().driverOptions.constBegin(); optionIt != it.value().driverOptions.constEnd(); ++optionIt )
2055  delete optionIt.value();
2056  for ( auto optionIt = it.value().layerOptions.constBegin(); optionIt != it.value().layerOptions.constEnd(); ++optionIt )
2057  delete optionIt.value();
2058  }
2059  }
2060 
2061  QMap<QString, QgsVectorFileWriter::MetaData> driverMetadata;
2062 
2063 };
2065 
2067 {
2068  static QgsVectorFileWriterMetadataContainer sDriverMetadata;
2069  QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.driverMetadata.constBegin();
2070 
2071  for ( ; it != sDriverMetadata.driverMetadata.constEnd(); ++it )
2072  {
2073  if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
2074  {
2075  driverMetadata = it.value();
2076  return true;
2077  }
2078  }
2079 
2080  return false;
2081 }
2082 
2083 QStringList QgsVectorFileWriter::defaultDatasetOptions( const QString &driverName )
2084 {
2085  MetaData metadata;
2086  bool ok = driverMetadata( driverName, metadata );
2087  if ( !ok )
2088  return QStringList();
2089  return concatenateOptions( metadata.driverOptions );
2090 }
2091 
2092 QStringList QgsVectorFileWriter::defaultLayerOptions( const QString &driverName )
2093 {
2094  MetaData metadata;
2095  bool ok = driverMetadata( driverName, metadata );
2096  if ( !ok )
2097  return QStringList();
2098  return concatenateOptions( metadata.layerOptions );
2099 }
2100 
2102 {
2103 
2104  OGRwkbGeometryType ogrType = static_cast<OGRwkbGeometryType>( type );
2105 
2106  if ( type >= QgsWkbTypes::PointZ && type <= QgsWkbTypes::GeometryCollectionZ )
2107  {
2108  ogrType = static_cast<OGRwkbGeometryType>( QgsWkbTypes::to25D( type ) );
2109  }
2110  return ogrType;
2111 }
2112 
2114 {
2115  return mError;
2116 }
2117 
2119 {
2120  return mErrorMessage;
2121 }
2122 
2123 bool QgsVectorFileWriter::addFeature( QgsFeature &feature, QgsFeatureSink::Flags )
2124 {
2125  return addFeatureWithStyle( feature, nullptr, QgsUnitTypes::DistanceMeters );
2126 }
2127 
2128 bool QgsVectorFileWriter::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags )
2129 {
2130  QgsFeatureList::iterator fIt = features.begin();
2131  bool result = true;
2132  for ( ; fIt != features.end(); ++fIt )
2133  {
2134  result = result && addFeatureWithStyle( *fIt, nullptr, QgsUnitTypes::DistanceMeters );
2135  }
2136  return result;
2137 }
2138 
2140 {
2141  // create the feature
2142  gdal::ogr_feature_unique_ptr poFeature = createFeature( feature );
2143  if ( !poFeature )
2144  return false;
2145 
2146  //add OGR feature style type
2147  if ( mSymbologyExport != NoSymbology && renderer )
2148  {
2149  mRenderContext.expressionContext().setFeature( feature );
2150  //SymbolLayerSymbology: concatenate ogr styles of all symbollayers
2151  QgsSymbolList symbols = renderer->symbolsForFeature( feature, mRenderContext );
2152  QString styleString;
2153  QString currentStyle;
2154 
2155  QgsSymbolList::const_iterator symbolIt = symbols.constBegin();
2156  for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
2157  {
2158  int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
2159  for ( int i = 0; i < nSymbolLayers; ++i )
2160  {
2161 #if 0
2162  QMap< QgsSymbolLayer *, QString >::const_iterator it = mSymbolLayerTable.find( ( *symbolIt )->symbolLayer( i ) );
2163  if ( it == mSymbolLayerTable.constEnd() )
2164  {
2165  continue;
2166  }
2167 #endif
2168  double mmsf = mmScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2169  double musf = mapUnitScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2170 
2171  currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );//"@" + it.value();
2172 
2174  {
2175  if ( symbolIt != symbols.constBegin() || i != 0 )
2176  {
2177  styleString.append( ';' );
2178  }
2179  styleString.append( currentStyle );
2180  }
2181  else if ( mSymbologyExport == SymbolLayerSymbology )
2182  {
2183  OGR_F_SetStyleString( poFeature.get(), currentStyle.toLocal8Bit().constData() );
2184  if ( !writeFeature( mLayer, poFeature.get() ) )
2185  {
2186  return false;
2187  }
2188  }
2189  }
2190  }
2191  OGR_F_SetStyleString( poFeature.get(), styleString.toLocal8Bit().constData() );
2192  }
2193 
2195  {
2196  if ( !writeFeature( mLayer, poFeature.get() ) )
2197  {
2198  return false;
2199  }
2200  }
2201 
2202  return true;
2203 }
2204 
2205 gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeature &feature )
2206 {
2207  QgsLocaleNumC l; // Make sure the decimal delimiter is a dot
2208  Q_UNUSED( l )
2209 
2210  gdal::ogr_feature_unique_ptr poFeature( OGR_F_Create( OGR_L_GetLayerDefn( mLayer ) ) );
2211 
2212  qint64 fid = FID_TO_NUMBER( feature.id() );
2213  if ( fid > std::numeric_limits<int>::max() )
2214  {
2215  QgsDebugMsg( QStringLiteral( "feature id %1 too large." ).arg( fid ) );
2216  OGRErr err = OGR_F_SetFID( poFeature.get(), static_cast<long>( fid ) );
2217  if ( err != OGRERR_NONE )
2218  {
2219  QgsDebugMsg( QStringLiteral( "Failed to set feature id to %1: %2 (OGR error: %3)" )
2220  .arg( feature.id() )
2221  .arg( err ).arg( CPLGetLastErrorMsg() )
2222  );
2223  }
2224  }
2225 
2226  // attribute handling
2227  for ( QMap<int, int>::const_iterator it = mAttrIdxToOgrIdx.constBegin(); it != mAttrIdxToOgrIdx.constEnd(); ++it )
2228  {
2229  int fldIdx = it.key();
2230  int ogrField = it.value();
2231 
2232  QVariant attrValue = feature.attribute( fldIdx );
2233  QgsField field = mFields.at( fldIdx );
2234 
2235  if ( !attrValue.isValid() || attrValue.isNull() )
2236  {
2237 // Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
2238 // whereas previously there was only unset fields. For a GeoJSON output,
2239 // leaving a field unset will cause it to not appear at all in the output
2240 // feature.
2241 // When all features of a layer have a field unset, this would cause the
2242 // field to not be present at all in the output, and thus on reading to
2243 // have disappeared. #16812
2244 #ifdef OGRNullMarker
2245  OGR_F_SetFieldNull( poFeature.get(), ogrField );
2246 #endif
2247  continue;
2248  }
2249 
2250  if ( mFieldValueConverter )
2251  {
2252  field = mFieldValueConverter->fieldDefinition( field );
2253  attrValue = mFieldValueConverter->convert( fldIdx, attrValue );
2254  }
2255 
2256  switch ( field.type() )
2257  {
2258  case QVariant::Int:
2259  OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2260  break;
2261  case QVariant::LongLong:
2262  OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
2263  break;
2264  case QVariant::Bool:
2265  OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2266  break;
2267  case QVariant::String:
2268  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toString() ).constData() );
2269  break;
2270  case QVariant::Double:
2271  OGR_F_SetFieldDouble( poFeature.get(), ogrField, attrValue.toDouble() );
2272  break;
2273  case QVariant::Date:
2274  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2275  attrValue.toDate().year(),
2276  attrValue.toDate().month(),
2277  attrValue.toDate().day(),
2278  0, 0, 0, 0 );
2279  break;
2280  case QVariant::DateTime:
2281  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
2282  {
2283  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toDateTime().toString( QStringLiteral( "yyyy/MM/dd hh:mm:ss.zzz" ) ) ).constData() );
2284  }
2285  else
2286  {
2287  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2288  attrValue.toDateTime().date().year(),
2289  attrValue.toDateTime().date().month(),
2290  attrValue.toDateTime().date().day(),
2291  attrValue.toDateTime().time().hour(),
2292  attrValue.toDateTime().time().minute(),
2293  attrValue.toDateTime().time().second(),
2294  0 );
2295  }
2296  break;
2297  case QVariant::Time:
2298  if ( mOgrDriverName == QLatin1String( "ESRI Shapefile" ) )
2299  {
2300  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toString() ).constData() );
2301  }
2302  else
2303  {
2304  OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2305  0, 0, 0,
2306  attrValue.toTime().hour(),
2307  attrValue.toTime().minute(),
2308  attrValue.toTime().second(),
2309  0 );
2310  }
2311  break;
2312 
2313  case QVariant::ByteArray:
2314  {
2315  const QByteArray ba = attrValue.toByteArray();
2316  OGR_F_SetFieldBinary( poFeature.get(), ogrField, ba.size(), const_cast< GByte * >( reinterpret_cast< const GByte * >( ba.data() ) ) );
2317  break;
2318  }
2319 
2320  case QVariant::Invalid:
2321  break;
2322 
2323 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,4,0)
2324  case QVariant::List:
2325  // only string list supported at the moment, fall through to default for other types
2326  if ( field.subType() == QVariant::String )
2327  {
2328  QStringList list = attrValue.toStringList();
2329  if ( supportsStringList )
2330  {
2331  int count = list.count();
2332  char **lst = new char *[count + 1];
2333  if ( count > 0 )
2334  {
2335  int pos = 0;
2336  for ( QString string : list )
2337  {
2338  lst[pos] = mCodec->fromUnicode( string ).data();
2339  pos++;
2340  }
2341  }
2342  lst[count] = nullptr;
2343  OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
2344  }
2345  else
2346  {
2347  OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( list.join( ',' ) ).constData() );
2348  }
2349  break;
2350  }
2351  //intentional fall-through
2352  FALLTHROUGH
2353 #endif
2354 
2355  default:
2356  mErrorMessage = QObject::tr( "Invalid variant type for field %1[%2]: received %3 with type %4" )
2357  .arg( mFields.at( fldIdx ).name() )
2358  .arg( ogrField )
2359  .arg( attrValue.typeName(),
2360  attrValue.toString() );
2361  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2363  return nullptr;
2364  }
2365  }
2366 
2368  {
2369  if ( feature.hasGeometry() )
2370  {
2371  // build geometry from WKB
2372  QgsGeometry geom = feature.geometry();
2373 
2374  // turn single geometry to multi geometry if needed
2377  {
2378  geom.convertToMultiType();
2379  }
2380 
2381  if ( geom.wkbType() != mWkbType )
2382  {
2383  OGRGeometryH mGeom2 = nullptr;
2384 
2385  // If requested WKB type is 25D and geometry WKB type is 3D,
2386  // we must force the use of 25D.
2388  {
2389  //ND: I suspect there's a bug here, in that this is NOT converting the geometry's WKB type,
2390  //so the exported WKB has a different type to what the OGRGeometry is expecting.
2391  //possibly this is handled already in OGR, but it should be fixed regardless by actually converting
2392  //geom to the correct WKB type
2393  QgsWkbTypes::Type wkbType = geom.wkbType();
2394  if ( wkbType >= QgsWkbTypes::PointZ && wkbType <= QgsWkbTypes::MultiPolygonZ )
2395  {
2397  mGeom2 = createEmptyGeometry( wkbType25d );
2398  }
2399  }
2400 
2401  // drop m/z value if not present in output wkb type
2402  if ( !QgsWkbTypes::hasZ( mWkbType ) && QgsWkbTypes::hasZ( geom.wkbType() ) )
2403  geom.get()->dropZValue();
2404  if ( !QgsWkbTypes::hasM( mWkbType ) && QgsWkbTypes::hasM( geom.wkbType() ) )
2405  geom.get()->dropMValue();
2406 
2407  // add m/z values if not present in the input wkb type -- this is needed for formats which determine
2408  // geometry type based on features, e.g. geojson
2409  if ( QgsWkbTypes::hasZ( mWkbType ) && !QgsWkbTypes::hasZ( geom.wkbType() ) )
2410  geom.get()->addZValue( 0 );
2411  if ( QgsWkbTypes::hasM( mWkbType ) && !QgsWkbTypes::hasM( geom.wkbType() ) )
2412  geom.get()->addMValue( 0 );
2413 
2414  if ( !mGeom2 )
2415  {
2416  // there's a problem when layer type is set as wkbtype Polygon
2417  // although there are also features of type MultiPolygon
2418  // (at least in OGR provider)
2419  // If the feature's wkbtype is different from the layer's wkbtype,
2420  // try to export it too.
2421  //
2422  // Btw. OGRGeometry must be exactly of the type of the geometry which it will receive
2423  // i.e. Polygons can't be imported to OGRMultiPolygon
2424  mGeom2 = createEmptyGeometry( geom.wkbType() );
2425  }
2426 
2427  if ( !mGeom2 )
2428  {
2429  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2430  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2432  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2433  return nullptr;
2434  }
2435 
2436  QByteArray wkb( geom.asWkb() );
2437  OGRErr err = OGR_G_ImportFromWkb( mGeom2, reinterpret_cast<unsigned char *>( const_cast<char *>( wkb.constData() ) ), wkb.length() );
2438  if ( err != OGRERR_NONE )
2439  {
2440  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2441  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2443  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2444  return nullptr;
2445  }
2446 
2447  // pass ownership to geometry
2448  OGR_F_SetGeometryDirectly( poFeature.get(), mGeom2 );
2449  }
2450  else // wkb type matches
2451  {
2452  QByteArray wkb( geom.asWkb() );
2453  OGRGeometryH ogrGeom = createEmptyGeometry( mWkbType );
2454  OGRErr err = OGR_G_ImportFromWkb( ogrGeom, reinterpret_cast<unsigned char *>( const_cast<char *>( wkb.constData() ) ), wkb.length() );
2455  if ( err != OGRERR_NONE )
2456  {
2457  mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
2458  .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2460  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2461  return nullptr;
2462  }
2463 
2464  // set geometry (ownership is passed to OGR)
2465  OGR_F_SetGeometryDirectly( poFeature.get(), ogrGeom );
2466  }
2467  }
2468  else
2469  {
2470  OGR_F_SetGeometryDirectly( poFeature.get(), createEmptyGeometry( mWkbType ) );
2471  }
2472  }
2473  return poFeature;
2474 }
2475 
2476 void QgsVectorFileWriter::resetMap( const QgsAttributeList &attributes )
2477 {
2478  QMap<int, int> omap( mAttrIdxToOgrIdx );
2479  mAttrIdxToOgrIdx.clear();
2480  for ( int i = 0; i < attributes.size(); i++ )
2481  {
2482  if ( omap.find( i ) != omap.end() )
2483  mAttrIdxToOgrIdx.insert( attributes[i], omap[i] );
2484  }
2485 }
2486 
2487 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
2488 {
2489  if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
2490  {
2491  mErrorMessage = QObject::tr( "Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2493  QgsMessageLog::logMessage( mErrorMessage, QObject::tr( "OGR" ) );
2494  return false;
2495  }
2496  return true;
2497 }
2498 
2500 {
2501  if ( mUsingTransaction )
2502  {
2503  if ( OGRERR_NONE != OGR_L_CommitTransaction( mLayer ) )
2504  {
2505  QgsDebugMsg( QStringLiteral( "Error while committing transaction on OGRLayer." ) );
2506  }
2507  }
2508 
2509  mDS.reset();
2510 
2511  if ( mOgrRef )
2512  {
2513  OSRDestroySpatialReference( mOgrRef );
2514  }
2515 }
2516 
2519  const QString &fileName,
2520  const QString &fileEncoding,
2521  const QgsCoordinateReferenceSystem &destCRS,
2522  const QString &driverName,
2523  bool onlySelected,
2524  QString *errorMessage,
2525  const QStringList &datasourceOptions,
2526  const QStringList &layerOptions,
2527  bool skipAttributeCreation,
2528  QString *newFilename,
2530  double symbologyScale,
2531  const QgsRectangle *filterExtent,
2532  QgsWkbTypes::Type overrideGeometryType,
2533  bool forceMulti,
2534  bool includeZ,
2535  const QgsAttributeList &attributes,
2536  FieldValueConverter *fieldValueConverter,
2537  QString *newLayer )
2538 {
2540  if ( destCRS.isValid() && layer )
2541  {
2542  ct = QgsCoordinateTransform( layer->crs(), destCRS, layer->transformContext() );
2543  }
2544 
2545  QgsVectorFileWriter::WriterError error = writeAsVectorFormat( layer, fileName, fileEncoding, ct, driverName, onlySelected,
2546  errorMessage, datasourceOptions, layerOptions, skipAttributeCreation,
2547  newFilename, symbologyExport, symbologyScale, filterExtent,
2548  overrideGeometryType, forceMulti, includeZ, attributes,
2549  fieldValueConverter, newLayer );
2550  return error;
2551 }
2552 
2554  const QString &fileName,
2555  const QString &fileEncoding,
2556  const QgsCoordinateTransform &ct,
2557  const QString &driverName,
2558  bool onlySelected,
2559  QString *errorMessage,
2560  const QStringList &datasourceOptions,
2561  const QStringList &layerOptions,
2562  bool skipAttributeCreation,
2563  QString *newFilename,
2565  double symbologyScale,
2566  const QgsRectangle *filterExtent,
2567  QgsWkbTypes::Type overrideGeometryType,
2568  bool forceMulti,
2569  bool includeZ,
2570  const QgsAttributeList &attributes,
2571  FieldValueConverter *fieldValueConverter,
2572  QString *newLayer )
2573 {
2574  SaveVectorOptions options;
2575  options.fileEncoding = fileEncoding;
2576  options.ct = ct;
2577  options.driverName = driverName;
2578  options.onlySelectedFeatures = onlySelected;
2579  options.datasourceOptions = datasourceOptions;
2580  options.layerOptions = layerOptions;
2581  options.skipAttributeCreation = skipAttributeCreation;
2582  options.symbologyExport = symbologyExport;
2583  options.symbologyScale = symbologyScale;
2584  if ( filterExtent )
2585  options.filterExtent = *filterExtent;
2586  options.overrideGeometryType = overrideGeometryType;
2587  options.forceMulti = forceMulti;
2588  options.includeZ = includeZ;
2589  options.attributes = attributes;
2590  options.fieldValueConverter = fieldValueConverter;
2591  return writeAsVectorFormat( layer, fileName, options, newFilename, errorMessage, newLayer );
2592 }
2593 
2594 
2596  : driverName( QStringLiteral( "GPKG" ) )
2597 {
2598 }
2599 
2600 
2601 
2602 QgsVectorFileWriter::WriterError QgsVectorFileWriter::prepareWriteAsVectorFormat( QgsVectorLayer *layer, const QgsVectorFileWriter::SaveVectorOptions &options, QgsVectorFileWriter::PreparedWriterDetails &details )
2603 {
2604  if ( !layer || !layer->isValid() )
2605  {
2606  return ErrInvalidLayer;
2607  }
2608 
2609 
2610  if ( layer->renderer() )
2611  details.renderer.reset( layer->renderer()->clone() );
2612  details.sourceCrs = layer->crs();
2613  details.sourceWkbType = layer->wkbType();
2614  details.sourceFields = layer->fields();
2615  details.providerType = layer->providerType();
2616  details.featureCount = options.onlySelectedFeatures ? layer->selectedFeatureCount() : layer->featureCount();
2617  if ( layer->dataProvider() )
2618  details.dataSourceUri = layer->dataProvider()->dataSourceUri();
2619  details.storageType = layer->storageType();
2620  details.selectedFeatureIds = layer->selectedFeatureIds();
2621  details.providerUriParams = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
2622 
2623  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) )
2624  {
2625  QgsFeatureRequest req;
2626  if ( options.onlySelectedFeatures )
2627  {
2628  req.setFilterFids( details.selectedFeatureIds );
2629  }
2630  req.setNoAttributes();
2631  details.geometryTypeScanIterator = layer->getFeatures( req );
2632  }
2633 
2634  details.expressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
2635  details.renderContext.setExpressionContext( details.expressionContext );
2636  details.renderContext.setRendererScale( options.symbologyScale );
2637 
2638  details.shallTransform = false;
2639  if ( options.ct.isValid() )
2640  {
2641  // This means we should transform
2642  details.outputCrs = options.ct.destinationCrs();
2643  details.shallTransform = true;
2644  }
2645  else
2646  {
2647  // This means we shouldn't transform, use source CRS as output (if defined)
2648  details.outputCrs = details.sourceCrs;
2649  }
2650 
2651  details.destWkbType = details.sourceWkbType;
2652  if ( options.overrideGeometryType != QgsWkbTypes::Unknown )
2653  {
2654  details.destWkbType = QgsWkbTypes::flatType( options.overrideGeometryType );
2655  if ( QgsWkbTypes::hasZ( options.overrideGeometryType ) || options.includeZ )
2656  details.destWkbType = QgsWkbTypes::addZ( details.destWkbType );
2657  }
2658  if ( options.forceMulti )
2659  {
2660  details.destWkbType = QgsWkbTypes::multiType( details.destWkbType );
2661  }
2662 
2663  details.attributes = options.attributes;
2664  if ( options.skipAttributeCreation )
2665  details.attributes.clear();
2666  else if ( details.attributes.isEmpty() )
2667  {
2668  const QgsAttributeList allAttributes = details.sourceFields.allAttributesList();
2669  for ( int idx : allAttributes )
2670  {
2671  QgsField fld = details.sourceFields.at( idx );
2672  if ( details.providerType == QLatin1String( "oracle" ) && fld.typeName().contains( QLatin1String( "SDO_GEOMETRY" ) ) )
2673  continue;
2674  details.attributes.append( idx );
2675  }
2676  }
2677 
2678  if ( !details.attributes.isEmpty() )
2679  {
2680  for ( int attrIdx : qgis::as_const( details.attributes ) )
2681  {
2682  details.outputFields.append( details.sourceFields.at( attrIdx ) );
2683  }
2684  }
2685 
2686  // not ideal - would be nice to avoid this happening in the preparation step if possible,
2687  // but currently requires access to the layer's minimumValue/maximumValue methods
2688  if ( details.providerType == QLatin1String( "spatialite" ) )
2689  {
2690  for ( int i = 0; i < details.outputFields.size(); i++ )
2691  {
2692  if ( details.outputFields.at( i ).type() == QVariant::LongLong )
2693  {
2694  QVariant min = layer->minimumValue( i );
2695  QVariant max = layer->maximumValue( i );
2696  if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < std::numeric_limits<int>::max() )
2697  {
2698  details.outputFields[i].setType( QVariant::Int );
2699  }
2700  }
2701  }
2702  }
2703 
2704 
2705  //add possible attributes needed by renderer
2706  addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
2707 
2708  QgsFeatureRequest req;
2709  req.setSubsetOfAttributes( details.attributes );
2710  if ( options.onlySelectedFeatures )
2711  req.setFilterFids( details.selectedFeatureIds );
2712 
2713  if ( !options.filterExtent.isNull() )
2714  {
2715  QgsRectangle filterRect = options.filterExtent;
2716  bool useFilterRect = true;
2717  if ( details.shallTransform )
2718  {
2719  try
2720  {
2721  // map filter rect back from destination CRS to layer CRS
2722  filterRect = options.ct.transformBoundingBox( filterRect, QgsCoordinateTransform::ReverseTransform );
2723  }
2724  catch ( QgsCsException & )
2725  {
2726  useFilterRect = false;
2727  }
2728  }
2729  if ( useFilterRect )
2730  {
2731  req.setFilterRect( filterRect );
2732  }
2733  details.filterRectGeometry = QgsGeometry::fromRect( options.filterExtent );
2734  details.filterRectEngine.reset( QgsGeometry::createGeometryEngine( details.filterRectGeometry.constGet() ) );
2735  details.filterRectEngine->prepareGeometry();
2736  }
2737  details.sourceFeatureIterator = layer->getFeatures( req );
2738 
2739  return NoError;
2740 }
2741 
2742 QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( PreparedWriterDetails &details, const QString &fileName, const QgsVectorFileWriter::SaveVectorOptions &options, QString *newFilename, QString *errorMessage, QString *newLayer )
2743 {
2744 
2745  QgsWkbTypes::Type destWkbType = details.destWkbType;
2746 
2747  int lastProgressReport = 0;
2748  long total = details.featureCount;
2749 
2750  // Special rules for OGR layers
2751  if ( details.providerType == QLatin1String( "ogr" ) && !details.dataSourceUri.isEmpty() )
2752  {
2753  QString srcFileName( details.providerUriParams.value( QLatin1String( "path" ) ).toString() );
2754  if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2755  {
2756  // Check the layer name too if it's a GPKG/SpatiaLite/SQLite OGR driver (pay attention: camel case in layerName)
2757  QgsDataSourceUri uri( details.dataSourceUri );
2758  if ( !( ( options.driverName == QLatin1String( "GPKG" ) ||
2759  options.driverName == QLatin1String( "SpatiaLite" ) ||
2760  options.driverName == QLatin1String( "SQLite" ) ) &&
2761  options.layerName != details.providerUriParams.value( QLatin1String( "layerName" ) ) ) )
2762  {
2763  if ( errorMessage )
2764  *errorMessage = QObject::tr( "Cannot overwrite a OGR layer in place" );
2765  return ErrCreateDataSource;
2766  }
2767  }
2768 
2769  // Shapefiles might contain multi types although wkbType() only reports singles
2770  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) && !QgsWkbTypes::isMultiType( destWkbType ) )
2771  {
2772  QgsFeatureIterator fit = details.geometryTypeScanIterator;
2773  QgsFeature fet;
2774  long scanned = 0;
2775  while ( fit.nextFeature( fet ) )
2776  {
2777  if ( options.feedback && options.feedback->isCanceled() )
2778  {
2779  return Canceled;
2780  }
2781  if ( options.feedback )
2782  {
2783  //dedicate first 5% of progress bar to this scan
2784  int newProgress = static_cast<int>( ( 5.0 * scanned ) / total );
2785  if ( newProgress != lastProgressReport )
2786  {
2787  lastProgressReport = newProgress;
2788  options.feedback->setProgress( lastProgressReport );
2789  }
2790  }
2791 
2792  if ( fet.hasGeometry() && QgsWkbTypes::isMultiType( fet.geometry().wkbType() ) )
2793  {
2794  destWkbType = QgsWkbTypes::multiType( destWkbType );
2795  break;
2796  }
2797  scanned++;
2798  }
2799  }
2800  }
2801 
2802  std::unique_ptr< QgsVectorFileWriter > writer =
2803  qgis::make_unique< QgsVectorFileWriter >( fileName,
2804  options.fileEncoding, details.outputFields, destWkbType,
2805  details.outputCrs, options.driverName,
2806  options.datasourceOptions,
2807  options.layerOptions,
2808  newFilename,
2809  options.symbologyExport,
2810  options.fieldValueConverter,
2811  options.layerName,
2812  options.actionOnExistingFile,
2813  newLayer );
2814  writer->setSymbologyScale( options.symbologyScale );
2815 
2816  if ( newFilename )
2817  {
2818  QgsDebugMsg( "newFilename = " + *newFilename );
2819  }
2820 
2821  // check whether file creation was successful
2822  WriterError err = writer->hasError();
2823  if ( err != NoError )
2824  {
2825  if ( errorMessage )
2826  *errorMessage = writer->errorMessage();
2827  return err;
2828  }
2829 
2830  if ( errorMessage )
2831  {
2832  errorMessage->clear();
2833  }
2834 
2835  QgsFeature fet;
2836 
2837  //create symbol table if needed
2838  if ( writer->symbologyExport() != NoSymbology )
2839  {
2840  //writer->createSymbolLayerTable( layer, writer->mDS );
2841  }
2842 
2843  if ( writer->symbologyExport() == SymbolLayerSymbology )
2844  {
2845  QgsFeatureRenderer *r = details.renderer.get();
2847  && r->usingSymbolLevels() )
2848  {
2849  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( details, details.sourceFeatureIterator, options.ct, errorMessage );
2850  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
2851  }
2852  }
2853 
2854  int n = 0, errors = 0;
2855 
2856  //unit type
2857  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
2858  if ( options.ct.isValid() )
2859  {
2860  mapUnits = options.ct.destinationCrs().mapUnits();
2861  }
2862 
2863  writer->startRender( details.renderer.get(), details.sourceFields );
2864 
2865  writer->resetMap( details.attributes );
2866  // Reset mFields to layer fields, and not just exported fields
2867  writer->mFields = details.sourceFields;
2868 
2869  // write all features
2870  long saved = 0;
2871  int initialProgress = lastProgressReport;
2872  while ( details.sourceFeatureIterator.nextFeature( fet ) )
2873  {
2874  if ( options.feedback && options.feedback->isCanceled() )
2875  {
2876  return Canceled;
2877  }
2878 
2879  saved++;
2880  if ( options.feedback )
2881  {
2882  //avoid spamming progress reports
2883  int newProgress = static_cast<int>( initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total );
2884  if ( newProgress < 100 && newProgress != lastProgressReport )
2885  {
2886  lastProgressReport = newProgress;
2887  options.feedback->setProgress( lastProgressReport );
2888  }
2889  }
2890 
2891  if ( details.shallTransform )
2892  {
2893  try
2894  {
2895  if ( fet.hasGeometry() )
2896  {
2897  QgsGeometry g = fet.geometry();
2898  g.transform( options.ct );
2899  fet.setGeometry( g );
2900  }
2901  }
2902  catch ( QgsCsException &e )
2903  {
2904  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
2905  .arg( fet.id() ).arg( e.what() );
2906  QgsLogger::warning( msg );
2907  if ( errorMessage )
2908  *errorMessage = msg;
2909 
2910  return ErrProjection;
2911  }
2912  }
2913 
2914  if ( fet.hasGeometry() && details.filterRectEngine && !details.filterRectEngine->intersects( fet.geometry().constGet() ) )
2915  continue;
2916 
2917  if ( details.attributes.empty() && options.skipAttributeCreation )
2918  {
2919  fet.initAttributes( 0 );
2920  }
2921 
2922  if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
2923  {
2924  WriterError err = writer->hasError();
2925  if ( err != NoError && errorMessage )
2926  {
2927  if ( errorMessage->isEmpty() )
2928  {
2929  *errorMessage = QObject::tr( "Feature write errors:" );
2930  }
2931  *errorMessage += '\n' + writer->errorMessage();
2932  }
2933  errors++;
2934 
2935  if ( errors > 1000 )
2936  {
2937  if ( errorMessage )
2938  {
2939  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
2940  }
2941 
2942  n = -1;
2943  break;
2944  }
2945  }
2946  n++;
2947  }
2948 
2949  writer->stopRender();
2950 
2951  if ( errors > 0 && errorMessage && n > 0 )
2952  {
2953  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
2954  }
2955 
2956  return errors == 0 ? NoError : ErrFeatureWriteFailed;
2957 }
2958 
2961  const QString &fileName,
2962  const SaveVectorOptions &options,
2963  QString *newFilename,
2964  QString *errorMessage,
2965  QString *newLayer )
2966 {
2967  QgsVectorFileWriter::PreparedWriterDetails details;
2968  WriterError err = prepareWriteAsVectorFormat( layer, options, details );
2969  if ( err != NoError )
2970  return err;
2971 
2972  return writeAsVectorFormat( details, fileName, options, newFilename, errorMessage, newLayer );
2973 }
2974 
2975 
2976 bool QgsVectorFileWriter::deleteShapeFile( const QString &fileName )
2977 {
2978  QFileInfo fi( fileName );
2979  QDir dir = fi.dir();
2980 
2981  QStringList filter;
2982  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj", ".cpg", ".sbn", ".sbx", ".idm", ".ind" };
2983  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
2984  {
2985  filter << fi.completeBaseName() + suffixes[i];
2986  }
2987 
2988  bool ok = true;
2989  const auto constEntryList = dir.entryList( filter );
2990  for ( const QString &file : constEntryList )
2991  {
2992  QFile f( dir.canonicalPath() + '/' + file );
2993  if ( !f.remove() )
2994  {
2995  QgsDebugMsg( QStringLiteral( "Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
2996  ok = false;
2997  }
2998  }
2999 
3000  return ok;
3001 }
3002 
3004 {
3005  mSymbologyScale = d;
3006  mRenderContext.setRendererScale( mSymbologyScale );
3007 }
3008 
3009 QList< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
3010 {
3011  QList< FilterFormatDetails > results;
3012 
3014  int const drvCount = OGRGetDriverCount();
3015 
3016  for ( int i = 0; i < drvCount; ++i )
3017  {
3018  OGRSFDriverH drv = OGRGetDriver( i );
3019  if ( drv )
3020  {
3021  QString drvName = OGR_Dr_GetName( drv );
3022 
3023 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
3024  GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
3025  char **metadata = nullptr;
3026  if ( gdalDriver )
3027  {
3028  metadata = GDALGetMetadata( gdalDriver, nullptr );
3029  }
3030 
3031  bool nonSpatialFormat = CSLFetchBoolean( metadata, GDAL_DCAP_NONSPATIAL, false );
3032 #else
3033  bool nonSpatialFormat = ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) );
3034 #endif
3035 
3036  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
3037  {
3038  if ( options & SkipNonSpatialFormats )
3039  {
3040  // skip non-spatial formats
3041  if ( nonSpatialFormat )
3042  continue;
3043  }
3044 
3045  QString filterString = filterForDriver( drvName );
3046  if ( filterString.isEmpty() )
3047  continue;
3048 
3049  MetaData metadata;
3050  QStringList globs;
3051  if ( driverMetadata( drvName, metadata ) && !metadata.glob.isEmpty() )
3052  {
3053  globs = metadata.glob.toLower().split( ' ' );
3054  }
3055 
3056  FilterFormatDetails details;
3057  details.driverName = drvName;
3058  details.filterString = filterString;
3059  details.globs = globs;
3060 
3061  results << details;
3062  }
3063  }
3064  }
3065 
3066  std::sort( results.begin(), results.end(), [options]( const FilterFormatDetails & a, const FilterFormatDetails & b ) -> bool
3067  {
3068  if ( options & SortRecommended )
3069  {
3070  if ( a.driverName == QLatin1String( "GPKG" ) )
3071  return true; // Make https://twitter.com/shapefiIe a sad little fellow
3072  else if ( b.driverName == QLatin1String( "GPKG" ) )
3073  return false;
3074  else if ( a.driverName == QLatin1String( "ESRI Shapefile" ) )
3075  return true;
3076  else if ( b.driverName == QLatin1String( "ESRI Shapefile" ) )
3077  return false;
3078  }
3079 
3080  return a.filterString.toLower().localeAwareCompare( b.filterString.toLower() ) < 0;
3081  } );
3082 
3083  return results;
3084 }
3085 
3086 QStringList QgsVectorFileWriter::supportedFormatExtensions( const VectorFormatOptions options )
3087 {
3088  const auto formats = supportedFiltersAndFormats( options );
3089  QSet< QString > extensions;
3090 
3091  const QRegularExpression rx( QStringLiteral( "\\*\\.(.*)$" ) );
3092 
3093  for ( const FilterFormatDetails &format : formats )
3094  {
3095  for ( const QString &glob : format.globs )
3096  {
3097  const QRegularExpressionMatch match = rx.match( glob );
3098  if ( !match.hasMatch() )
3099  continue;
3100 
3101  const QString matched = match.captured( 1 );
3102  extensions.insert( matched );
3103  }
3104  }
3105 
3106  QStringList extensionList = extensions.toList();
3107 
3108  std::sort( extensionList.begin(), extensionList.end(), [options]( const QString & a, const QString & b ) -> bool
3109  {
3110  if ( options & SortRecommended )
3111  {
3112  if ( a == QLatin1String( "gpkg" ) )
3113  return true; // Make https://twitter.com/shapefiIe a sad little fellow
3114  else if ( b == QLatin1String( "gpkg" ) )
3115  return false;
3116  else if ( a == QLatin1String( "shp" ) )
3117  return true;
3118  else if ( b == QLatin1String( "shp" ) )
3119  return false;
3120  }
3121 
3122  return a.toLower().localeAwareCompare( b.toLower() ) < 0;
3123  } );
3124 
3125  return extensionList;
3126 }
3127 
3128 QList< QgsVectorFileWriter::DriverDetails > QgsVectorFileWriter::ogrDriverList( const VectorFormatOptions options )
3129 {
3130  QList< QgsVectorFileWriter::DriverDetails > results;
3131 
3133  const int drvCount = OGRGetDriverCount();
3134 
3135  QStringList writableDrivers;
3136  for ( int i = 0; i < drvCount; ++i )
3137  {
3138  OGRSFDriverH drv = OGRGetDriver( i );
3139  if ( drv )
3140  {
3141  QString drvName = OGR_Dr_GetName( drv );
3142 
3143  if ( options & SkipNonSpatialFormats )
3144  {
3145  // skip non-spatial formats
3146  // TODO - use GDAL metadata to determine this, when support exists in GDAL
3147  if ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) )
3148  continue;
3149  }
3150 
3151  if ( drvName == QLatin1String( "ESRI Shapefile" ) )
3152  {
3153  writableDrivers << QStringLiteral( "DBF file" );
3154  }
3155  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
3156  {
3157  // Add separate format for Mapinfo MIF (MITAB is OGR default)
3158  if ( drvName == QLatin1String( "MapInfo File" ) )
3159  {
3160  writableDrivers << QStringLiteral( "MapInfo MIF" );
3161  }
3162  else if ( drvName == QLatin1String( "SQLite" ) )
3163  {
3164  // Unfortunately it seems that there is no simple way to detect if
3165  // OGR SQLite driver is compiled with SpatiaLite support.
3166  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
3167  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
3168  // -> test if creation failes
3169  QString option = QStringLiteral( "SPATIALITE=YES" );
3170  char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ), nullptr };
3171  OGRSFDriverH poDriver;
3173  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
3174  if ( poDriver )
3175  {
3176  gdal::ogr_datasource_unique_ptr ds( OGR_Dr_CreateDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData(), options ) );
3177  if ( ds )
3178  {
3179  writableDrivers << QStringLiteral( "SpatiaLite" );
3180  OGR_Dr_DeleteDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData() );
3181  }
3182  }
3183  CPLFree( options[0] );
3184  }
3185  writableDrivers << drvName;
3186  }
3187  }
3188  }
3189 
3190  results.reserve( writableDrivers.count() );
3191  for ( const QString &drvName : qgis::as_const( writableDrivers ) )
3192  {
3193  MetaData metadata;
3194  if ( driverMetadata( drvName, metadata ) && !metadata.trLongName.isEmpty() )
3195  {
3196  DriverDetails details;
3197  details.driverName = drvName;
3198  details.longName = metadata.trLongName;
3199  results << details;
3200  }
3201  }
3202 
3203  std::sort( results.begin(), results.end(), [options]( const DriverDetails & a, const DriverDetails & b ) -> bool
3204  {
3205  if ( options & SortRecommended )
3206  {
3207  if ( a.driverName == QLatin1String( "GPKG" ) )
3208  return true; // Make https://twitter.com/shapefiIe a sad little fellow
3209  else if ( b.driverName == QLatin1String( "GPKG" ) )
3210  return false;
3211  else if ( a.driverName == QLatin1String( "ESRI Shapefile" ) )
3212  return true;
3213  else if ( b.driverName == QLatin1String( "ESRI Shapefile" ) )
3214  return false;
3215  }
3216 
3217  return a.longName.toLower().localeAwareCompare( b.longName.toLower() ) < 0;
3218  } );
3219  return results;
3220 }
3221 
3222 QString QgsVectorFileWriter::driverForExtension( const QString &extension )
3223 {
3224  QString ext = extension.trimmed();
3225  if ( ext.isEmpty() )
3226  return QString();
3227 
3228  if ( ext.startsWith( '.' ) )
3229  ext.remove( 0, 1 );
3230 
3231  GDALAllRegister();
3232  int const drvCount = GDALGetDriverCount();
3233 
3234  for ( int i = 0; i < drvCount; ++i )
3235  {
3236  GDALDriverH drv = GDALGetDriver( i );
3237  if ( drv )
3238  {
3239  char **driverMetadata = GDALGetMetadata( drv, nullptr );
3240  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) && CSLFetchBoolean( driverMetadata, GDAL_DCAP_VECTOR, false ) )
3241  {
3242  QString drvName = GDALGetDriverShortName( drv );
3243  QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
3244 
3245  const auto constDriverExtensions = driverExtensions;
3246  for ( const QString &driver : constDriverExtensions )
3247  {
3248  if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
3249  return drvName;
3250  }
3251  }
3252  }
3253  }
3254  return QString();
3255 }
3256 
3257 QString QgsVectorFileWriter::fileFilterString( const VectorFormatOptions options )
3258 {
3259  QString filterString;
3260  const auto driverFormats = supportedFiltersAndFormats( options );
3261  for ( const FilterFormatDetails &details : driverFormats )
3262  {
3263  if ( !filterString.isEmpty() )
3264  filterString += QLatin1String( ";;" );
3265 
3266  filterString += details.filterString;
3267  }
3268  return filterString;
3269 }
3270 
3271 QString QgsVectorFileWriter::filterForDriver( const QString &driverName )
3272 {
3273  MetaData metadata;
3274  if ( !driverMetadata( driverName, metadata ) || metadata.trLongName.isEmpty() || metadata.glob.isEmpty() )
3275  return QString();
3276 
3277  return QStringLiteral( "%1 (%2 %3)" ).arg( metadata.trLongName,
3278  metadata.glob.toLower(),
3279  metadata.glob.toUpper() );
3280 }
3281 
3283 {
3284  if ( codecName == QLatin1String( "System" ) )
3285  return QStringLiteral( "LDID/0" );
3286 
3287  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
3288  if ( re.exactMatch( codecName ) )
3289  {
3290  QString c = re.cap( 2 ).remove( '-' );
3291  bool isNumber;
3292  c.toInt( &isNumber );
3293  if ( isNumber )
3294  return c;
3295  }
3296  return codecName;
3297 }
3298 
3299 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer *vl, const QgsCoordinateTransform &ct, OGRDataSourceH ds )
3300 {
3301  if ( !vl || !ds )
3302  {
3303  return;
3304  }
3305 
3306  QgsFeatureRenderer *renderer = vl->renderer();
3307  if ( !renderer )
3308  {
3309  return;
3310  }
3311 
3312  //unit type
3313  QgsUnitTypes::DistanceUnit mapUnits = vl->crs().mapUnits();
3314  if ( ct.isValid() )
3315  {
3316  mapUnits = ct.destinationCrs().mapUnits();
3317  }
3318 
3319  mSymbolLayerTable.clear();
3320  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
3321  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
3322 
3323  //get symbols
3324  int nTotalLevels = 0;
3325  QgsSymbolList symbolList = renderer->symbols( mRenderContext );
3326  QgsSymbolList::iterator symbolIt = symbolList.begin();
3327  for ( ; symbolIt != symbolList.end(); ++symbolIt )
3328  {
3329  double mmsf = mmScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3330  double musf = mapUnitScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3331 
3332  int nLevels = ( *symbolIt )->symbolLayerCount();
3333  for ( int i = 0; i < nLevels; ++i )
3334  {
3335  mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
3336  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
3337  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
3338  ++nTotalLevels;
3339  }
3340  }
3341  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
3342 }
3343 
3344 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( const PreparedWriterDetails &details, QgsFeatureIterator &fit,
3345  const QgsCoordinateTransform &ct, QString *errorMessage )
3346 {
3347  if ( !details.renderer )
3348  return ErrInvalidLayer;
3349 
3350  mRenderContext.expressionContext() = details.expressionContext;
3351 
3352  QHash< QgsSymbol *, QList<QgsFeature> > features;
3353 
3354  //unit type
3355  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
3356  if ( ct.isValid() )
3357  {
3358  mapUnits = ct.destinationCrs().mapUnits();
3359  }
3360 
3361  startRender( details.renderer.get(), details.sourceFields );
3362 
3363  //fetch features
3364  QgsFeature fet;
3365  QgsSymbol *featureSymbol = nullptr;
3366  while ( fit.nextFeature( fet ) )
3367  {
3368  if ( ct.isValid() )
3369  {
3370  try
3371  {
3372  if ( fet.hasGeometry() )
3373  {
3374  QgsGeometry g = fet.geometry();
3375  g.transform( ct );
3376  fet.setGeometry( g );
3377  }
3378  }
3379  catch ( QgsCsException &e )
3380  {
3381  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
3382  .arg( e.what() );
3383  QgsLogger::warning( msg );
3384  if ( errorMessage )
3385  *errorMessage = msg;
3386 
3387  return ErrProjection;
3388  }
3389  }
3390  mRenderContext.expressionContext().setFeature( fet );
3391 
3392  featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
3393  if ( !featureSymbol )
3394  {
3395  continue;
3396  }
3397 
3398  QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
3399  if ( it == features.end() )
3400  {
3401  it = features.insert( featureSymbol, QList<QgsFeature>() );
3402  }
3403  it.value().append( fet );
3404  }
3405 
3406  //find out order
3407  QgsSymbolLevelOrder levels;
3408  QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
3409  for ( int i = 0; i < symbols.count(); i++ )
3410  {
3411  QgsSymbol *sym = symbols[i];
3412  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
3413  {
3414  int level = sym->symbolLayer( j )->renderingPass();
3415  if ( level < 0 || level >= 1000 ) // ignore invalid levels
3416  continue;
3417  QgsSymbolLevelItem item( sym, j );
3418  while ( level >= levels.count() ) // append new empty levels
3419  levels.append( QgsSymbolLevel() );
3420  levels[level].append( item );
3421  }
3422  }
3423 
3424  int nErrors = 0;
3425  int nTotalFeatures = 0;
3426 
3427  //export symbol layers and symbology
3428  for ( int l = 0; l < levels.count(); l++ )
3429  {
3430  QgsSymbolLevel &level = levels[l];
3431  for ( int i = 0; i < level.count(); i++ )
3432  {
3433  QgsSymbolLevelItem &item = level[i];
3434  QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
3435  if ( levelIt == features.end() )
3436  {
3437  ++nErrors;
3438  continue;
3439  }
3440 
3441  double mmsf = mmScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3442  double musf = mapUnitScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3443 
3444  int llayer = item.layer();
3445  QList<QgsFeature> &featureList = levelIt.value();
3446  QList<QgsFeature>::iterator featureIt = featureList.begin();
3447  for ( ; featureIt != featureList.end(); ++featureIt )
3448  {
3449  ++nTotalFeatures;
3450  gdal::ogr_feature_unique_ptr ogrFeature = createFeature( *featureIt );
3451  if ( !ogrFeature )
3452  {
3453  ++nErrors;
3454  continue;
3455  }
3456 
3457  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
3458  if ( !styleString.isEmpty() )
3459  {
3460  OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
3461  if ( !writeFeature( mLayer, ogrFeature.get() ) )
3462  {
3463  ++nErrors;
3464  }
3465  }
3466  }
3467  }
3468  }
3469 
3470  stopRender();
3471 
3472  if ( nErrors > 0 && errorMessage )
3473  {
3474  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
3475  }
3476 
3478 }
3479 
3480 double QgsVectorFileWriter::mmScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3481 {
3482  if ( symbolUnits == QgsUnitTypes::RenderMillimeters )
3483  {
3484  return 1.0;
3485  }
3486  else
3487  {
3488  //conversion factor map units -> mm
3489  if ( mapUnits == QgsUnitTypes::DistanceMeters )
3490  {
3491  return 1000 / scale;
3492  }
3493 
3494  }
3495  return 1.0; //todo: map units
3496 }
3497 
3498 double QgsVectorFileWriter::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3499 {
3500  if ( symbolUnits == QgsUnitTypes::RenderMapUnits )
3501  {
3502  return 1.0;
3503  }
3504  else
3505  {
3506  if ( symbolUnits == QgsUnitTypes::RenderMillimeters && mapUnits == QgsUnitTypes::DistanceMeters )
3507  {
3508  return scale / 1000;
3509  }
3510  }
3511  return 1.0;
3512 }
3513 
3514 void QgsVectorFileWriter::startRender( QgsFeatureRenderer *sourceRenderer, const QgsFields &fields )
3515 {
3516  mRenderer = createSymbologyRenderer( sourceRenderer );
3517  if ( !mRenderer )
3518  {
3519  return;
3520  }
3521 
3522  mRenderer->startRender( mRenderContext, fields );
3523 }
3524 
3525 void QgsVectorFileWriter::stopRender()
3526 {
3527  if ( !mRenderer )
3528  {
3529  return;
3530  }
3531 
3532  mRenderer->stopRender( mRenderContext );
3533 }
3534 
3535 std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer( QgsFeatureRenderer *sourceRenderer ) const
3536 {
3537  if ( mSymbologyExport == NoSymbology )
3538  {
3539  return nullptr;
3540  }
3541  if ( !sourceRenderer )
3542  {
3543  return nullptr;
3544  }
3545 
3546  return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->clone() );
3547 }
3548 
3549 void QgsVectorFileWriter::addRendererAttributes( QgsFeatureRenderer *renderer, QgsRenderContext &context, const QgsFields &fields, QgsAttributeList &attList )
3550 {
3551  if ( renderer )
3552  {
3553  const QSet<QString> rendererAttributes = renderer->usedAttributes( context );
3554  for ( const QString &attr : rendererAttributes )
3555  {
3556  int index = fields.lookupField( attr );
3557  if ( index != -1 )
3558  {
3559  attList.append( index );
3560  }
3561  }
3562  }
3563 }
3564 
3565 QStringList QgsVectorFileWriter::concatenateOptions( const QMap<QString, QgsVectorFileWriter::Option *> &options )
3566 {
3567  QStringList list;
3568  QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
3569 
3570  for ( it = options.constBegin(); it != options.constEnd(); ++it )
3571  {
3572  QgsVectorFileWriter::Option *option = it.value();
3573  switch ( option->type )
3574  {
3576  {
3577  QgsVectorFileWriter::IntOption *opt = dynamic_cast<QgsVectorFileWriter::IntOption *>( option );
3578  if ( opt )
3579  {
3580  list.append( QStringLiteral( "%1=%2" ).arg( it.key() ).arg( opt->defaultValue ) );
3581  }
3582  break;
3583  }
3584 
3586  {
3587  QgsVectorFileWriter::SetOption *opt = dynamic_cast<QgsVectorFileWriter::SetOption *>( option );
3588  if ( opt && !opt->defaultValue.isEmpty() )
3589  {
3590  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3591  }
3592  break;
3593  }
3594 
3596  {
3598  if ( opt && !opt->defaultValue.isNull() )
3599  {
3600  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3601  }
3602  break;
3603  }
3604 
3607  if ( opt )
3608  {
3609  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->mValue ) );
3610  }
3611  break;
3612  }
3613  }
3614 
3615  return list;
3616 }
3617 
3618 QgsVectorFileWriter::EditionCapabilities QgsVectorFileWriter::editionCapabilities( const QString &datasetName )
3619 {
3620  OGRSFDriverH hDriver = nullptr;
3621  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3622  if ( !hDS )
3623  return nullptr;
3624  QString drvName = OGR_Dr_GetName( hDriver );
3625  QgsVectorFileWriter::EditionCapabilities caps = nullptr;
3626  if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
3627  {
3628  // Shapefile driver returns True for a "foo.shp" dataset name,
3629  // creating "bar.shp" new layer, but this would be a bit confusing
3630  // for the user, so pretent that it does not support that
3631  if ( !( drvName == QLatin1String( "ESRI Shapefile" ) && QFile::exists( datasetName ) ) )
3632  caps |= CanAddNewLayer;
3633  }
3634  if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
3635  {
3636  caps |= CanDeleteLayer;
3637  }
3638  int layer_count = OGR_DS_GetLayerCount( hDS.get() );
3639  if ( layer_count )
3640  {
3641  OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
3642  if ( hLayer )
3643  {
3644  if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
3645  {
3646  caps |= CanAppendToExistingLayer;
3647  if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
3648  {
3650  }
3651  }
3652  }
3653  }
3654  return caps;
3655 }
3656 
3657 bool QgsVectorFileWriter::targetLayerExists( const QString &datasetName,
3658  const QString &layerNameIn )
3659 {
3660  OGRSFDriverH hDriver = nullptr;
3661  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3662  if ( !hDS )
3663  return false;
3664 
3665  QString layerName( layerNameIn );
3666  if ( layerName.isEmpty() )
3667  layerName = QFileInfo( datasetName ).baseName();
3668 
3669  return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3670 }
3671 
3672 
3673 bool QgsVectorFileWriter::areThereNewFieldsToCreate( const QString &datasetName,
3674  const QString &layerName,
3675  QgsVectorLayer *layer,
3676  const QgsAttributeList &attributes )
3677 {
3678  OGRSFDriverH hDriver = nullptr;
3679  gdal::ogr_datasource_unique_ptr hDS( myOGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3680  if ( !hDS )
3681  return false;
3682  OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3683  if ( !hLayer )
3684  {
3685  return false;
3686  }
3687  bool ret = false;
3688  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
3689  const auto constAttributes = attributes;
3690  for ( int idx : constAttributes )
3691  {
3692  QgsField fld = layer->fields().at( idx );
3693  if ( OGR_FD_GetFieldIndex( defn, fld.name().toUtf8().constData() ) < 0 )
3694  {
3695  ret = true;
3696  break;
3697  }
3698  }
3699  return ret;
3700 }
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:957
static Type singleType(Type type)
Returns the single type for a WKB type.
Definition: qgswkbtypes.h:155
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:299
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:560
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:111
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:150
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:771
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:77
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:43
QgsFields fields() const FINAL
Returns the list of fields of this layer.
#define FALLTHROUGH
Definition: qgis.h:656
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:867
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 a specific symbol layer contained in the symbol.
Definition: qgssymbol.cpp:358
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:242
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:271
static QString convertCodecNameForEncodingOption(const QString &codecName)
Converts codec name to string passed to ENCODING layer creation option of OGR Shapefile.
virtual QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const
Returns list of symbols used for rendering the feature.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QgsVectorFileWriter::WriterError hasError()
Checks whether there were any errors in constructor.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Transform from destination to source CRS.
QList< QgsSymbolLevelItem > QgsSymbolLevel
Definition: qgsrenderer.h:73
bool skipAttributeCreation
Only write geometries.
double symbologyScale
Scale of symbology.
virtual QgsSymbolList symbols(QgsRenderContext &context) const
Returns list of symbols used by the renderer.
static 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).
QString toWkt() const
Returns a WKT representation of this CRS.
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
Definition: qgsogrutils.h:124
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
QMap< QString, QgsVectorFileWriter::Option * > driverOptions
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h: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:821
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:430
Writing was interrupted by manual cancellation.
QgsSymbol * symbol()
Definition: qgsrenderer.h:65
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
QVariant::Type type
Definition: qgsfield.h:56
QgsWkbTypes::Type mWkbType
Geometry type which is being used.
virtual QgsFeatureRenderer::Capabilities capabilities()
Returns details about internals of this renderer.
Definition: qgsrenderer.h:262
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
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:85
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:111
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.