QGIS API Documentation  3.0.2-Girona (307d082)
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_SetGeometryDirectly( 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 
2350 
2352  : driverName( QStringLiteral( "GPKG" ) )
2353 {
2354 }
2355 
2356 
2357 
2358 QgsVectorFileWriter::WriterError QgsVectorFileWriter::prepareWriteAsVectorFormat( QgsVectorLayer *layer, const QgsVectorFileWriter::SaveVectorOptions &options, QgsVectorFileWriter::PreparedWriterDetails &details )
2359 {
2360  if ( !layer )
2361  {
2362  return ErrInvalidLayer;
2363  }
2364 
2365 
2366  if ( layer->renderer() )
2367  details.renderer.reset( layer->renderer()->clone() );
2368  details.sourceCrs = layer->crs();
2369  details.sourceWkbType = layer->wkbType();
2370  details.sourceFields = layer->fields();
2371  details.providerType = layer->providerType();
2372  details.featureCount = options.onlySelectedFeatures ? layer->selectedFeatureCount() : layer->featureCount();
2373  if ( layer->dataProvider() )
2374  details.dataSourceUri = layer->dataProvider()->dataSourceUri();
2375  details.storageType = layer->storageType();
2376  details.selectedFeatureIds = layer->selectedFeatureIds();
2377 
2378  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) )
2379  {
2380  QgsFeatureRequest req;
2381  if ( options.onlySelectedFeatures )
2382  {
2383  req.setFilterFids( details.selectedFeatureIds );
2384  }
2386  details.geometryTypeScanIterator = layer->getFeatures( req );
2387  }
2388 
2389  details.expressionContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
2390  details.renderContext.setExpressionContext( details.expressionContext );
2391  details.renderContext.setRendererScale( options.symbologyScale );
2392 
2393  details.shallTransform = false;
2394  if ( options.ct.isValid() )
2395  {
2396  // This means we should transform
2397  details.outputCrs = options.ct.destinationCrs();
2398  details.shallTransform = true;
2399  }
2400  else
2401  {
2402  // This means we shouldn't transform, use source CRS as output (if defined)
2403  details.outputCrs = details.sourceCrs;
2404  }
2405 
2406  details.destWkbType = details.sourceWkbType;
2407  if ( options.overrideGeometryType != QgsWkbTypes::Unknown )
2408  {
2409  details.destWkbType = QgsWkbTypes::flatType( options.overrideGeometryType );
2410  if ( QgsWkbTypes::hasZ( options.overrideGeometryType ) || options.includeZ )
2411  details.destWkbType = QgsWkbTypes::addZ( details.destWkbType );
2412  }
2413  if ( options.forceMulti )
2414  {
2415  details.destWkbType = QgsWkbTypes::multiType( details.destWkbType );
2416  }
2417 
2418  details.attributes = options.attributes;
2419  if ( options.skipAttributeCreation )
2420  details.attributes.clear();
2421  else if ( details.attributes.isEmpty() )
2422  {
2423  const QgsAttributeList allAttributes = details.sourceFields.allAttributesList();
2424  for ( int idx : allAttributes )
2425  {
2426  QgsField fld = details.sourceFields.at( idx );
2427  if ( details.providerType == QLatin1String( "oracle" ) && fld.typeName().contains( QLatin1String( "SDO_GEOMETRY" ) ) )
2428  continue;
2429  details.attributes.append( idx );
2430  }
2431  }
2432 
2433  if ( !details.attributes.isEmpty() )
2434  {
2435  for ( int attrIdx : qgis::as_const( details.attributes ) )
2436  {
2437  details.outputFields.append( details.sourceFields.at( attrIdx ) );
2438  }
2439  }
2440 
2441  // not ideal - would be nice to avoid this happening in the preparation step if possible,
2442  // but currently requires access to the layer's minimumValue/maximumValue methods
2443  if ( details.providerType == QLatin1String( "spatialite" ) )
2444  {
2445  for ( int i = 0; i < details.outputFields.size(); i++ )
2446  {
2447  if ( details.outputFields.at( i ).type() == QVariant::LongLong )
2448  {
2449  QVariant min = layer->minimumValue( i );
2450  QVariant max = layer->maximumValue( i );
2451  if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < INT_MAX )
2452  {
2453  details.outputFields[i].setType( QVariant::Int );
2454  }
2455  }
2456  }
2457  }
2458 
2459 
2460  //add possible attributes needed by renderer
2461  addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
2462 
2463  QgsFeatureRequest req;
2464  req.setSubsetOfAttributes( details.attributes );
2465  if ( options.onlySelectedFeatures )
2466  req.setFilterFids( details.selectedFeatureIds );
2467 
2468  if ( !options.filterExtent.isNull() )
2469  {
2470  QgsRectangle filterRect = options.filterExtent;
2471  bool useFilterRect = true;
2472  if ( details.shallTransform )
2473  {
2474  try
2475  {
2476  // map filter rect back from destination CRS to layer CRS
2477  filterRect = options.ct.transformBoundingBox( filterRect, QgsCoordinateTransform::ReverseTransform );
2478  }
2479  catch ( QgsCsException & )
2480  {
2481  useFilterRect = false;
2482  }
2483  }
2484  if ( useFilterRect )
2485  {
2486  req.setFilterRect( filterRect );
2487  }
2488  details.filterRectGeometry = QgsGeometry::fromRect( options.filterExtent );
2489  details.filterRectEngine.reset( QgsGeometry::createGeometryEngine( details.filterRectGeometry.constGet() ) );
2490  details.filterRectEngine->prepareGeometry();
2491  }
2492  details.sourceFeatureIterator = layer->getFeatures( req );
2493 
2494  return NoError;
2495 }
2496 
2497 QgsVectorFileWriter::WriterError QgsVectorFileWriter::writeAsVectorFormat( PreparedWriterDetails &details, const QString &fileName, const QgsVectorFileWriter::SaveVectorOptions &options, QString *newFilename, QString *errorMessage )
2498 {
2499 
2500  QgsWkbTypes::Type destWkbType = details.destWkbType;
2501 
2502  int lastProgressReport = 0;
2503  long total = details.featureCount;
2504 
2505  if ( details.providerType == QLatin1String( "ogr" ) && !details.dataSourceUri.isEmpty() )
2506  {
2507  QStringList theURIParts = details.dataSourceUri.split( '|' );
2508  QString srcFileName = theURIParts[0];
2509 
2510  if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2511  {
2512  if ( errorMessage )
2513  *errorMessage = QObject::tr( "Cannot overwrite a OGR layer in place" );
2514  return ErrCreateDataSource;
2515  }
2516 
2517  // Shapefiles might contain multi types although wkbType() only reports singles
2518  if ( details.storageType == QLatin1String( "ESRI Shapefile" ) && !QgsWkbTypes::isMultiType( destWkbType ) )
2519  {
2520  QgsFeatureIterator fit = details.geometryTypeScanIterator;
2521  QgsFeature fet;
2522  long scanned = 0;
2523  while ( fit.nextFeature( fet ) )
2524  {
2525  if ( options.feedback && options.feedback->isCanceled() )
2526  {
2527  return Canceled;
2528  }
2529  if ( options.feedback )
2530  {
2531  //dedicate first 5% of progress bar to this scan
2532  int newProgress = ( 5.0 * scanned ) / total;
2533  if ( newProgress != lastProgressReport )
2534  {
2535  lastProgressReport = newProgress;
2536  options.feedback->setProgress( lastProgressReport );
2537  }
2538  }
2539 
2540  if ( fet.hasGeometry() && QgsWkbTypes::isMultiType( fet.geometry().wkbType() ) )
2541  {
2542  destWkbType = QgsWkbTypes::multiType( destWkbType );
2543  break;
2544  }
2545  scanned++;
2546  }
2547  }
2548  }
2549 
2550  std::unique_ptr< QgsVectorFileWriter > writer =
2551  qgis::make_unique< QgsVectorFileWriter >( fileName,
2552  options.fileEncoding, details.outputFields, destWkbType,
2553  details.outputCrs, options.driverName,
2554  options.datasourceOptions,
2555  options.layerOptions,
2556  newFilename,
2557  options.symbologyExport,
2558  options.fieldValueConverter,
2559  options.layerName,
2560  options.actionOnExistingFile );
2561  writer->setSymbologyScale( options.symbologyScale );
2562 
2563  if ( newFilename )
2564  {
2565  QgsDebugMsg( "newFilename = " + *newFilename );
2566  }
2567 
2568  // check whether file creation was successful
2569  WriterError err = writer->hasError();
2570  if ( err != NoError )
2571  {
2572  if ( errorMessage )
2573  *errorMessage = writer->errorMessage();
2574  return err;
2575  }
2576 
2577  if ( errorMessage )
2578  {
2579  errorMessage->clear();
2580  }
2581 
2582  QgsFeature fet;
2583 
2584  //create symbol table if needed
2585  if ( writer->symbologyExport() != NoSymbology )
2586  {
2587  //writer->createSymbolLayerTable( layer, writer->mDS );
2588  }
2589 
2590  if ( writer->symbologyExport() == SymbolLayerSymbology )
2591  {
2592  QgsFeatureRenderer *r = details.renderer.get();
2594  && r->usingSymbolLevels() )
2595  {
2596  QgsVectorFileWriter::WriterError error = writer->exportFeaturesSymbolLevels( details, details.sourceFeatureIterator, options.ct, errorMessage );
2597  return ( error == NoError ) ? NoError : ErrFeatureWriteFailed;
2598  }
2599  }
2600 
2601  int n = 0, errors = 0;
2602 
2603  //unit type
2604  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
2605  if ( options.ct.isValid() )
2606  {
2607  mapUnits = options.ct.destinationCrs().mapUnits();
2608  }
2609 
2610  writer->startRender( details.renderer.get(), details.sourceFields );
2611 
2612  writer->resetMap( details.attributes );
2613  // Reset mFields to layer fields, and not just exported fields
2614  writer->mFields = details.sourceFields;
2615 
2616  // write all features
2617  long saved = 0;
2618  int initialProgress = lastProgressReport;
2619  while ( details.sourceFeatureIterator.nextFeature( fet ) )
2620  {
2621  if ( options.feedback && options.feedback->isCanceled() )
2622  {
2623  return Canceled;
2624  }
2625 
2626  saved++;
2627  if ( options.feedback )
2628  {
2629  //avoid spamming progress reports
2630  int newProgress = initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total;
2631  if ( newProgress < 100 && newProgress != lastProgressReport )
2632  {
2633  lastProgressReport = newProgress;
2634  options.feedback->setProgress( lastProgressReport );
2635  }
2636  }
2637 
2638  if ( details.shallTransform )
2639  {
2640  try
2641  {
2642  if ( fet.hasGeometry() )
2643  {
2644  QgsGeometry g = fet.geometry();
2645  g.transform( options.ct );
2646  fet.setGeometry( g );
2647  }
2648  }
2649  catch ( QgsCsException &e )
2650  {
2651  QString msg = QObject::tr( "Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
2652  .arg( fet.id() ).arg( e.what() );
2653  QgsLogger::warning( msg );
2654  if ( errorMessage )
2655  *errorMessage = msg;
2656 
2657  return ErrProjection;
2658  }
2659  }
2660 
2661  if ( fet.hasGeometry() && details.filterRectEngine && !details.filterRectEngine->intersects( fet.geometry().constGet() ) )
2662  continue;
2663 
2664  if ( details.attributes.empty() && options.skipAttributeCreation )
2665  {
2666  fet.initAttributes( 0 );
2667  }
2668 
2669  if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
2670  {
2671  WriterError err = writer->hasError();
2672  if ( err != NoError && errorMessage )
2673  {
2674  if ( errorMessage->isEmpty() )
2675  {
2676  *errorMessage = QObject::tr( "Feature write errors:" );
2677  }
2678  *errorMessage += '\n' + writer->errorMessage();
2679  }
2680  errors++;
2681 
2682  if ( errors > 1000 )
2683  {
2684  if ( errorMessage )
2685  {
2686  *errorMessage += QObject::tr( "Stopping after %1 errors" ).arg( errors );
2687  }
2688 
2689  n = -1;
2690  break;
2691  }
2692  }
2693  n++;
2694  }
2695 
2696  writer->stopRender();
2697 
2698  if ( errors > 0 && errorMessage && n > 0 )
2699  {
2700  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
2701  }
2702 
2703  return errors == 0 ? NoError : ErrFeatureWriteFailed;
2704 }
2705 
2708  const QString &fileName,
2709  const SaveVectorOptions &options,
2710  QString *newFilename,
2711  QString *errorMessage )
2712 {
2713  QgsVectorFileWriter::PreparedWriterDetails details;
2714  WriterError err = prepareWriteAsVectorFormat( layer, options, details );
2715  if ( err != NoError )
2716  return err;
2717 
2718  return writeAsVectorFormat( details, fileName, options, newFilename, errorMessage );
2719 }
2720 
2721 
2722 bool QgsVectorFileWriter::deleteShapeFile( const QString &fileName )
2723 {
2724  QFileInfo fi( fileName );
2725  QDir dir = fi.dir();
2726 
2727  QStringList filter;
2728  const char *suffixes[] = { ".shp", ".shx", ".dbf", ".prj", ".qix", ".qpj" };
2729  for ( std::size_t i = 0; i < sizeof( suffixes ) / sizeof( *suffixes ); i++ )
2730  {
2731  filter << fi.completeBaseName() + suffixes[i];
2732  }
2733 
2734  bool ok = true;
2735  Q_FOREACH ( const QString &file, dir.entryList( filter ) )
2736  {
2737  QFile f( dir.canonicalPath() + '/' + file );
2738  if ( !f.remove() )
2739  {
2740  QgsDebugMsg( QString( "Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
2741  ok = false;
2742  }
2743  }
2744 
2745  return ok;
2746 }
2747 
2749 {
2750  mSymbologyScale = d;
2751  mRenderContext.setRendererScale( mSymbologyScale );
2752 }
2753 
2754 QList< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
2755 {
2756  QList< FilterFormatDetails > results;
2757 
2759  int const drvCount = OGRGetDriverCount();
2760 
2761  FilterFormatDetails shapeFormat;
2762  FilterFormatDetails gpkgFormat;
2763 
2764  for ( int i = 0; i < drvCount; ++i )
2765  {
2766  OGRSFDriverH drv = OGRGetDriver( i );
2767  if ( drv )
2768  {
2769  QString drvName = OGR_Dr_GetName( drv );
2770 
2771 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
2772  GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
2773  char **driverMetadata = nullptr;
2774  if ( gdalDriver )
2775  {
2776  driverMetadata = GDALGetMetadata( gdalDriver, nullptr );
2777  }
2778 
2779  bool nonSpatialFormat = CSLFetchBoolean( driverMetadata, GDAL_DCAP_NONSPATIAL, false );
2780 #else
2781  bool nonSpatialFormat = ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) );
2782 #endif
2783 
2784  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2785  {
2786  if ( options & SkipNonSpatialFormats )
2787  {
2788  // skip non-spatial formats
2789  if ( nonSpatialFormat )
2790  continue;
2791  }
2792 
2793  QString filterString = filterForDriver( drvName );
2794  if ( filterString.isEmpty() )
2795  continue;
2796 
2797  FilterFormatDetails details;
2798  details.driverName = drvName;
2799  details.filterString = filterString;
2800 
2801  if ( options & SortRecommended )
2802  {
2803  if ( drvName == QLatin1String( "ESRI Shapefile" ) )
2804  {
2805  shapeFormat = details;
2806  continue;
2807  }
2808  else if ( drvName == QLatin1String( "GPKG" ) )
2809  {
2810  gpkgFormat = details;
2811  continue;
2812  }
2813  }
2814 
2815  results << details;
2816  }
2817  }
2818  }
2819 
2820  std::sort( results.begin(), results.end(), []( const FilterFormatDetails & a, const FilterFormatDetails & b ) -> bool
2821  {
2822  return a.driverName < b.driverName;
2823  } );
2824 
2825  if ( options & SortRecommended )
2826  {
2827  if ( !shapeFormat.filterString.isEmpty() )
2828  {
2829  results.insert( 0, shapeFormat );
2830  }
2831  if ( !gpkgFormat.filterString.isEmpty() )
2832  {
2833  results.insert( 0, gpkgFormat );
2834  }
2835  }
2836 
2837  return results;
2838 }
2839 
2840 QStringList QgsVectorFileWriter::supportedFormatExtensions( const VectorFormatOptions options )
2841 {
2842  const auto formats = supportedFiltersAndFormats( options );
2843  QStringList extensions;
2844 
2845  QRegularExpression rx( QStringLiteral( "\\*\\.([a-zA-Z0-9]*)" ) );
2846 
2847  for ( const FilterFormatDetails &format : formats )
2848  {
2849  QString ext = format.filterString;
2850  QRegularExpressionMatch match = rx.match( ext );
2851  if ( !match.hasMatch() )
2852  continue;
2853 
2854  QString matched = match.captured( 1 );
2855  extensions << matched;
2856  }
2857  return extensions;
2858 }
2859 
2860 QList< QgsVectorFileWriter::DriverDetails > QgsVectorFileWriter::ogrDriverList( const VectorFormatOptions options )
2861 {
2862  QList< QgsVectorFileWriter::DriverDetails > results;
2863 
2865  const int drvCount = OGRGetDriverCount();
2866 
2867  QStringList writableDrivers;
2868  for ( int i = 0; i < drvCount; ++i )
2869  {
2870  OGRSFDriverH drv = OGRGetDriver( i );
2871  if ( drv )
2872  {
2873  QString drvName = OGR_Dr_GetName( drv );
2874 
2875  if ( options & SkipNonSpatialFormats )
2876  {
2877  // skip non-spatial formats
2878  // TODO - use GDAL metadata to determine this, when support exists in GDAL
2879  if ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) )
2880  continue;
2881  }
2882 
2883  if ( drvName == QLatin1String( "ESRI Shapefile" ) )
2884  {
2885  writableDrivers << QStringLiteral( "DBF file" );
2886  }
2887  if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
2888  {
2889  // Add separate format for Mapinfo MIF (MITAB is OGR default)
2890  if ( drvName == QLatin1String( "MapInfo File" ) )
2891  {
2892  writableDrivers << QStringLiteral( "MapInfo MIF" );
2893  }
2894  else if ( drvName == QLatin1String( "SQLite" ) )
2895  {
2896  // Unfortunately it seems that there is no simple way to detect if
2897  // OGR SQLite driver is compiled with SpatiaLite support.
2898  // We have HAVE_SPATIALITE in QGIS, but that may differ from OGR
2899  // http://lists.osgeo.org/pipermail/gdal-dev/2012-November/034580.html
2900  // -> test if creation failes
2901  QString option = QStringLiteral( "SPATIALITE=YES" );
2902  char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ), nullptr };
2903  OGRSFDriverH poDriver;
2905  poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
2906  if ( poDriver )
2907  {
2908  gdal::ogr_datasource_unique_ptr ds( OGR_Dr_CreateDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData(), options ) );
2909  if ( ds )
2910  {
2911  writableDrivers << QStringLiteral( "SpatiaLite" );
2912  OGR_Dr_DeleteDataSource( poDriver, QStringLiteral( "/vsimem/spatialitetest.sqlite" ).toUtf8().constData() );
2913  }
2914  }
2915  CPLFree( options[0] );
2916  }
2917  writableDrivers << drvName;
2918  }
2919  }
2920  }
2921  std::sort( writableDrivers.begin(), writableDrivers.end() );
2922  if ( options & SortRecommended )
2923  {
2924  // recommended order sorting, so we shift certain formats to the top
2925  if ( writableDrivers.contains( QStringLiteral( "ESRI Shapefile" ) ) )
2926  {
2927  writableDrivers.removeAll( QStringLiteral( "ESRI Shapefile" ) );
2928  writableDrivers.insert( 0, QStringLiteral( "ESRI Shapefile" ) );
2929  }
2930  if ( writableDrivers.contains( QStringLiteral( "GPKG" ) ) )
2931  {
2932  // Make https://twitter.com/shapefiIe a sad little fellow
2933  writableDrivers.removeAll( QStringLiteral( "GPKG" ) );
2934  writableDrivers.insert( 0, QStringLiteral( "GPKG" ) );
2935  }
2936  }
2937 
2938  for ( const QString &drvName : qgis::as_const( writableDrivers ) )
2939  {
2940  MetaData metadata;
2941  if ( driverMetadata( drvName, metadata ) && !metadata.trLongName.isEmpty() )
2942  {
2943  DriverDetails details;
2944  details.driverName = drvName;
2945  details.longName = metadata.trLongName;
2946  results << details;
2947  }
2948  }
2949  return results;
2950 }
2951 
2952 QString QgsVectorFileWriter::driverForExtension( const QString &extension )
2953 {
2954  QString ext = extension.trimmed();
2955  if ( ext.isEmpty() )
2956  return QString();
2957 
2958  if ( ext.startsWith( '.' ) )
2959  ext.remove( 0, 1 );
2960 
2961  GDALAllRegister();
2962  int const drvCount = GDALGetDriverCount();
2963 
2964  for ( int i = 0; i < drvCount; ++i )
2965  {
2966  GDALDriverH drv = GDALGetDriver( i );
2967  if ( drv )
2968  {
2969  char **driverMetadata = GDALGetMetadata( drv, nullptr );
2970  if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) && CSLFetchBoolean( driverMetadata, GDAL_DCAP_VECTOR, false ) )
2971  {
2972  QString drvName = GDALGetDriverShortName( drv );
2973  QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS, nullptr ) ).split( ' ' );
2974 
2975  Q_FOREACH ( const QString &driver, driverExtensions )
2976  {
2977  if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
2978  return drvName;
2979  }
2980  }
2981  }
2982  }
2983  return QString();
2984 }
2985 
2986 QString QgsVectorFileWriter::fileFilterString( const VectorFormatOptions options )
2987 {
2988  QString filterString;
2989  const auto driverFormats = supportedFiltersAndFormats( options );
2990  for ( const FilterFormatDetails &details : driverFormats )
2991  {
2992  if ( !filterString.isEmpty() )
2993  filterString += QLatin1String( ";;" );
2994 
2995  filterString += details.filterString;
2996  }
2997  return filterString;
2998 }
2999 
3001 {
3002  MetaData metadata;
3003  if ( !driverMetadata( driverName, metadata ) || metadata.trLongName.isEmpty() || metadata.glob.isEmpty() )
3004  return QString();
3005 
3006  return QStringLiteral( "%1 (%2 %3)" ).arg( metadata.trLongName,
3007  metadata.glob.toLower(),
3008  metadata.glob.toUpper() );
3009 }
3010 
3012 {
3013  if ( codecName == QLatin1String( "System" ) )
3014  return QStringLiteral( "LDID/0" );
3015 
3016  QRegExp re = QRegExp( QString( "(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
3017  if ( re.exactMatch( codecName ) )
3018  {
3019  QString c = re.cap( 2 ).remove( '-' );
3020  bool isNumber;
3021  c.toInt( &isNumber );
3022  if ( isNumber )
3023  return c;
3024  }
3025  return codecName;
3026 }
3027 
3028 void QgsVectorFileWriter::createSymbolLayerTable( QgsVectorLayer *vl, const QgsCoordinateTransform &ct, OGRDataSourceH ds )
3029 {
3030  if ( !vl || !ds )
3031  {
3032  return;
3033  }
3034 
3035  QgsFeatureRenderer *renderer = vl->renderer();
3036  if ( !renderer )
3037  {
3038  return;
3039  }
3040 
3041  //unit type
3042  QgsUnitTypes::DistanceUnit mapUnits = vl->crs().mapUnits();
3043  if ( ct.isValid() )
3044  {
3045  mapUnits = ct.destinationCrs().mapUnits();
3046  }
3047 
3048  mSymbolLayerTable.clear();
3049  OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
3050  OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
3051 
3052  //get symbols
3053  int nTotalLevels = 0;
3054  QgsSymbolList symbolList = renderer->symbols( mRenderContext );
3055  QgsSymbolList::iterator symbolIt = symbolList.begin();
3056  for ( ; symbolIt != symbolList.end(); ++symbolIt )
3057  {
3058  double mmsf = mmScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3059  double musf = mapUnitScaleFactor( mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3060 
3061  int nLevels = ( *symbolIt )->symbolLayerCount();
3062  for ( int i = 0; i < nLevels; ++i )
3063  {
3064  mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
3065  OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
3066  ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
3067  ++nTotalLevels;
3068  }
3069  }
3070  OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
3071 }
3072 
3073 QgsVectorFileWriter::WriterError QgsVectorFileWriter::exportFeaturesSymbolLevels( const PreparedWriterDetails &details, QgsFeatureIterator &fit,
3074  const QgsCoordinateTransform &ct, QString *errorMessage )
3075 {
3076  if ( !details.renderer )
3077  return ErrInvalidLayer;
3078 
3079  mRenderContext.expressionContext() = details.expressionContext;
3080 
3081  QHash< QgsSymbol *, QList<QgsFeature> > features;
3082 
3083  //unit type
3084  QgsUnitTypes::DistanceUnit mapUnits = details.sourceCrs.mapUnits();
3085  if ( ct.isValid() )
3086  {
3087  mapUnits = ct.destinationCrs().mapUnits();
3088  }
3089 
3090  startRender( details.renderer.get(), details.sourceFields );
3091 
3092  //fetch features
3093  QgsFeature fet;
3094  QgsSymbol *featureSymbol = nullptr;
3095  while ( fit.nextFeature( fet ) )
3096  {
3097  if ( ct.isValid() )
3098  {
3099  try
3100  {
3101  if ( fet.hasGeometry() )
3102  {
3103  QgsGeometry g = fet.geometry();
3104  g.transform( ct );
3105  fet.setGeometry( g );
3106  }
3107  }
3108  catch ( QgsCsException &e )
3109  {
3110  QString msg = QObject::tr( "Failed to transform, writing stopped. (Exception: %1)" )
3111  .arg( e.what() );
3112  QgsLogger::warning( msg );
3113  if ( errorMessage )
3114  *errorMessage = msg;
3115 
3116  return ErrProjection;
3117  }
3118  }
3119  mRenderContext.expressionContext().setFeature( fet );
3120 
3121  featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
3122  if ( !featureSymbol )
3123  {
3124  continue;
3125  }
3126 
3127  QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
3128  if ( it == features.end() )
3129  {
3130  it = features.insert( featureSymbol, QList<QgsFeature>() );
3131  }
3132  it.value().append( fet );
3133  }
3134 
3135  //find out order
3136  QgsSymbolLevelOrder levels;
3137  QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
3138  for ( int i = 0; i < symbols.count(); i++ )
3139  {
3140  QgsSymbol *sym = symbols[i];
3141  for ( int j = 0; j < sym->symbolLayerCount(); j++ )
3142  {
3143  int level = sym->symbolLayer( j )->renderingPass();
3144  if ( level < 0 || level >= 1000 ) // ignore invalid levels
3145  continue;
3146  QgsSymbolLevelItem item( sym, j );
3147  while ( level >= levels.count() ) // append new empty levels
3148  levels.append( QgsSymbolLevel() );
3149  levels[level].append( item );
3150  }
3151  }
3152 
3153  int nErrors = 0;
3154  int nTotalFeatures = 0;
3155 
3156  //export symbol layers and symbology
3157  for ( int l = 0; l < levels.count(); l++ )
3158  {
3159  QgsSymbolLevel &level = levels[l];
3160  for ( int i = 0; i < level.count(); i++ )
3161  {
3162  QgsSymbolLevelItem &item = level[i];
3163  QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.symbol() );
3164  if ( levelIt == features.end() )
3165  {
3166  ++nErrors;
3167  continue;
3168  }
3169 
3170  double mmsf = mmScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3171  double musf = mapUnitScaleFactor( mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3172 
3173  int llayer = item.layer();
3174  QList<QgsFeature> &featureList = levelIt.value();
3175  QList<QgsFeature>::iterator featureIt = featureList.begin();
3176  for ( ; featureIt != featureList.end(); ++featureIt )
3177  {
3178  ++nTotalFeatures;
3179  gdal::ogr_feature_unique_ptr ogrFeature = createFeature( *featureIt );
3180  if ( !ogrFeature )
3181  {
3182  ++nErrors;
3183  continue;
3184  }
3185 
3186  QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
3187  if ( !styleString.isEmpty() )
3188  {
3189  OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
3190  if ( !writeFeature( mLayer, ogrFeature.get() ) )
3191  {
3192  ++nErrors;
3193  }
3194  }
3195  }
3196  }
3197  }
3198 
3199  stopRender();
3200 
3201  if ( nErrors > 0 && errorMessage )
3202  {
3203  *errorMessage += QObject::tr( "\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
3204  }
3205 
3207 }
3208 
3209 double QgsVectorFileWriter::mmScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3210 {
3211  if ( symbolUnits == QgsUnitTypes::RenderMillimeters )
3212  {
3213  return 1.0;
3214  }
3215  else
3216  {
3217  //conversion factor map units -> mm
3218  if ( mapUnits == QgsUnitTypes::DistanceMeters )
3219  {
3220  return 1000 / scale;
3221  }
3222 
3223  }
3224  return 1.0; //todo: map units
3225 }
3226 
3227 double QgsVectorFileWriter::mapUnitScaleFactor( double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits )
3228 {
3229  if ( symbolUnits == QgsUnitTypes::RenderMapUnits )
3230  {
3231  return 1.0;
3232  }
3233  else
3234  {
3235  if ( symbolUnits == QgsUnitTypes::RenderMillimeters && mapUnits == QgsUnitTypes::DistanceMeters )
3236  {
3237  return scale / 1000;
3238  }
3239  }
3240  return 1.0;
3241 }
3242 
3243 void QgsVectorFileWriter::startRender( QgsFeatureRenderer *sourceRenderer, const QgsFields &fields )
3244 {
3245  mRenderer = createSymbologyRenderer( sourceRenderer );
3246  if ( !mRenderer )
3247  {
3248  return;
3249  }
3250 
3251  mRenderer->startRender( mRenderContext, fields );
3252 }
3253 
3254 void QgsVectorFileWriter::stopRender()
3255 {
3256  if ( !mRenderer )
3257  {
3258  return;
3259  }
3260 
3261  mRenderer->stopRender( mRenderContext );
3262 }
3263 
3264 std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer( QgsFeatureRenderer *sourceRenderer ) const
3265 {
3266  if ( mSymbologyExport == NoSymbology )
3267  {
3268  return nullptr;
3269  }
3270  if ( !sourceRenderer )
3271  {
3272  return nullptr;
3273  }
3274 
3275  return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->clone() );
3276 }
3277 
3278 void QgsVectorFileWriter::addRendererAttributes( QgsFeatureRenderer *renderer, QgsRenderContext &context, const QgsFields &fields, QgsAttributeList &attList )
3279 {
3280  if ( renderer )
3281  {
3282  const QSet<QString> rendererAttributes = renderer->usedAttributes( context );
3283  for ( const QString &attr : rendererAttributes )
3284  {
3285  int index = fields.lookupField( attr );
3286  if ( index != -1 )
3287  {
3288  attList.append( index );
3289  }
3290  }
3291  }
3292 }
3293 
3294 QStringList QgsVectorFileWriter::concatenateOptions( const QMap<QString, QgsVectorFileWriter::Option *> &options )
3295 {
3296  QStringList list;
3297  QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
3298 
3299  for ( it = options.constBegin(); it != options.constEnd(); ++it )
3300  {
3301  QgsVectorFileWriter::Option *option = it.value();
3302  switch ( option->type )
3303  {
3305  {
3306  QgsVectorFileWriter::IntOption *opt = dynamic_cast<QgsVectorFileWriter::IntOption *>( option );
3307  if ( opt )
3308  {
3309  list.append( QStringLiteral( "%1=%2" ).arg( it.key() ).arg( opt->defaultValue ) );
3310  }
3311  break;
3312  }
3313 
3315  {
3316  QgsVectorFileWriter::SetOption *opt = dynamic_cast<QgsVectorFileWriter::SetOption *>( option );
3317  if ( opt && !opt->defaultValue.isEmpty() )
3318  {
3319  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3320  }
3321  break;
3322  }
3323 
3325  {
3327  if ( opt && !opt->defaultValue.isNull() )
3328  {
3329  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->defaultValue ) );
3330  }
3331  break;
3332  }
3333 
3336  if ( opt )
3337  {
3338  list.append( QStringLiteral( "%1=%2" ).arg( it.key(), opt->mValue ) );
3339  }
3340  break;
3341  }
3342  }
3343 
3344  return list;
3345 }
3346 
3347 QgsVectorFileWriter::EditionCapabilities QgsVectorFileWriter::editionCapabilities( const QString &datasetName )
3348 {
3349  OGRSFDriverH hDriver = nullptr;
3350  gdal::ogr_datasource_unique_ptr hDS( OGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3351  if ( !hDS )
3352  return nullptr;
3353  QString drvName = OGR_Dr_GetName( hDriver );
3354  QgsVectorFileWriter::EditionCapabilities caps = nullptr;
3355  if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
3356  {
3357  // Shapefile driver returns True for a "foo.shp" dataset name,
3358  // creating "bar.shp" new layer, but this would be a bit confusing
3359  // for the user, so pretent that it does not support that
3360  if ( !( drvName == QLatin1String( "ESRI Shapefile" ) && QFile::exists( datasetName ) ) )
3361  caps |= CanAddNewLayer;
3362  }
3363  if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
3364  {
3365  caps |= CanDeleteLayer;
3366  }
3367  int layer_count = OGR_DS_GetLayerCount( hDS.get() );
3368  if ( layer_count )
3369  {
3370  OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
3371  if ( hLayer )
3372  {
3373  if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
3374  {
3375  caps |= CanAppendToExistingLayer;
3376  if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
3377  {
3379  }
3380  }
3381  }
3382  }
3383  return caps;
3384 }
3385 
3386 bool QgsVectorFileWriter::targetLayerExists( const QString &datasetName,
3387  const QString &layerNameIn )
3388 {
3389  OGRSFDriverH hDriver = nullptr;
3390  gdal::ogr_datasource_unique_ptr hDS( OGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3391  if ( !hDS )
3392  return false;
3393 
3394  QString layerName( layerNameIn );
3395  if ( layerName.isEmpty() )
3396  layerName = QFileInfo( datasetName ).baseName();
3397 
3398  return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3399 }
3400 
3401 
3402 bool QgsVectorFileWriter::areThereNewFieldsToCreate( const QString &datasetName,
3403  const QString &layerName,
3404  QgsVectorLayer *layer,
3405  const QgsAttributeList &attributes )
3406 {
3407  OGRSFDriverH hDriver = nullptr;
3408  gdal::ogr_datasource_unique_ptr hDS( OGROpen( datasetName.toUtf8().constData(), TRUE, &hDriver ) );
3409  if ( !hDS )
3410  return false;
3411  OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3412  if ( !hLayer )
3413  {
3414  return false;
3415  }
3416  bool ret = false;
3417  OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
3418  Q_FOREACH ( int idx, attributes )
3419  {
3420  QgsField fld = layer->fields().at( idx );
3421  if ( OGR_FD_GetFieldIndex( defn, fld.name().toUtf8().constData() ) < 0 )
3422  {
3423  ret = true;
3424  break;
3425  }
3426  }
3427  return ret;
3428 }
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.
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.
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const =0
Return a list of attributes required by this renderer.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Options to pass to writeAsVectorFormat()
virtual QgsVectorFileWriter::FieldValueConverter * clone() const
Creates a clone of the FieldValueConverter.
void setSymbologyScale(double scale)
Set reference scale for output.
int renderingPass() const
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h: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.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QMap< QString, QgsVectorFileWriter::Option * > layerOptions
ActionOnExistingFile
Combination of CanAddNewLayer, CanAppendToExistingLayer, CanAddNewFieldsToExistingLayer or CanDeleteL...
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:337
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.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
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.
Contains information about the context of a rendering operation.
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.
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.
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.
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.