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