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