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