44 #include <QTextStream>
53 #include <ogr_srs_api.h>
54 #include <cpl_error.h>
56 #include <cpl_string.h>
62 static OGRDataSourceH myOGROpen(
const char *pszName,
int bUpdate, OGRSFDriverH *phDriver )
64 OGRSFDriverH hDriver =
nullptr;
65 OGRDataSourceH hDS = OGROpen( pszName, bUpdate, &hDriver );
68 QString drvName = OGR_Dr_GetName( hDriver );
69 if ( drvName ==
"BNA" )
71 OGR_DS_Destroy( hDS );
98 const QString &vectorFileName,
99 const QString &fileEncoding,
103 const QString &driverName,
104 const QStringList &datasourceOptions,
105 const QStringList &layerOptions,
106 QString *newFilename,
108 QgsFeatureSink::SinkFlags sinkFlags,
117 init( vectorFileName, fileEncoding, fields, geometryType,
118 srs, driverName, datasourceOptions, layerOptions, newFilename,
nullptr,
123 const QString &vectorFileName,
124 const QString &fileEncoding,
128 const QString &driverName,
129 const QStringList &datasourceOptions,
130 const QStringList &layerOptions,
131 QString *newFilename,
134 const QString &layerName,
138 QgsFeatureSink::SinkFlags sinkFlags
141 , mWkbType( geometryType )
142 , mSymbologyExport( symbologyExport )
143 , mSymbologyScale( 1.0 )
145 init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName,
146 datasourceOptions, layerOptions, newFilename, fieldValueConverter,
147 layerName, action, newLayer, sinkFlags, transformContext );
151 const QString &fileName,
157 QgsFeatureSink::SinkFlags sinkFlags,
158 QString *newFilename,
172 if ( driverName == QLatin1String(
"MapInfo MIF" ) )
176 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
177 GDALDriverH gdalDriver = GDALGetDriverByName( driverName.toLocal8Bit().constData() );
185 return CSLFetchBoolean(
driverMetadata, GDAL_DCAP_FEATURE_STYLES,
false );
187 return driverName == QLatin1String(
"DXF" ) || driverName == QLatin1String(
"KML" ) || driverName == QLatin1String(
"MapInfo File" );
191 void QgsVectorFileWriter::init( QString vectorFileName,
192 QString fileEncoding,
196 const QString &driverName,
197 QStringList datasourceOptions,
198 QStringList layerOptions,
199 QString *newFilename,
200 FieldValueConverter *fieldValueConverter,
201 const QString &layerNameIn,
202 ActionOnExistingFile action,
203 QString *newLayer, SinkFlags sinkFlags,
208 if ( vectorFileName.isEmpty() )
215 if ( driverName == QLatin1String(
"MapInfo MIF" ) )
219 else if ( driverName == QLatin1String(
"SpatiaLite" ) )
222 if ( !datasourceOptions.contains( QStringLiteral(
"SPATIALITE=YES" ) ) )
224 datasourceOptions.append( QStringLiteral(
"SPATIALITE=YES" ) );
227 else if ( driverName == QLatin1String(
"DBF file" ) )
230 if ( !layerOptions.contains( QStringLiteral(
"SHPT=NULL" ) ) )
232 layerOptions.append( QStringLiteral(
"SHPT=NULL" ) );
242 OGRSFDriverH poDriver;
245 poDriver = OGRGetDriverByName(
mOgrDriverName.toLocal8Bit().constData() );
249 mErrorMessage = QObject::tr(
"OGR driver for '%1' not found (OGR error: %2)" )
251 QString::fromUtf8( CPLGetLastErrorMsg() ) );
261 if ( layerOptions.join( QString() ).toUpper().indexOf( QLatin1String(
"ENCODING=" ) ) == -1 )
266 if ( driverName == QLatin1String(
"ESRI Shapefile" ) && !vectorFileName.endsWith( QLatin1String(
".shp" ), Qt::CaseInsensitive ) )
268 vectorFileName += QLatin1String(
".shp" );
270 else if ( driverName == QLatin1String(
"DBF file" ) && !vectorFileName.endsWith( QLatin1String(
".dbf" ), Qt::CaseInsensitive ) )
272 vectorFileName += QLatin1String(
".dbf" );
282 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
283 QStringList allExts = metadata.ext.split(
' ', QString::SkipEmptyParts );
285 QStringList allExts = metadata.ext.split(
' ', Qt::SkipEmptyParts );
288 const auto constAllExts = allExts;
289 for (
const QString &ext : constAllExts )
291 if ( vectorFileName.endsWith(
'.' + ext, Qt::CaseInsensitive ) )
300 vectorFileName +=
'.' + allExts[0];
306 if ( vectorFileName.endsWith( QLatin1String(
".gdb" ), Qt::CaseInsensitive ) )
308 QDir dir( vectorFileName );
311 QFileInfoList fileList = dir.entryInfoList(
312 QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst );
313 const auto constFileList = fileList;
314 for (
const QFileInfo &info : constFileList )
316 QFile::remove( info.absoluteFilePath() );
319 QDir().rmdir( vectorFileName );
323 QFile::remove( vectorFileName );
328 if ( metadataFound && !metadata.compulsoryEncoding.isEmpty() )
330 if ( fileEncoding.compare( metadata.compulsoryEncoding, Qt::CaseInsensitive ) != 0 )
332 QgsDebugMsgLevel( QStringLiteral(
"forced %1 encoding for %2" ).arg( metadata.compulsoryEncoding, driverName ), 2 );
333 fileEncoding = metadata.compulsoryEncoding;
338 char **options =
nullptr;
339 if ( !datasourceOptions.isEmpty() )
341 options =
new char *[ datasourceOptions.size() + 1 ];
342 for (
int i = 0; i < datasourceOptions.size(); i++ )
344 QgsDebugMsgLevel( QStringLiteral(
"-dsco=%1" ).arg( datasourceOptions[i] ), 2 );
345 options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().constData() );
347 options[ datasourceOptions.size()] =
nullptr;
353 mDS.reset( OGR_Dr_CreateDataSource( poDriver, vectorFileName.toUtf8().constData(), options ) );
355 mDS.reset( myOGROpen( vectorFileName.toUtf8().constData(), TRUE,
nullptr ) );
359 for (
int i = 0; i < datasourceOptions.size(); i++ )
360 CPLFree( options[i] );
369 mErrorMessage = QObject::tr(
"Creation of data source failed (OGR error: %1)" )
370 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
372 mErrorMessage = QObject::tr(
"Opening of data source in update mode failed (OGR error: %1)" )
373 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
377 QString layerName( layerNameIn );
378 if ( layerName.isEmpty() )
379 layerName = QFileInfo( vectorFileName ).baseName();
383 const int layer_count = OGR_DS_GetLayerCount(
mDS.get() );
384 for (
int i = 0; i < layer_count; i++ )
386 OGRLayerH hLayer = OGR_DS_GetLayer(
mDS.get(), i );
387 if ( EQUAL( OGR_L_GetName( hLayer ), layerName.toUtf8().constData() ) )
389 if ( OGR_DS_DeleteLayer(
mDS.get(), i ) != OGRERR_NONE )
392 mErrorMessage = QObject::tr(
"Overwriting of existing layer failed (OGR error: %1)" )
393 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
407 QgsDebugMsgLevel( QStringLiteral(
"Opened data source in update mode" ), 2 );
411 mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
414 QgsDebugMsg(
"error finding QTextCodec for " + fileEncoding );
417 QString enc = settings.
value( QStringLiteral(
"UI/encoding" ),
"System" ).toString();
418 mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
421 QgsDebugMsg(
"error finding QTextCodec for " + enc );
422 mCodec = QTextCodec::codecForLocale();
428 if ( driverName == QLatin1String(
"KML" ) || driverName == QLatin1String(
"LIBKML" ) || driverName == QLatin1String(
"GPX" ) )
430 if ( srs.
authid() != QLatin1String(
"EPSG:4326" ) )
443 mOgrRef = OSRNewSpatialReference( srsWkt.toLocal8Bit().constData() );
444 #if GDAL_VERSION_MAJOR >= 3
447 OSRSetAxisMappingStrategy(
mOgrRef, OAMS_TRADITIONAL_GIS_ORDER );
456 int optIndex = layerOptions.indexOf( QLatin1String(
"FEATURE_DATASET=" ) );
457 if ( optIndex != -1 )
459 layerOptions.removeAt( optIndex );
462 if ( !layerOptions.isEmpty() )
464 options =
new char *[ layerOptions.size() + 1 ];
465 for (
int i = 0; i < layerOptions.size(); i++ )
468 options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().constData() );
470 options[ layerOptions.size()] =
nullptr;
474 CPLSetConfigOption(
"SHAPE_ENCODING",
"" );
478 mLayer = OGR_DS_CreateLayer(
mDS.get(), layerName.toUtf8().constData(),
mOgrRef, wkbType, options );
481 *newLayer = OGR_L_GetName(
mLayer );
482 if ( driverName == QLatin1String(
"GPX" ) )
489 if ( !EQUAL( layerName.toUtf8().constData(),
"track_points" ) &&
490 !EQUAL( layerName.toUtf8().constData(),
"route_points" ) )
492 *newLayer = QStringLiteral(
"waypoints" );
499 const char *pszForceGPXTrack
500 = CSLFetchNameValue( options,
"FORCE_GPX_TRACK" );
501 if ( pszForceGPXTrack && CPLTestBool( pszForceGPXTrack ) )
502 *newLayer = QStringLiteral(
"tracks" );
504 *newLayer = QStringLiteral(
"routes" );
511 const char *pszForceGPXRoute
512 = CSLFetchNameValue( options,
"FORCE_GPX_ROUTE" );
513 if ( pszForceGPXRoute && CPLTestBool( pszForceGPXRoute ) )
514 *newLayer = QStringLiteral(
"routes" );
516 *newLayer = QStringLiteral(
"tracks" );
526 else if ( driverName == QLatin1String(
"DGN" ) )
528 mLayer = OGR_DS_GetLayerByName(
mDS.get(),
"elements" );
532 mLayer = OGR_DS_GetLayerByName(
mDS.get(), layerName.toUtf8().constData() );
537 for (
int i = 0; i < layerOptions.size(); i++ )
538 CPLFree( options[i] );
547 QString layerName = vectorFileName.left( vectorFileName.indexOf( QLatin1String(
".shp" ), Qt::CaseInsensitive ) );
548 QFile prjFile( layerName +
".qpj" );
549 #if PROJ_VERSION_MAJOR<6
550 if ( prjFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
552 QTextStream prjStream( &prjFile );
553 prjStream << srs.
toWkt().toLocal8Bit().constData() << endl;
558 QgsDebugMsg(
"Couldn't open file " + layerName +
".qpj" );
561 if ( prjFile.exists() )
570 mErrorMessage = QObject::tr(
"Creation of layer failed (OGR error: %1)" )
571 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
573 mErrorMessage = QObject::tr(
"Opening of layer failed (OGR error: %1)" )
574 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
579 OGRFeatureDefnH defn = OGR_L_GetLayerDefn(
mLayer );
588 QSet<int> existingIdxs;
598 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
602 if ( fieldValueConverter )
604 attrField = fieldValueConverter->fieldDefinition( fields.
at( fldIdx ) );
607 QString name( attrField.
name() );
610 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
618 OGRFieldType ogrType = OFTString;
619 int ogrWidth = attrField.
length();
620 int ogrPrecision = attrField.
precision();
621 if ( ogrPrecision > 0 )
624 switch ( attrField.
type() )
626 case QVariant::LongLong:
628 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
629 if ( pszDataTypes && strstr( pszDataTypes,
"Integer64" ) )
630 ogrType = OFTInteger64;
633 ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
637 case QVariant::String:
639 if ( ( ogrWidth <= 0 || ogrWidth > 255 ) &&
mOgrDriverName == QLatin1String(
"ESRI Shapefile" ) )
644 ogrType = OFTInteger;
645 ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
650 ogrType = OFTInteger;
655 case QVariant::Double:
675 case QVariant::DateTime:
683 ogrType = OFTDateTime;
687 case QVariant::ByteArray:
691 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,4,0)
694 if ( attrField.
subType() == QVariant::String )
696 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
697 if ( pszDataTypes && strstr( pszDataTypes,
"StringList" ) )
699 ogrType = OFTStringList;
700 supportsStringList =
true;
715 mErrorMessage = QObject::tr(
"Unsupported type for field %1" )
716 .arg( attrField.
name() );
721 if (
mOgrDriverName == QLatin1String(
"SQLite" ) && name.compare( QLatin1String(
"ogc_fid" ), Qt::CaseInsensitive ) == 0 )
724 for ( i = 0; i < 10; i++ )
726 name = QStringLiteral(
"ogc_fid%1" ).arg( i );
729 for ( j = 0; j < fields.
size() && name.compare( fields.
at( j ).
name(), Qt::CaseInsensitive ) != 0; j++ )
732 if ( j == fields.
size() )
738 mErrorMessage = QObject::tr(
"No available replacement for internal fieldname ogc_fid found" ).arg( attrField.
name() );
743 QgsMessageLog::logMessage( QObject::tr(
"Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr(
"OGR" ) );
750 OGR_Fld_SetWidth( fld.get(), ogrWidth );
753 if ( ogrPrecision >= 0 )
755 OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
758 switch ( attrField.
type() )
761 OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
769 " type " + QString( QVariant::typeToName( attrField.
type() ) ) +
770 " width " + QString::number( ogrWidth ) +
771 " precision " + QString::number( ogrPrecision ), 2 );
772 if ( OGR_L_CreateField(
mLayer, fld.get(),
true ) != OGRERR_NONE )
775 mErrorMessage = QObject::tr(
"Creation of field %1 failed (OGR error: %2)" )
776 .arg( attrField.
name(),
777 QString::fromUtf8( CPLGetLastErrorMsg() ) );
782 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
783 QgsDebugMsgLevel( QStringLiteral(
"returned field index for %1: %2" ).arg( name ).arg( ogrIdx ), 2 );
784 if ( ogrIdx < 0 || existingIdxs.contains( ogrIdx ) )
787 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
792 mErrorMessage = QObject::tr(
"Created field %1 not found (OGR error: %2)" )
793 .arg( attrField.
name(),
794 QString::fromUtf8( CPLGetLastErrorMsg() ) );
800 existingIdxs.insert( ogrIdx );
808 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
811 QString name( attrField.
name() );
812 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
824 int fidIdx = fields.
lookupField( QStringLiteral(
"FID" ) );
835 *newFilename = vectorFileName;
838 mUsingTransaction =
true;
839 if ( OGRERR_NONE != OGR_L_StartTransaction(
mLayer ) )
841 mUsingTransaction =
false;
851 class QgsVectorFileWriterMetadataContainer
855 QgsVectorFileWriterMetadataContainer()
857 QMap<QString, QgsVectorFileWriter::Option *> datasetOptions;
858 QMap<QString, QgsVectorFileWriter::Option *> layerOptions;
861 datasetOptions.clear();
862 layerOptions.clear();
864 driverMetadata.insert( QStringLiteral(
"AVCE00" ),
866 QStringLiteral(
"Arc/Info ASCII Coverage" ),
867 QObject::tr(
"Arc/Info ASCII Coverage" ),
868 QStringLiteral(
"*.e00" ),
869 QStringLiteral(
"e00" ),
876 datasetOptions.clear();
877 layerOptions.clear();
880 QObject::tr(
"New BNA files are created by the "
881 "systems default line termination conventions. "
882 "This may be overridden here." ),
884 << QStringLiteral(
"CRLF" )
885 << QStringLiteral(
"LF" ),
891 QObject::tr(
"By default, BNA files are created in multi-line format. "
892 "For each record, the first line contains the identifiers and the "
893 "type/number of coordinates to follow. Each following line contains "
894 "a pair of coordinates." ),
899 QObject::tr(
"BNA records may contain from 2 to 4 identifiers per record. "
900 "Some software packages only support a precise number of identifiers. "
901 "You can override the default value (2) by a precise value." ),
903 << QStringLiteral(
"2" )
904 << QStringLiteral(
"3" )
905 << QStringLiteral(
"4" )
906 << QStringLiteral(
"NB_SOURCE_FIELDS" ),
907 QStringLiteral(
"2" )
911 QObject::tr(
"The BNA writer will try to recognize ellipses and circles when writing a polygon. "
912 "This will only work if the feature has previously been read from a BNA file. "
913 "As some software packages do not support ellipses/circles in BNA data file, "
914 "it may be useful to tell the writer by specifying ELLIPSES_AS_ELLIPSES=NO not "
915 "to export them as such, but keep them as polygons." ),
920 QObject::tr(
"Limit the number of coordinate pairs per line in multiline format." ),
925 QObject::tr(
"Set the number of decimal for coordinates. Default value is 10." ),
929 driverMetadata.insert( QStringLiteral(
"BNA" ),
931 QStringLiteral(
"Atlas BNA" ),
932 QObject::tr(
"Atlas BNA" ),
933 QStringLiteral(
"*.bna" ),
934 QStringLiteral(
"bna" ),
941 datasetOptions.clear();
942 layerOptions.clear();
945 QObject::tr(
"By default when creating new .csv files they "
946 "are created with the line termination conventions "
947 "of the local platform (CR/LF on Win32 or LF on all other systems). "
948 "This may be overridden through the use of the LINEFORMAT option." ),
950 << QStringLiteral(
"CRLF" )
951 << QStringLiteral(
"LF" ),
957 QObject::tr(
"By default, the geometry of a feature written to a .csv file is discarded. "
958 "It is possible to export the geometry in its WKT representation by "
959 "specifying GEOMETRY=AS_WKT. It is also possible to export point geometries "
960 "into their X,Y,Z components by specifying GEOMETRY=AS_XYZ, GEOMETRY=AS_XY "
961 "or GEOMETRY=AS_YX." ),
963 << QStringLiteral(
"AS_WKT" )
964 << QStringLiteral(
"AS_XYZ" )
965 << QStringLiteral(
"AS_XY" )
966 << QStringLiteral(
"AS_YX" ),
972 QObject::tr(
"Create the associated .csvt file to describe the type of each "
973 "column of the layer and its optional width and precision." ),
978 QObject::tr(
"Field separator character." ),
980 << QStringLiteral(
"COMMA" )
981 << QStringLiteral(
"SEMICOLON" )
982 << QStringLiteral(
"TAB" ),
983 QStringLiteral(
"COMMA" )
986 #if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
988 QObject::tr(
"Double-quote strings. IF_AMBIGUOUS means that string values that look like numbers will be quoted." ),
990 << QStringLiteral(
"IF_NEEDED" )
991 << QStringLiteral(
"IF_AMBIGUOUS" )
992 << QStringLiteral(
"ALWAYS" ),
993 QStringLiteral(
"IF_AMBIGUOUS" )
998 QObject::tr(
"Write a UTF-8 Byte Order Mark (BOM) at the start of the file." ),
1002 driverMetadata.insert( QStringLiteral(
"CSV" ),
1004 QStringLiteral(
"Comma Separated Value [CSV]" ),
1005 QObject::tr(
"Comma Separated Value [CSV]" ),
1006 QStringLiteral(
"*.csv" ),
1007 QStringLiteral(
"csv" ),
1013 #if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0)
1015 datasetOptions.clear();
1016 layerOptions.clear();
1018 driverMetadata.insert( QStringLiteral(
"FlatGeobuf" ),
1020 QStringLiteral(
"FlatGeobuf" ),
1021 QObject::tr(
"FlatGeobuf" ),
1022 QStringLiteral(
"*.fgb" ),
1023 QStringLiteral(
"fgb" ),
1031 datasetOptions.clear();
1032 layerOptions.clear();
1035 QObject::tr(
"Override the type of shapefile created. "
1036 "Can be one of NULL for a simple .dbf file with no .shp file, POINT, "
1037 "ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or "
1038 "MULTIPOINTZ for 3D;" ) +
1039 QObject::tr(
" POINTM, ARCM, POLYGONM or MULTIPOINTM for measured geometries"
1040 " and POINTZM, ARCZM, POLYGONZM or MULTIPOINTZM for 3D measured"
1042 #
if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
1043 QObject::tr(
" MULTIPATCH files are supported since GDAL 2.2." ) +
1047 << QStringLiteral(
"NULL" )
1048 << QStringLiteral(
"POINT" )
1049 << QStringLiteral(
"ARC" )
1050 << QStringLiteral(
"POLYGON" )
1051 << QStringLiteral(
"MULTIPOINT" )
1052 << QStringLiteral(
"POINTZ" )
1053 << QStringLiteral(
"ARCZ" )
1054 << QStringLiteral(
"POLYGONZ" )
1055 << QStringLiteral(
"MULTIPOINTZ" )
1056 << QStringLiteral(
"POINTM" )
1057 << QStringLiteral(
"ARCM" )
1058 << QStringLiteral(
"POLYGONM" )
1059 << QStringLiteral(
"MULTIPOINTM" )
1060 << QStringLiteral(
"POINTZM" )
1061 << QStringLiteral(
"ARCZM" )
1062 << QStringLiteral(
"POLYGONZM" )
1063 << QStringLiteral(
"MULTIPOINTZM" )
1064 #
if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
1065 << QStringLiteral(
"MULTIPATCH" )
1076 QObject::tr(
"Set the encoding value in the DBF file. "
1077 "The default value is LDID/87. It is not clear "
1078 "what other values may be appropriate." ),
1086 QObject::tr(
"Set to YES to resize fields to their optimal size." ),
1090 driverMetadata.insert( QStringLiteral(
"ESRI" ),
1092 QStringLiteral(
"ESRI Shapefile" ),
1093 QObject::tr(
"ESRI Shapefile" ),
1094 QStringLiteral(
"*.shp" ),
1095 QStringLiteral(
"shp" ),
1102 datasetOptions.clear();
1103 layerOptions.clear();
1105 driverMetadata.insert( QStringLiteral(
"DBF File" ),
1107 QStringLiteral(
"DBF File" ),
1108 QObject::tr(
"DBF File" ),
1109 QStringLiteral(
"*.dbf" ),
1110 QStringLiteral(
"dbf" ),
1117 datasetOptions.clear();
1118 layerOptions.clear();
1120 driverMetadata.insert( QStringLiteral(
"FMEObjects Gateway" ),
1122 QStringLiteral(
"FMEObjects Gateway" ),
1123 QObject::tr(
"FMEObjects Gateway" ),
1124 QStringLiteral(
"*.fdd" ),
1125 QStringLiteral(
"fdd" ),
1132 datasetOptions.clear();
1133 layerOptions.clear();
1136 QObject::tr(
"Set to YES to write a bbox property with the bounding box "
1137 "of the geometries at the feature and feature collection level." ),
1142 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1143 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1148 QObject::tr(
"Whether to use RFC 7946 standard. "
1149 "If disabled GeoJSON 2008 initial version will be used. "
1150 "Default is NO (thus GeoJSON 2008). See also Documentation (via Help button)" ),
1154 driverMetadata.insert( QStringLiteral(
"GeoJSON" ),
1156 QStringLiteral(
"GeoJSON" ),
1157 QObject::tr(
"GeoJSON" ),
1158 QStringLiteral(
"*.geojson" ),
1159 QStringLiteral(
"geojson" ),
1162 QStringLiteral(
"UTF-8" )
1167 datasetOptions.clear();
1168 layerOptions.clear();
1171 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1172 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1177 QObject::tr(
"Whether to start records with the RS=0x1E character (RFC 8142 standard). "
1178 "Defaults to NO: Newline Delimited JSON (geojsonl). \n"
1179 "If set to YES: RFC 8142 standard: GeoJSON Text Sequences (geojsons)." ),
1183 driverMetadata.insert( QStringLiteral(
"GeoJSONSeq" ),
1185 QStringLiteral(
"GeoJSON - Newline Delimited" ),
1186 QObject::tr(
"GeoJSON - Newline Delimited" ),
1187 QStringLiteral(
"*.geojsonl *.geojsons *.json" ),
1188 QStringLiteral(
"json" ),
1191 QStringLiteral(
"UTF-8" )
1196 datasetOptions.clear();
1197 layerOptions.clear();
1200 QObject::tr(
"whether the document must be in RSS 2.0 or Atom 1.0 format. "
1201 "Default value : RSS" ),
1203 << QStringLiteral(
"RSS" )
1204 << QStringLiteral(
"ATOM" ),
1205 QStringLiteral(
"RSS" )
1209 QObject::tr(
"The encoding of location information. Default value : SIMPLE. "
1210 "W3C_GEO only supports point geometries. "
1211 "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
1213 << QStringLiteral(
"SIMPLE" )
1214 << QStringLiteral(
"GML" )
1215 << QStringLiteral(
"W3C_GEO" ),
1216 QStringLiteral(
"SIMPLE" )
1220 QObject::tr(
"If defined to YES, extension fields will be written. "
1221 "If the field name not found in the base schema matches "
1222 "the foo_bar pattern, foo will be considered as the namespace "
1223 "of the element, and a <foo:bar> element will be written. "
1224 "Otherwise, elements will be written in the <ogr:> namespace." ),
1229 QObject::tr(
"If defined to NO, only <entry> or <item> elements will be written. "
1230 "The user will have to provide the appropriate header and footer of the document." ),
1235 QObject::tr(
"XML content that will be put between the <channel> element and the "
1236 "first <item> element for a RSS document, or between the xml tag and "
1237 "the first <entry> element for an Atom document." ),
1242 QObject::tr(
"Value put inside the <title> element in the header. "
1243 "If not provided, a dummy value will be used as that element is compulsory." ),
1248 QObject::tr(
"Value put inside the <description> element in the header. "
1249 "If not provided, a dummy value will be used as that element is compulsory." ),
1254 QObject::tr(
"Value put inside the <link> element in the header. "
1255 "If not provided, a dummy value will be used as that element is compulsory." ),
1260 QObject::tr(
"Value put inside the <updated> element in the header. "
1261 "Should be formatted as a XML datetime. "
1262 "If not provided, a dummy value will be used as that element is compulsory." ),
1267 QObject::tr(
"Value put inside the <author><name> element in the header. "
1268 "If not provided, a dummy value will be used as that element is compulsory." ),
1273 QObject::tr(
"Value put inside the <id> element in the header. "
1274 "If not provided, a dummy value will be used as that element is compulsory." ),
1278 driverMetadata.insert( QStringLiteral(
"GeoRSS" ),
1280 QStringLiteral(
"GeoRSS" ),
1281 QObject::tr(
"GeoRSS" ),
1282 QStringLiteral(
"*.xml" ),
1283 QStringLiteral(
"xml" ),
1286 QStringLiteral(
"UTF-8" )
1291 datasetOptions.clear();
1292 layerOptions.clear();
1295 QObject::tr(
"If provided, this URI will be inserted as the schema location. "
1296 "Note that the schema file isn't actually accessed by OGR, so it "
1297 "is up to the user to ensure it will match the schema of the OGR "
1298 "produced GML data file." ),
1303 QObject::tr(
"This writes a GML application schema file to a corresponding "
1304 ".xsd file (with the same basename). If INTERNAL is used the "
1305 "schema is written within the GML file, but this is experimental "
1306 "and almost certainly not valid XML. "
1307 "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
1309 << QStringLiteral(
"EXTERNAL" )
1310 << QStringLiteral(
"INTERNAL" )
1311 << QStringLiteral(
"OFF" ),
1312 QStringLiteral(
"EXTERNAL" )
1316 QObject::tr(
"This is the prefix for the application target namespace." ),
1317 QStringLiteral(
"ogr" )
1321 QObject::tr(
"Can be set to TRUE to avoid writing the prefix of the "
1322 "application target namespace in the GML file." ),
1327 QObject::tr(
"Defaults to 'http://ogr.maptools.org/'. "
1328 "This is the application target namespace." ),
1329 QStringLiteral(
"http://ogr.maptools.org/" )
1333 QObject::tr(
"If not specified, GML2 will be used." ),
1335 << QStringLiteral(
"GML3" )
1336 << QStringLiteral(
"GML3Deegree" )
1337 << QStringLiteral(
"GML3.2" ),
1343 QObject::tr(
"Only valid when FORMAT=GML3/GML3Degree/GML3.2. Default to YES. "
1344 "If YES, SRS with EPSG authority will be written with the "
1345 "'urn:ogc:def:crs:EPSG::' prefix. In the case the SRS is a "
1346 "geographic SRS without explicit AXIS order, but that the same "
1347 "SRS authority code imported with ImportFromEPSGA() should be "
1348 "treated as lat/long, then the function will take care of coordinate "
1349 "order swapping. If set to NO, SRS with EPSG authority will be "
1350 "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
1355 QObject::tr(
"only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
1356 "If set to NO, the <gml:boundedBy> element will not be written for "
1362 QObject::tr(
"Default to YES. If YES, the output will be indented with spaces "
1363 "for more readability, but at the expense of file size." ),
1368 driverMetadata.insert( QStringLiteral(
"GML" ),
1370 QStringLiteral(
"Geography Markup Language [GML]" ),
1371 QObject::tr(
"Geography Markup Language [GML]" ),
1372 QStringLiteral(
"*.gml" ),
1373 QStringLiteral(
"gml" ),
1376 QStringLiteral(
"UTF-8" )
1381 datasetOptions.clear();
1382 layerOptions.clear();
1385 QObject::tr(
"Human-readable identifier (e.g. short name) for the layer content" ),
1390 QObject::tr(
"Human-readable description for the layer content" ),
1395 QObject::tr(
"Name for the feature identifier column" ),
1396 QStringLiteral(
"fid" )
1400 QObject::tr(
"Name for the geometry column" ),
1401 QStringLiteral(
"geom" )
1405 QObject::tr(
"If a spatial index must be created." ),
1409 driverMetadata.insert( QStringLiteral(
"GPKG" ),
1411 QStringLiteral(
"GeoPackage" ),
1412 QObject::tr(
"GeoPackage" ),
1413 QStringLiteral(
"*.gpkg" ),
1414 QStringLiteral(
"gpkg" ),
1417 QStringLiteral(
"UTF-8" )
1422 datasetOptions.clear();
1423 layerOptions.clear();
1425 driverMetadata.insert( QStringLiteral(
"GMT" ),
1427 QStringLiteral(
"Generic Mapping Tools [GMT]" ),
1428 QObject::tr(
"Generic Mapping Tools [GMT]" ),
1429 QStringLiteral(
"*.gmt" ),
1430 QStringLiteral(
"gmt" ),
1437 datasetOptions.clear();
1438 layerOptions.clear();
1441 QObject::tr(
"By default when writing a layer whose features are of "
1442 "type wkbLineString, the GPX driver chooses to write "
1443 "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1444 "they will be written as tracks." ),
1449 QObject::tr(
"By default when writing a layer whose features are of "
1450 "type wkbMultiLineString, the GPX driver chooses to write "
1451 "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1452 "they will be written as routes, provided that the multilines "
1453 "are composed of only one single line." ),
1458 QObject::tr(
"If GPX_USE_EXTENSIONS=YES is specified, "
1459 "extra fields will be written inside the <extensions> tag." ),
1464 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1465 "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1466 QStringLiteral(
"ogr" )
1470 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1471 "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1472 QStringLiteral(
"http://osgeo.org/gdal" )
1476 QObject::tr(
"By default files are created with the line termination "
1477 "conventions of the local platform (CR/LF on win32 or LF "
1478 "on all other systems). This may be overridden through use "
1479 "of the LINEFORMAT layer creation option which may have a value "
1480 "of CRLF (DOS format) or LF (Unix format)." ),
1482 << QStringLiteral(
"CRLF" )
1483 << QStringLiteral(
"LF" ),
1488 driverMetadata.insert( QStringLiteral(
"GPX" ),
1490 QStringLiteral(
"GPS eXchange Format [GPX]" ),
1491 QObject::tr(
"GPS eXchange Format [GPX]" ),
1492 QStringLiteral(
"*.gpx" ),
1493 QStringLiteral(
"gpx" ),
1496 QStringLiteral(
"UTF-8" )
1501 datasetOptions.clear();
1502 layerOptions.clear();
1504 driverMetadata.insert( QStringLiteral(
"Interlis 1" ),
1506 QStringLiteral(
"INTERLIS 1" ),
1507 QObject::tr(
"INTERLIS 1" ),
1508 QStringLiteral(
"*.itf *.xml *.ili" ),
1509 QStringLiteral(
"ili" ),
1516 datasetOptions.clear();
1517 layerOptions.clear();
1519 driverMetadata.insert( QStringLiteral(
"Interlis 2" ),
1521 QStringLiteral(
"INTERLIS 2" ),
1522 QObject::tr(
"INTERLIS 2" ),
1523 QStringLiteral(
"*.xtf *.xml *.ili" ),
1524 QStringLiteral(
"ili" ),
1531 datasetOptions.clear();
1532 layerOptions.clear();
1535 QObject::tr(
"Allows you to specify the field to use for the KML <name> element." ),
1536 QStringLiteral(
"Name" )
1540 QObject::tr(
"Allows you to specify the field to use for the KML <description> element." ),
1541 QStringLiteral(
"Description" )
1545 QObject::tr(
"Allows you to specify the AltitudeMode to use for KML geometries. "
1546 "This will only affect 3D geometries and must be one of the valid KML options." ),
1548 << QStringLiteral(
"clampToGround" )
1549 << QStringLiteral(
"relativeToGround" )
1550 << QStringLiteral(
"absolute" ),
1551 QStringLiteral(
"relativeToGround" )
1554 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
1556 QObject::tr(
"The DOCUMENT_ID datasource creation option can be used to specified "
1557 "the id of the root <Document> node. The default value is root_doc." ),
1558 QStringLiteral(
"root_doc" )
1562 driverMetadata.insert( QStringLiteral(
"KML" ),
1564 QStringLiteral(
"Keyhole Markup Language [KML]" ),
1565 QObject::tr(
"Keyhole Markup Language [KML]" ),
1566 QStringLiteral(
"*.kml" ),
1567 QStringLiteral(
"kml" ),
1570 QStringLiteral(
"UTF-8" )
1575 datasetOptions.clear();
1576 layerOptions.clear();
1578 auto insertMapInfoOptions = []( QMap<QString, QgsVectorFileWriter::Option *> &datasetOptions, QMap<QString, QgsVectorFileWriter::Option *> &layerOptions )
1581 QObject::tr(
"Use this to turn on 'quick spatial index mode'. "
1582 "In this mode writing files can be about 5 times faster, "
1583 "but spatial queries can be up to 30 times slower." ),
1585 << QStringLiteral(
"QUICK" )
1586 << QStringLiteral(
"OPTIMIZED" ),
1587 QStringLiteral(
"QUICK" ),
1592 QObject::tr(
"(multiples of 512): Block size for .map files. Defaults "
1593 "to 512. MapInfo 15.2 and above creates .tab files with a "
1594 "blocksize of 16384 bytes. Any MapInfo version should be "
1595 "able to handle block sizes from 512 to 32256." ),
1599 QObject::tr(
"xmin,ymin,xmax,ymax: Define custom layer bounds to increase the "
1600 "accuracy of the coordinates. Note: the geometry of written "
1601 "features must be within the defined box." ),
1605 insertMapInfoOptions( datasetOptions, layerOptions );
1607 driverMetadata.insert( QStringLiteral(
"MapInfo File" ),
1609 QStringLiteral(
"Mapinfo" ),
1610 QObject::tr(
"Mapinfo TAB" ),
1611 QStringLiteral(
"*.tab" ),
1612 QStringLiteral(
"tab" ),
1617 datasetOptions.clear();
1618 layerOptions.clear();
1619 insertMapInfoOptions( datasetOptions, layerOptions );
1622 driverMetadata.insert( QStringLiteral(
"MapInfo MIF" ),
1624 QStringLiteral(
"Mapinfo" ),
1625 QObject::tr(
"Mapinfo MIF" ),
1626 QStringLiteral(
"*.mif" ),
1627 QStringLiteral(
"mif" ),
1634 datasetOptions.clear();
1635 layerOptions.clear();
1638 QObject::tr(
"Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1639 "seed file should be used. This option is ignored if the SEED option is provided." ),
1644 QObject::tr(
"Override the seed file to use." ),
1649 QObject::tr(
"Indicate whether the whole seed file should be copied. "
1650 "If not, only the first three elements will be copied." ),
1655 QObject::tr(
"Indicates whether the color table should be copied from the seed file." ),
1660 QObject::tr(
"Override the master unit name from the seed file with "
1661 "the provided one or two character unit name." ),
1666 QObject::tr(
"Override the sub unit name from the seed file with the provided "
1667 "one or two character unit name." ),
1672 QObject::tr(
"Override the number of subunits per master unit. "
1673 "By default the seed file value is used." ),
1678 QObject::tr(
"Override the number of UORs (Units of Resolution) "
1679 "per sub unit. By default the seed file value is used." ),
1684 QObject::tr(
"ORIGIN=x,y,z: Override the origin of the design plane. "
1685 "By default the origin from the seed file is used." ),
1689 driverMetadata.insert( QStringLiteral(
"DGN" ),
1691 QStringLiteral(
"Microstation DGN" ),
1692 QObject::tr(
"Microstation DGN" ),
1693 QStringLiteral(
"*.dgn" ),
1694 QStringLiteral(
"dgn" ),
1701 datasetOptions.clear();
1702 layerOptions.clear();
1705 QObject::tr(
"Should update files be incorporated into the base data on the fly." ),
1707 << QStringLiteral(
"APPLY" )
1708 << QStringLiteral(
"IGNORE" ),
1709 QStringLiteral(
"APPLY" )
1713 QObject::tr(
"Should multipoint soundings be split into many single point sounding features. "
1714 "Multipoint geometries are not well handled by many formats, "
1715 "so it can be convenient to split single sounding features with many points "
1716 "into many single point features." ),
1721 QObject::tr(
"Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1722 "of the sounding. This should only be enabled when SPLIT_MULTIPOINT is "
1728 QObject::tr(
"Should all the low level geometry primitives be returned as special "
1729 "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1734 QObject::tr(
"If enabled, numeric attributes assigned an empty string as a value will "
1735 "be preserved as a special numeric value. This option should not generally "
1736 "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1741 QObject::tr(
"Should LNAM and LNAM_REFS fields be attached to features capturing "
1742 "the feature to feature relationships in the FFPT group of the S-57 file." ),
1747 QObject::tr(
"Should additional attributes relating features to their underlying "
1748 "geometric primitives be attached. These are the values of the FSPT group, "
1749 "and are primarily needed when doing S-57 to S-57 translations." ),
1754 QObject::tr(
"Should attribute values be recoded to UTF-8 from the character encoding "
1755 "specified in the S57 DSSI record." ),
1761 driverMetadata.insert( QStringLiteral(
"S57" ),
1763 QStringLiteral(
"S-57 Base file" ),
1764 QObject::tr(
"S-57 Base file" ),
1765 QStringLiteral(
"*.000" ),
1766 QStringLiteral(
"000" ),
1773 datasetOptions.clear();
1774 layerOptions.clear();
1776 driverMetadata.insert( QStringLiteral(
"SDTS" ),
1778 QStringLiteral(
"Spatial Data Transfer Standard [SDTS]" ),
1779 QObject::tr(
"Spatial Data Transfer Standard [SDTS]" ),
1780 QStringLiteral(
"*catd.ddf" ),
1781 QStringLiteral(
"ddf" ),
1788 datasetOptions.clear();
1789 layerOptions.clear();
1792 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1793 "tables in a new database. By default these metadata tables are created "
1794 "when a new database is created." ),
1800 QStringLiteral(
"NO" )
1805 QStringLiteral(
"NO" )
1809 QObject::tr(
"Controls the format used for the geometry column. Defaults to WKB. "
1810 "This is generally more space and processing efficient, but harder "
1811 "to inspect or use in simple applications than WKT (Well Known Text)." ),
1813 << QStringLiteral(
"WKB" )
1814 << QStringLiteral(
"WKT" ),
1815 QStringLiteral(
"WKB" )
1819 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
1820 "in SQLite. Laundered names will be converted to lower case and some special "
1821 "characters(' - #) will be changed to underscores." ),
1826 QStringLiteral(
"NO" )
1830 QStringLiteral(
"NO" )
1838 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
1839 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1840 "for databases that have big string blobs. However, use with care, since "
1841 "the value of such columns will be seen as compressed binary content with "
1842 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1843 "modifying or querying compressed columns, compression/decompression is "
1844 "done transparently. However, such columns cannot be (easily) queried with "
1845 "an attribute filter or WHERE clause. Note: in table definition, such columns "
1846 "have the 'VARCHAR_deflate' declaration type." ),
1850 driverMetadata.insert( QStringLiteral(
"SQLite" ),
1852 QStringLiteral(
"SQLite" ),
1853 QObject::tr(
"SQLite" ),
1854 QStringLiteral(
"*.sqlite" ),
1855 QStringLiteral(
"sqlite" ),
1858 QStringLiteral(
"UTF-8" )
1863 datasetOptions.clear();
1864 layerOptions.clear();
1867 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1868 "tables in a new database. By default these metadata tables are created "
1869 "when a new database is created." ),
1874 QStringLiteral(
"YES" )
1878 QObject::tr(
"Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
1879 "Set to NO for regular SQLite databases." ),
1884 QStringLiteral(
"SPATIALITE" )
1888 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
1889 "in SQLite. Laundered names will be converted to lower case and some special "
1890 "characters(' - #) will be changed to underscores." ),
1895 QObject::tr(
"If the database is of the SpatiaLite flavor, and if OGR is linked "
1896 "against libspatialite, this option can be used to control if a spatial "
1897 "index must be created." ),
1902 QObject::tr(
"If the format of the geometry BLOB is of the SpatiaLite flavor, "
1903 "this option can be used to control if the compressed format for "
1904 "geometries (LINESTRINGs, POLYGONs) must be used." ),
1909 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
1910 "When this option isn't specified and that a SRS is associated with the "
1911 "layer, a search is made in the spatial_ref_sys to find a match for the "
1912 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
1913 "the spatial_ref_sys table. When the SRID option is specified, this "
1914 "search (and the eventual insertion of a new entry) will not be done: "
1915 "the specified SRID is used as such." ),
1920 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
1921 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1922 "for databases that have big string blobs. However, use with care, since "
1923 "the value of such columns will be seen as compressed binary content with "
1924 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1925 "modifying or queryings compressed columns, compression/decompression is "
1926 "done transparently. However, such columns cannot be (easily) queried with "
1927 "an attribute filter or WHERE clause. Note: in table definition, such columns "
1928 "have the 'VARCHAR_deflate' declaration type." ),
1932 driverMetadata.insert( QStringLiteral(
"SpatiaLite" ),
1934 QStringLiteral(
"SpatiaLite" ),
1935 QObject::tr(
"SpatiaLite" ),
1936 QStringLiteral(
"*.sqlite" ),
1937 QStringLiteral(
"sqlite" ),
1940 QStringLiteral(
"UTF-8" )
1944 datasetOptions.clear();
1945 layerOptions.clear();
1948 QObject::tr(
"Override the header file used - in place of header.dxf." ),
1953 QObject::tr(
"Override the trailer file used - in place of trailer.dxf." ),
1957 driverMetadata.insert( QStringLiteral(
"DXF" ),
1959 QStringLiteral(
"AutoCAD DXF" ),
1960 QObject::tr(
"AutoCAD DXF" ),
1961 QStringLiteral(
"*.dxf" ),
1962 QStringLiteral(
"dxf" ),
1969 datasetOptions.clear();
1970 layerOptions.clear();
1973 QObject::tr(
"Indicates the GeoConcept export file extension. "
1974 "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
1976 << QStringLiteral(
"GXT" )
1977 << QStringLiteral(
"TXT" ),
1978 QStringLiteral(
"GXT" )
1982 QObject::tr(
"Path to the GCT: the GCT file describes the GeoConcept types definitions: "
1983 "In this file, every line must start with //# followed by a keyword. "
1984 "Lines starting with // are comments." ),
1989 QObject::tr(
"Defines the feature to be created. The TYPE corresponds to one of the Name "
1990 "found in the GCT file for a type section. The SUBTYPE corresponds to one of "
1991 "the Name found in the GCT file for a sub-type section within the previous "
1996 driverMetadata.insert( QStringLiteral(
"Geoconcept" ),
1998 QStringLiteral(
"Geoconcept" ),
1999 QObject::tr(
"Geoconcept" ),
2000 QStringLiteral(
"*.gxt *.txt" ),
2001 QStringLiteral(
"gxt" ),
2008 datasetOptions.clear();
2009 layerOptions.clear();
2012 QObject::tr(
"When this option is set, the new layer will be created inside the named "
2013 "FeatureDataset folder. If the folder does not already exist, it will be created." ),
2018 QObject::tr(
"Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
2019 QStringLiteral(
"SHAPE" )
2023 QObject::tr(
"Name of the OID column to create. Defaults to 'OBJECTID'." ),
2024 QStringLiteral(
"OBJECTID" )
2027 driverMetadata.insert( QStringLiteral(
"FileGDB" ),
2029 QStringLiteral(
"ESRI FileGDB" ),
2030 QObject::tr(
"ESRI FileGDB" ),
2031 QStringLiteral(
"*.gdb" ),
2032 QStringLiteral(
"gdb" ),
2035 QStringLiteral(
"UTF-8" )
2040 datasetOptions.clear();
2041 layerOptions.clear();
2044 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2045 "to STRING, all fields will be of String type." ),
2047 << QStringLiteral(
"AUTO" )
2048 << QStringLiteral(
"STRING" ),
2049 QStringLiteral(
"AUTO" ),
2054 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2055 "if the first line might be the name of columns. If set to FORCE, the driver "
2056 "will consider the first line as the header line. If set to "
2057 "DISABLE, it will be considered as the first feature. Otherwise "
2058 "auto-detection will occur." ),
2060 << QStringLiteral(
"FORCE" )
2061 << QStringLiteral(
"DISABLE" )
2062 << QStringLiteral(
"AUTO" ),
2063 QStringLiteral(
"AUTO" ),
2067 driverMetadata.insert( QStringLiteral(
"XLSX" ),
2069 QStringLiteral(
"MS Office Open XML spreadsheet" ),
2070 QObject::tr(
"MS Office Open XML spreadsheet [XLSX]" ),
2071 QStringLiteral(
"*.xlsx" ),
2072 QStringLiteral(
"xlsx" ),
2075 QStringLiteral(
"UTF-8" )
2080 datasetOptions.clear();
2081 layerOptions.clear();
2084 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2085 "to STRING, all fields will be of String type." ),
2087 << QStringLiteral(
"AUTO" )
2088 << QStringLiteral(
"STRING" ),
2089 QStringLiteral(
"AUTO" ),
2094 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2095 "if the first line might be the name of columns. If set to FORCE, the driver "
2096 "will consider the first line as the header line. If set to "
2097 "DISABLE, it will be considered as the first feature. Otherwise "
2098 "auto-detection will occur." ),
2100 << QStringLiteral(
"FORCE" )
2101 << QStringLiteral(
"DISABLE" )
2102 << QStringLiteral(
"AUTO" ),
2103 QStringLiteral(
"AUTO" ),
2107 driverMetadata.insert( QStringLiteral(
"ODS" ),
2109 QStringLiteral(
"Open Document Spreadsheet" ),
2110 QObject::tr(
"Open Document Spreadsheet [ODS]" ),
2111 QStringLiteral(
"*.ods" ),
2112 QStringLiteral(
"ods" ),
2115 QStringLiteral(
"UTF-8" )
2120 datasetOptions.clear();
2121 layerOptions.clear();
2124 QObject::tr(
"Line termination character sequence." ),
2126 << QStringLiteral(
"CRLF" )
2127 << QStringLiteral(
"LF" ),
2134 QObject::tr(
"Format of geometry columns." ),
2136 << QStringLiteral(
"geometry" )
2137 << QStringLiteral(
"geography" ),
2138 QStringLiteral(
"geometry" ),
2143 QObject::tr(
"Controls whether layer and field names will be laundered for easier use. "
2144 "Laundered names will be converted to lower case and some special "
2145 "characters(' - #) will be changed to underscores." ),
2150 QObject::tr(
"Name for the geometry column. Defaults to wkb_geometry "
2151 "for GEOM_TYPE=geometry or the_geog for GEOM_TYPE=geography" ) ) );
2154 QObject::tr(
"Name of schema into which to create the new table" ) ) );
2157 QObject::tr(
"Whether to explicitly emit the CREATE SCHEMA statement to create the specified schema." ),
2162 QObject::tr(
"Whether to explicitly recreate the table if necessary." ),
2167 QObject::tr(
"Whether to explicitly destroy tables before recreating them." ),
2169 << QStringLiteral(
"YES" )
2170 << QStringLiteral(
"NO" )
2171 << QStringLiteral(
"IF_EXISTS" ),
2172 QStringLiteral(
"YES" ),
2177 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
2178 "When this option isn't specified and that a SRS is associated with the "
2179 "layer, a search is made in the spatial_ref_sys to find a match for the "
2180 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
2181 "the spatial_ref_sys table. When the SRID option is specified, this "
2182 "search (and the eventual insertion of a new entry) will not be done: "
2183 "the specified SRID is used as such." ),
2188 QObject::tr(
"Can be set to 2.0 or 2.2 for PostGIS 2.0/2.2 compatibility. "
2189 "Important to set it correctly if using non-linear geometry types" ),
2193 driverMetadata.insert( QStringLiteral(
"PGDUMP" ),
2195 QStringLiteral(
"PostgreSQL SQL dump" ),
2196 QObject::tr(
"PostgreSQL SQL dump" ),
2197 QStringLiteral(
"*.sql" ),
2198 QStringLiteral(
"sql" ),
2201 QStringLiteral(
"UTF-8" )
2207 QgsVectorFileWriterMetadataContainer(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2208 QgsVectorFileWriterMetadataContainer &operator=(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2209 ~QgsVectorFileWriterMetadataContainer()
2211 for (
auto it = driverMetadata.constBegin(); it != driverMetadata.constEnd(); ++it )
2213 for (
auto optionIt = it.value().driverOptions.constBegin(); optionIt != it.value().driverOptions.constEnd(); ++optionIt )
2214 delete optionIt.value();
2215 for (
auto optionIt = it.value().layerOptions.constBegin(); optionIt != it.value().layerOptions.constEnd(); ++optionIt )
2216 delete optionIt.value();
2220 QMap<QString, QgsVectorFileWriter::MetaData> driverMetadata;
2227 static QgsVectorFileWriterMetadataContainer sDriverMetadata;
2228 QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.driverMetadata.constBegin();
2230 for ( ; it != sDriverMetadata.driverMetadata.constEnd(); ++it )
2232 if ( it.key() == QLatin1String(
"PGDUMP" ) &&
2233 driverName != QLatin1String(
"PGDUMP" ) &&
2234 driverName != QLatin1String(
"PostgreSQL SQL dump" ) )
2239 if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
2254 return QStringList();
2263 return QStringList();
2270 OGRwkbGeometryType ogrType =
static_cast<OGRwkbGeometryType
>( type );
2296 QgsFeatureList::iterator fIt = features.begin();
2298 for ( ; fIt != features.end(); ++fIt )
2323 QString styleString;
2324 QString currentStyle;
2326 QgsSymbolList::const_iterator symbolIt = symbols.constBegin();
2327 for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
2329 int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
2330 for (
int i = 0; i < nSymbolLayers; ++i )
2333 QMap< QgsSymbolLayer *, QString >::const_iterator it =
mSymbolLayerTable.find( ( *symbolIt )->symbolLayer( i ) );
2339 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2340 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2342 currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );
2346 if ( symbolIt != symbols.constBegin() || i != 0 )
2348 styleString.append(
';' );
2350 styleString.append( currentStyle );
2354 OGR_F_SetStyleString( poFeature.get(), currentStyle.toLocal8Bit().constData() );
2355 if ( !writeFeature(
mLayer, poFeature.get() ) )
2362 OGR_F_SetStyleString( poFeature.get(), styleString.toLocal8Bit().constData() );
2367 if ( !writeFeature(
mLayer, poFeature.get() ) )
2384 if ( fid > std::numeric_limits<int>::max() )
2386 QgsDebugMsg( QStringLiteral(
"feature id %1 too large." ).arg( fid ) );
2387 OGRErr err = OGR_F_SetFID( poFeature.get(),
static_cast<long>( fid ) );
2388 if ( err != OGRERR_NONE )
2390 QgsDebugMsg( QStringLiteral(
"Failed to set feature id to %1: %2 (OGR error: %3)" )
2391 .arg( feature.
id() )
2392 .arg( err ).arg( CPLGetLastErrorMsg() )
2400 int fldIdx = it.key();
2401 int ogrField = it.value();
2403 QVariant attrValue = feature.
attribute( fldIdx );
2406 if ( !attrValue.isValid() || attrValue.isNull() )
2415 #ifdef OGRNullMarker
2416 OGR_F_SetFieldNull( poFeature.get(), ogrField );
2431 mErrorMessage = QObject::tr(
"Error converting value (%1) for attribute field %2: %3" )
2432 .arg( feature.
attribute( fldIdx ).toString(),
2442 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2444 case QVariant::LongLong:
2445 OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
2447 case QVariant::Bool:
2448 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2450 case QVariant::String:
2451 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2453 case QVariant::Double:
2454 OGR_F_SetFieldDouble( poFeature.get(), ogrField, attrValue.toDouble() );
2456 case QVariant::Date:
2457 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2458 attrValue.toDate().year(),
2459 attrValue.toDate().month(),
2460 attrValue.toDate().day(),
2463 case QVariant::DateTime:
2466 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toDateTime().toString( QStringLiteral(
"yyyy/MM/dd hh:mm:ss.zzz" ) ) ).constData() );
2470 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2471 attrValue.toDateTime().date().year(),
2472 attrValue.toDateTime().date().month(),
2473 attrValue.toDateTime().date().day(),
2474 attrValue.toDateTime().time().hour(),
2475 attrValue.toDateTime().time().minute(),
2476 attrValue.toDateTime().time().second(),
2480 case QVariant::Time:
2483 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2487 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2489 attrValue.toTime().hour(),
2490 attrValue.toTime().minute(),
2491 attrValue.toTime().second(),
2496 case QVariant::ByteArray:
2498 const QByteArray ba = attrValue.toByteArray();
2499 OGR_F_SetFieldBinary( poFeature.get(), ogrField, ba.size(),
const_cast< GByte *
>(
reinterpret_cast< const GByte *
>( ba.data() ) ) );
2503 case QVariant::Invalid:
2506 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,4,0)
2507 case QVariant::List:
2511 QStringList list = attrValue.toStringList();
2512 if ( supportsStringList )
2514 int count = list.count();
2515 char **lst =
new char *[count + 1];
2519 for ( QString
string : list )
2521 lst[pos] =
mCodec->fromUnicode(
string ).data();
2525 lst[count] =
nullptr;
2526 OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
2530 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( list.join(
',' ) ).constData() );
2539 mErrorMessage = QObject::tr(
"Invalid variant type for field %1[%2]: received %3 with type %4" )
2542 .arg( attrValue.typeName(),
2543 attrValue.toString() );
2556 if ( mCoordinateTransform )
2561 geom.
transform( *mCoordinateTransform );
2579 OGRGeometryH mGeom2 =
nullptr;
2625 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2626 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2632 QByteArray wkb( geom.
asWkb() );
2633 OGRErr err = OGR_G_ImportFromWkb( mGeom2,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
2634 if ( err != OGRERR_NONE )
2636 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2637 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2644 OGR_F_SetGeometryDirectly( poFeature.get(), mGeom2 );
2650 OGRErr err = OGR_G_ImportFromWkb( ogrGeom,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
2651 if ( err != OGRERR_NONE )
2653 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2654 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2661 OGR_F_SetGeometryDirectly( poFeature.get(), ogrGeom );
2676 for (
int i = 0; i < attributes.size(); i++ )
2678 if ( omap.find( i ) != omap.end() )
2683 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
2685 if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
2687 mErrorMessage = QObject::tr(
"Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2697 if ( mUsingTransaction )
2699 if ( OGRERR_NONE != OGR_L_CommitTransaction(
mLayer ) )
2701 QgsDebugMsg( QStringLiteral(
"Error while committing transaction on OGRLayer." ) );
2705 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0) && GDAL_VERSION_NUM <= GDAL_COMPUTE_VERSION(3,1,3)
2709 QString drvName = GDALGetDriverShortName( GDALGetDatasetDriver(
mDS.get() ) );
2710 if ( drvName == QLatin1String(
"XLSX" ) ||
2711 drvName == QLatin1String(
"ODS" ) )
2713 CPLSetThreadLocalConfigOption(
"CPL_CREATE_ZIP64",
"NO" );
2715 CPLSetThreadLocalConfigOption(
"CPL_CREATE_ZIP64",
nullptr );
2724 OSRDestroySpatialReference(
mOgrRef );
2730 const QString &fileName,
2731 const QString &fileEncoding,
2733 const QString &driverName,
2735 QString *errorMessage,
2736 const QStringList &datasourceOptions,
2737 const QStringList &layerOptions,
2738 bool skipAttributeCreation,
2739 QString *newFilename,
2741 double symbologyScale,
2751 if ( destCRS.
isValid() && layer )
2777 const QString &fileName,
2778 const QString &fileEncoding,
2780 const QString &driverName,
2782 QString *errorMessage,
2783 const QStringList &datasourceOptions,
2784 const QStringList &layerOptions,
2785 bool skipAttributeCreation,
2786 QString *newFilename,
2788 double symbologyScale,
2819 : driverName( QStringLiteral(
"GPKG" ) )
2827 if ( !layer || !layer->
isValid() )
2834 details.sourceCrs = layer->
crs();
2835 details.sourceWkbType = layer->
wkbType();
2836 details.sourceFields = layer->
fields();
2845 if ( details.storageType == QLatin1String(
"ESRI Shapefile" ) )
2853 details.geometryTypeScanIterator = layer->
getFeatures( req );
2857 details.renderContext.setExpressionContext( details.expressionContext );
2858 details.renderContext.setRendererScale( options.
symbologyScale );
2860 details.shallTransform =
false;
2865 details.shallTransform =
true;
2870 details.outputCrs = details.sourceCrs;
2873 details.destWkbType = details.sourceWkbType;
2887 details.attributes.clear();
2888 else if ( details.attributes.isEmpty() )
2890 const QgsAttributeList allAttributes = details.sourceFields.allAttributesList();
2891 for (
int idx : allAttributes )
2893 QgsField fld = details.sourceFields.at( idx );
2894 if ( details.providerType == QLatin1String(
"oracle" ) && fld.
typeName().contains( QLatin1String(
"SDO_GEOMETRY" ) ) )
2896 details.attributes.append( idx );
2900 if ( !details.attributes.isEmpty() )
2902 for (
int attrIdx : qgis::as_const( details.attributes ) )
2904 details.outputFields.append( details.sourceFields.at( attrIdx ) );
2910 if ( details.providerType == QLatin1String(
"spatialite" ) )
2912 for (
int i = 0; i < details.outputFields.size(); i++ )
2914 if ( details.outputFields.at( i ).type() == QVariant::LongLong )
2918 if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < std::numeric_limits<int>::max() )
2920 details.outputFields[i].setType( QVariant::Int );
2928 addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
2938 bool useFilterRect =
true;
2939 if ( details.shallTransform )
2948 useFilterRect =
false;
2951 if ( useFilterRect )
2957 details.filterRectEngine->prepareGeometry();
2959 details.sourceFeatureIterator = layer->
getFeatures( req );
2973 int lastProgressReport = 0;
2974 long total = details.featureCount;
2977 if ( details.providerType == QLatin1String(
"ogr" ) && !details.dataSourceUri.isEmpty() )
2979 QString srcFileName( details.providerUriParams.value( QLatin1String(
"path" ) ).toString() );
2980 if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
2984 if ( !( ( options.
driverName == QLatin1String(
"GPKG" ) ||
2985 options.
driverName == QLatin1String(
"SpatiaLite" ) ||
2986 options.
driverName == QLatin1String(
"SQLite" ) ) &&
2987 options.
layerName != details.providerUriParams.value( QLatin1String(
"layerName" ) ) ) )
2990 *
errorMessage = QObject::tr(
"Cannot overwrite a OGR layer in place" );
3010 int newProgress =
static_cast<int>( ( 5.0 * scanned ) / total );
3011 if ( newProgress != lastProgressReport )
3013 lastProgressReport = newProgress;
3028 std::unique_ptr< QgsVectorFileWriter > writer(
create( fileName, details.outputFields, destWkbType, details.outputCrs, transformContext, options, QgsFeatureSink::SinkFlags(), newFilename, newLayer ) );
3069 int n = 0, errors = 0;
3078 writer->startRender( details.renderer.get(), details.sourceFields );
3080 writer->resetMap( details.attributes );
3082 writer->mFields = details.sourceFields;
3086 int initialProgress = lastProgressReport;
3087 while ( details.sourceFeatureIterator.nextFeature( fet ) )
3098 int newProgress =
static_cast<int>( initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total );
3099 if ( newProgress < 100 && newProgress != lastProgressReport )
3101 lastProgressReport = newProgress;
3106 if ( details.shallTransform )
3119 QString msg = QObject::tr(
"Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
3120 .arg( fet.
id() ).arg( e.
what() );
3137 if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
3144 *
errorMessage = QObject::tr(
"Feature write errors:" );
3150 if ( errors > 1000 )
3154 *
errorMessage += QObject::tr(
"Stopping after %1 errors" ).arg( errors );
3164 writer->stopRender();
3168 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
3175 const QString &fileName,
3177 QString *newFilename,
3181 QgsVectorFileWriter::PreparedWriterDetails details;
3182 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3190 const QString &fileName,
3193 QString *newFilename,
3197 QgsVectorFileWriter::PreparedWriterDetails details;
3198 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3207 QFileInfo fi( fileName );
3208 QDir dir = fi.dir();
3211 const char *suffixes[] = {
".shp",
".shx",
".dbf",
".prj",
".qix",
".qpj",
".cpg",
".sbn",
".sbx",
".idm",
".ind" };
3212 for ( std::size_t i = 0; i <
sizeof( suffixes ) /
sizeof( *suffixes ); i++ )
3214 filter << fi.completeBaseName() + suffixes[i];
3218 const auto constEntryList = dir.entryList( filter );
3219 for (
const QString &file : constEntryList )
3221 QFile f( dir.canonicalPath() +
'/' + file );
3224 QgsDebugMsg( QStringLiteral(
"Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
3240 static QReadWriteLock sFilterLock;
3241 static QMap< VectorFormatOptions, QList< QgsVectorFileWriter::FilterFormatDetails > > sFilters;
3245 const auto it = sFilters.constFind( options );
3246 if ( it != sFilters.constEnd() )
3250 QList< QgsVectorFileWriter::FilterFormatDetails > results;
3253 int const drvCount = OGRGetDriverCount();
3255 for (
int i = 0; i < drvCount; ++i )
3257 OGRSFDriverH drv = OGRGetDriver( i );
3260 QString drvName = OGR_Dr_GetName( drv );
3262 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,3,0)
3263 GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
3264 char **metadata =
nullptr;
3267 metadata = GDALGetMetadata( gdalDriver,
nullptr );
3270 bool nonSpatialFormat = CSLFetchBoolean( metadata, GDAL_DCAP_NONSPATIAL,
false );
3272 bool nonSpatialFormat = ( drvName == QLatin1String(
"ODS" ) || drvName == QLatin1String(
"XLSX" ) || drvName == QLatin1String(
"XLS" ) );
3275 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
3280 if ( nonSpatialFormat )
3285 if ( filterString.isEmpty() )
3292 globs = metadata.
glob.toLower().split(
' ' );
3298 details.
globs = globs;
3307 if ( options & SortRecommended )
3309 if ( a.driverName == QLatin1String(
"GPKG" ) )
3311 else if ( b.driverName == QLatin1String(
"GPKG" ) )
3313 else if ( a.driverName == QLatin1String(
"ESRI Shapefile" ) )
3315 else if ( b.driverName == QLatin1String(
"ESRI Shapefile" ) )
3322 sFilters.insert( options, results );
3329 QSet< QString > extensions;
3331 const QRegularExpression rx( QStringLiteral(
"\\*\\.(.*)$" ) );
3335 for (
const QString &glob : format.globs )
3337 const QRegularExpressionMatch match = rx.match( glob );
3338 if ( !match.hasMatch() )
3341 const QString matched = match.captured( 1 );
3342 extensions.insert( matched );
3346 QStringList extensionList = qgis::setToList( extensions );
3348 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
3350 if ( options & SortRecommended )
3352 if ( a == QLatin1String(
"gpkg" ) )
3354 else if ( b == QLatin1String(
"gpkg" ) )
3356 else if ( a == QLatin1String(
"shp" ) )
3358 else if ( b == QLatin1String(
"shp" ) )
3362 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
3365 return extensionList;
3370 QList< QgsVectorFileWriter::DriverDetails > results;
3373 const int drvCount = OGRGetDriverCount();
3375 QStringList writableDrivers;
3376 for (
int i = 0; i < drvCount; ++i )
3378 OGRSFDriverH drv = OGRGetDriver( i );
3381 QString drvName = OGR_Dr_GetName( drv );
3387 if ( drvName == QLatin1String(
"ODS" ) || drvName == QLatin1String(
"XLSX" ) || drvName == QLatin1String(
"XLS" ) )
3391 if ( drvName == QLatin1String(
"ESRI Shapefile" ) )
3393 writableDrivers << QStringLiteral(
"DBF file" );
3395 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
3398 if ( drvName == QLatin1String(
"MapInfo File" ) )
3400 writableDrivers << QStringLiteral(
"MapInfo MIF" );
3402 else if ( drvName == QLatin1String(
"SQLite" ) )
3409 QString option = QStringLiteral(
"SPATIALITE=YES" );
3410 char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ),
nullptr };
3411 OGRSFDriverH poDriver;
3413 poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
3416 gdal::ogr_datasource_unique_ptr ds( OGR_Dr_CreateDataSource( poDriver, QStringLiteral(
"/vsimem/spatialitetest.sqlite" ).toUtf8().constData(), options ) );
3419 writableDrivers << QStringLiteral(
"SpatiaLite" );
3420 OGR_Dr_DeleteDataSource( poDriver, QStringLiteral(
"/vsimem/spatialitetest.sqlite" ).toUtf8().constData() );
3423 CPLFree( options[0] );
3425 writableDrivers << drvName;
3430 results.reserve( writableDrivers.count() );
3431 for (
const QString &drvName : qgis::as_const( writableDrivers ) )
3445 if ( options & SortRecommended )
3447 if ( a.driverName == QLatin1String(
"GPKG" ) )
3449 else if ( b.driverName == QLatin1String(
"GPKG" ) )
3451 else if ( a.driverName == QLatin1String(
"ESRI Shapefile" ) )
3453 else if ( b.driverName == QLatin1String(
"ESRI Shapefile" ) )
3457 return a.
longName.toLower().localeAwareCompare( b.
longName.toLower() ) < 0;
3464 QString ext = extension.trimmed();
3465 if ( ext.isEmpty() )
3468 if ( ext.startsWith(
'.' ) )
3472 int const drvCount = GDALGetDriverCount();
3474 for (
int i = 0; i < drvCount; ++i )
3476 GDALDriverH drv = GDALGetDriver( i );
3482 QString drvName = GDALGetDriverShortName( drv );
3483 QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
3485 const auto constDriverExtensions = driverExtensions;
3486 for (
const QString &driver : constDriverExtensions )
3488 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
3499 QString filterString;
3503 if ( !filterString.isEmpty() )
3504 filterString += QLatin1String(
";;" );
3506 filterString += details.filterString;
3508 return filterString;
3517 return QStringLiteral(
"%1 (%2 %3)" ).arg( metadata.
trLongName,
3518 metadata.
glob.toLower(),
3519 metadata.
glob.toUpper() );
3524 if ( codecName == QLatin1String(
"System" ) )
3525 return QStringLiteral(
"LDID/0" );
3527 QRegExp re = QRegExp( QString(
"(CP|windows-|ISO[ -])(.+)" ), Qt::CaseInsensitive );
3528 if ( re.exactMatch( codecName ) )
3530 QString
c = re.cap( 2 ).remove(
'-' );
3532 ( void )
c.toInt( &isNumber );
3560 OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
3561 OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
3564 int nTotalLevels = 0;
3566 QgsSymbolList::iterator symbolIt = symbolList.begin();
3567 for ( ; symbolIt != symbolList.end(); ++symbolIt )
3569 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3570 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3572 int nLevels = ( *symbolIt )->symbolLayerCount();
3573 for (
int i = 0; i < nLevels; ++i )
3575 mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
3576 OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
3577 ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
3581 OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
3587 if ( !details.renderer )
3592 QHash< QgsSymbol *, QList<QgsFeature> > features;
3601 startRender( details.renderer.get(), details.sourceFields );
3621 QString msg = QObject::tr(
"Failed to transform, writing stopped. (Exception: %1)" )
3632 featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
3633 if ( !featureSymbol )
3638 QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
3639 if ( it == features.end() )
3641 it = features.insert( featureSymbol, QList<QgsFeature>() );
3643 it.value().append( fet );
3648 QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
3649 for (
int i = 0; i < symbols.count(); i++ )
3655 if ( level < 0 || level >= 1000 )
3658 while ( level >= levels.count() )
3660 levels[level].append( item );
3665 int nTotalFeatures = 0;
3668 for (
int l = 0; l < levels.count(); l++ )
3671 for (
int i = 0; i < level.count(); i++ )
3674 QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.
symbol() );
3675 if ( levelIt == features.end() )
3681 double mmsf = mmScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3682 double musf = mapUnitScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3684 int llayer = item.
layer();
3685 QList<QgsFeature> &featureList = levelIt.value();
3686 QList<QgsFeature>::iterator featureIt = featureList.begin();
3687 for ( ; featureIt != featureList.end(); ++featureIt )
3697 QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
3698 if ( !styleString.isEmpty() )
3700 OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
3701 if ( !writeFeature(
mLayer, ogrFeature.get() ) )
3714 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
3731 return 1000 / scale;
3748 return scale / 1000;
3756 mRenderer = createSymbologyRenderer( sourceRenderer );
3762 mRenderer->startRender( mRenderContext, fields );
3765 void QgsVectorFileWriter::stopRender()
3772 mRenderer->stopRender( mRenderContext );
3775 std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer(
QgsFeatureRenderer *sourceRenderer )
const
3781 if ( !sourceRenderer )
3786 return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->
clone() );
3793 const QSet<QString> rendererAttributes = renderer->
usedAttributes( context );
3794 for (
const QString &attr : rendererAttributes )
3799 attList.append( index );
3805 QStringList QgsVectorFileWriter::concatenateOptions(
const QMap<QString, QgsVectorFileWriter::Option *> &options )
3808 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
3810 for ( it = options.constBegin(); it != options.constEnd(); ++it )
3813 switch ( option->
type )
3820 list.append( QStringLiteral(
"%1=%2" ).arg( it.key() ).arg( opt->
defaultValue ) );
3830 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
defaultValue ) );
3840 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
defaultValue ) );
3849 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
mValue ) );
3860 OGRSFDriverH hDriver =
nullptr;
3863 return QgsVectorFileWriter::EditionCapabilities();
3864 QString drvName = OGR_Dr_GetName( hDriver );
3865 QgsVectorFileWriter::EditionCapabilities caps = QgsVectorFileWriter::EditionCapabilities();
3866 if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
3871 if ( !( drvName == QLatin1String(
"ESRI Shapefile" ) && QFile::exists( datasetName ) ) )
3874 if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
3878 int layer_count = OGR_DS_GetLayerCount( hDS.get() );
3881 OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
3884 if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
3887 if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
3898 const QString &layerNameIn )
3900 OGRSFDriverH hDriver =
nullptr;
3905 QString layerName( layerNameIn );
3906 if ( layerName.isEmpty() )
3907 layerName = QFileInfo( datasetName ).baseName();
3909 return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3914 const QString &layerName,
3918 OGRSFDriverH hDriver =
nullptr;
3922 OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
3928 OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
3929 const auto constAttributes = attributes;
3930 for (
int idx : constAttributes )
3933 if ( OGR_FD_GetFieldIndex( defn, fld.
name().toUtf8().constData() ) < 0 )