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