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