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