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