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