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