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