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