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