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