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