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