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