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