46 #include <QTextStream>
50 #include <QRegularExpression>
51 #include <QJsonDocument>
57 #include <ogr_srs_api.h>
58 #include <cpl_error.h>
60 #include <cpl_string.h>
79 const QString &vectorFileName,
80 const QString &fileEncoding,
84 const QString &driverName,
85 const QStringList &datasourceOptions,
86 const QStringList &layerOptions,
89 QgsFeatureSink::SinkFlags sinkFlags,
99 init( vectorFileName, fileEncoding, fields, geometryType,
100 srs, driverName, datasourceOptions, layerOptions, newFilename,
nullptr,
105 const QString &vectorFileName,
106 const QString &fileEncoding,
110 const QString &driverName,
111 const QStringList &datasourceOptions,
112 const QStringList &layerOptions,
113 QString *newFilename,
116 const QString &layerName,
120 QgsFeatureSink::SinkFlags sinkFlags,
124 , mWkbType( geometryType )
125 , mSymbologyExport( symbologyExport )
126 , mSymbologyScale( 1.0 )
128 init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName,
129 datasourceOptions, layerOptions, newFilename, fieldValueConverter,
130 layerName, action, newLayer, sinkFlags, transformContext, fieldNameSource );
134 const QString &fileName,
140 QgsFeatureSink::SinkFlags sinkFlags,
141 QString *newFilename,
155 if ( driverName == QLatin1String(
"MapInfo MIF" ) )
159 GDALDriverH gdalDriver = GDALGetDriverByName( driverName.toLocal8Bit().constData() );
167 return CSLFetchBoolean(
driverMetadata, GDAL_DCAP_FEATURE_STYLES,
false );
170 void QgsVectorFileWriter::init( QString vectorFileName,
171 QString fileEncoding,
175 const QString &driverName,
176 QStringList datasourceOptions,
177 QStringList layerOptions,
178 QString *newFilename,
179 FieldValueConverter *fieldValueConverter,
180 const QString &layerNameIn,
181 ActionOnExistingFile action,
182 QString *newLayer, SinkFlags sinkFlags,
187 if ( vectorFileName.isEmpty() )
194 if ( driverName == QLatin1String(
"MapInfo MIF" ) )
198 else if ( driverName == QLatin1String(
"SpatiaLite" ) )
201 if ( !datasourceOptions.contains( QStringLiteral(
"SPATIALITE=YES" ) ) )
203 datasourceOptions.append( QStringLiteral(
"SPATIALITE=YES" ) );
206 else if ( driverName == QLatin1String(
"DBF file" ) )
209 if ( !layerOptions.contains( QStringLiteral(
"SHPT=NULL" ) ) )
211 layerOptions.append( QStringLiteral(
"SHPT=NULL" ) );
220 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,3,1)
221 QString fidFieldName;
224 for (
const QString &layerOption : layerOptions )
226 if ( layerOption.startsWith( QLatin1String(
"FID=" ) ) )
228 fidFieldName = layerOption.mid( 4 );
232 if ( fidFieldName.isEmpty() )
233 fidFieldName = QStringLiteral(
"fid" );
238 OGRSFDriverH poDriver;
241 poDriver = OGRGetDriverByName(
mOgrDriverName.toLocal8Bit().constData() );
245 mErrorMessage = QObject::tr(
"OGR driver for '%1' not found (OGR error: %2)" )
247 QString::fromUtf8( CPLGetLastErrorMsg() ) );
257 if ( layerOptions.join( QString() ).toUpper().indexOf( QLatin1String(
"ENCODING=" ) ) == -1 )
262 if ( driverName == QLatin1String(
"ESRI Shapefile" ) && !vectorFileName.endsWith( QLatin1String(
".shp" ), Qt::CaseInsensitive ) )
264 vectorFileName += QLatin1String(
".shp" );
266 else if ( driverName == QLatin1String(
"DBF file" ) && !vectorFileName.endsWith( QLatin1String(
".dbf" ), Qt::CaseInsensitive ) )
268 vectorFileName += QLatin1String(
".dbf" );
278 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
279 QStringList allExts = metadata.ext.split(
' ', QString::SkipEmptyParts );
281 QStringList allExts = metadata.ext.split(
' ', Qt::SkipEmptyParts );
284 const auto constAllExts = allExts;
285 for (
const QString &ext : constAllExts )
287 if ( vectorFileName.endsWith(
'.' + ext, Qt::CaseInsensitive ) )
296 vectorFileName +=
'.' + allExts[0];
302 if ( vectorFileName.endsWith( QLatin1String(
".gdb" ), Qt::CaseInsensitive ) )
304 QDir dir( vectorFileName );
307 QFileInfoList fileList = dir.entryInfoList(
308 QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst );
309 const auto constFileList = fileList;
310 for (
const QFileInfo &info : constFileList )
312 QFile::remove( info.absoluteFilePath() );
315 QDir().rmdir( vectorFileName );
319 QFile::remove( vectorFileName );
324 if ( metadataFound && !metadata.compulsoryEncoding.isEmpty() )
326 if ( fileEncoding.compare( metadata.compulsoryEncoding, Qt::CaseInsensitive ) != 0 )
328 QgsDebugMsgLevel( QStringLiteral(
"forced %1 encoding for %2" ).arg( metadata.compulsoryEncoding, driverName ), 2 );
329 fileEncoding = metadata.compulsoryEncoding;
334 char **options =
nullptr;
335 if ( !datasourceOptions.isEmpty() )
337 options =
new char *[ datasourceOptions.size() + 1 ];
338 for (
int i = 0; i < datasourceOptions.size(); i++ )
340 QgsDebugMsgLevel( QStringLiteral(
"-dsco=%1" ).arg( datasourceOptions[i] ), 2 );
341 options[i] = CPLStrdup( datasourceOptions[i].toLocal8Bit().constData() );
343 options[ datasourceOptions.size()] =
nullptr;
349 mDS.reset( OGR_Dr_CreateDataSource( poDriver, vectorFileName.toUtf8().constData(), options ) );
351 mDS.reset( OGROpen( vectorFileName.toUtf8().constData(), TRUE,
nullptr ) );
355 for (
int i = 0; i < datasourceOptions.size(); i++ )
356 CPLFree( options[i] );
365 mErrorMessage = QObject::tr(
"Creation of data source failed (OGR error: %1)" )
366 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
368 mErrorMessage = QObject::tr(
"Opening of data source in update mode failed (OGR error: %1)" )
369 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
373 QString layerName( layerNameIn );
374 if ( layerName.isEmpty() )
375 layerName = QFileInfo( vectorFileName ).baseName();
379 const int layer_count = OGR_DS_GetLayerCount(
mDS.get() );
380 for (
int i = 0; i < layer_count; i++ )
382 OGRLayerH hLayer = OGR_DS_GetLayer(
mDS.get(), i );
383 if ( EQUAL( OGR_L_GetName( hLayer ), layerName.toUtf8().constData() ) )
385 if ( OGR_DS_DeleteLayer(
mDS.get(), i ) != OGRERR_NONE )
388 mErrorMessage = QObject::tr(
"Overwriting of existing layer failed (OGR error: %1)" )
389 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
403 QgsDebugMsgLevel( QStringLiteral(
"Opened data source in update mode" ), 2 );
407 mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
410 QgsDebugMsg(
"error finding QTextCodec for " + fileEncoding );
413 QString enc = settings.
value( QStringLiteral(
"UI/encoding" ),
"System" ).toString();
414 mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
417 QgsDebugMsg(
"error finding QTextCodec for " + enc );
418 mCodec = QTextCodec::codecForLocale();
424 if ( driverName == QLatin1String(
"KML" ) || driverName == QLatin1String(
"LIBKML" ) || driverName == QLatin1String(
"GPX" ) )
426 if ( srs.
authid() != QLatin1String(
"EPSG:4326" ) )
441 int optIndex = layerOptions.indexOf( QLatin1String(
"FEATURE_DATASET=" ) );
442 if ( optIndex != -1 )
444 layerOptions.removeAt( optIndex );
447 if ( !layerOptions.isEmpty() )
449 options =
new char *[ layerOptions.size() + 1 ];
450 for (
int i = 0; i < layerOptions.size(); i++ )
453 options[i] = CPLStrdup( layerOptions[i].toLocal8Bit().constData() );
455 options[ layerOptions.size()] =
nullptr;
459 CPLSetConfigOption(
"SHAPE_ENCODING",
"" );
463 mLayer = OGR_DS_CreateLayer(
mDS.get(), layerName.toUtf8().constData(),
mOgrRef, wkbType, options );
466 *newLayer = OGR_L_GetName(
mLayer );
467 if ( driverName == QLatin1String(
"GPX" ) )
474 if ( !EQUAL( layerName.toUtf8().constData(),
"track_points" ) &&
475 !EQUAL( layerName.toUtf8().constData(),
"route_points" ) )
477 *newLayer = QStringLiteral(
"waypoints" );
484 const char *pszForceGPXTrack
485 = CSLFetchNameValue( options,
"FORCE_GPX_TRACK" );
486 if ( pszForceGPXTrack && CPLTestBool( pszForceGPXTrack ) )
487 *newLayer = QStringLiteral(
"tracks" );
489 *newLayer = QStringLiteral(
"routes" );
496 const char *pszForceGPXRoute
497 = CSLFetchNameValue( options,
"FORCE_GPX_ROUTE" );
498 if ( pszForceGPXRoute && CPLTestBool( pszForceGPXRoute ) )
499 *newLayer = QStringLiteral(
"routes" );
501 *newLayer = QStringLiteral(
"tracks" );
511 else if ( driverName == QLatin1String(
"DGN" ) )
513 mLayer = OGR_DS_GetLayerByName(
mDS.get(),
"elements" );
517 mLayer = OGR_DS_GetLayerByName(
mDS.get(), layerName.toUtf8().constData() );
522 for (
int i = 0; i < layerOptions.size(); i++ )
523 CPLFree( options[i] );
532 QString layerName = vectorFileName.left( vectorFileName.indexOf( QLatin1String(
".shp" ), Qt::CaseInsensitive ) );
533 QFile prjFile( layerName +
".qpj" );
534 if ( prjFile.exists() )
542 mErrorMessage = QObject::tr(
"Creation of layer failed (OGR error: %1)" )
543 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
545 mErrorMessage = QObject::tr(
"Opening of layer failed (OGR error: %1)" )
546 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
551 OGRFeatureDefnH defn = OGR_L_GetLayerDefn(
mLayer );
560 QSet<int> existingIdxs;
570 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
574 if ( fieldValueConverter )
576 attrField = fieldValueConverter->fieldDefinition( fields.
at( fldIdx ) );
581 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( attrField.
name() ) );
590 switch ( fieldNameSource )
593 name = attrField.
name();
597 name = !attrField.
alias().isEmpty() ? attrField.
alias() : attrField.
name();
601 OGRFieldType ogrType = OFTString;
602 OGRFieldSubType ogrSubType = OFSTNone;
603 int ogrWidth = attrField.
length();
604 int ogrPrecision = attrField.
precision();
605 if ( ogrPrecision > 0 )
608 switch ( attrField.
type() )
610 case QVariant::LongLong:
612 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
613 if ( pszDataTypes && strstr( pszDataTypes,
"Integer64" ) )
614 ogrType = OFTInteger64;
617 ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
621 case QVariant::String:
623 if ( ( ogrWidth <= 0 || ogrWidth > 255 ) &&
mOgrDriverName == QLatin1String(
"ESRI Shapefile" ) )
628 ogrType = OFTInteger;
629 ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
634 ogrType = OFTInteger;
635 ogrSubType = OFSTBoolean;
640 case QVariant::Double:
641 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,3,1)
642 if (
mOgrDriverName == QLatin1String(
"GPKG" ) && attrField.
precision() == 0 && attrField.
name().compare( fidFieldName, Qt::CaseInsensitive ) == 0 )
645 ogrType = OFTInteger64;
668 case QVariant::DateTime:
676 ogrType = OFTDateTime;
680 case QVariant::ByteArray:
684 case QVariant::StringList:
690 ogrSubType = OFSTJSON;
694 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
695 if ( pszDataTypes && strstr( pszDataTypes,
"StringList" ) )
697 ogrType = OFTStringList;
698 mSupportedListSubTypes.insert( QVariant::String );
713 ogrSubType = OFSTJSON;
718 if ( attrField.
subType() == QVariant::String )
720 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
721 if ( pszDataTypes && strstr( pszDataTypes,
"StringList" ) )
723 ogrType = OFTStringList;
724 mSupportedListSubTypes.insert( QVariant::String );
733 else if ( attrField.
subType() == QVariant::Int )
735 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
736 if ( pszDataTypes && strstr( pszDataTypes,
"IntegerList" ) )
738 ogrType = OFTIntegerList;
739 mSupportedListSubTypes.insert( QVariant::Int );
748 else if ( attrField.
subType() == QVariant::Double )
750 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
751 if ( pszDataTypes && strstr( pszDataTypes,
"RealList" ) )
753 ogrType = OFTRealList;
754 mSupportedListSubTypes.insert( QVariant::Double );
763 else if ( attrField.
subType() == QVariant::LongLong )
765 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
766 if ( pszDataTypes && strstr( pszDataTypes,
"Integer64List" ) )
768 ogrType = OFTInteger64List;
769 mSupportedListSubTypes.insert( QVariant::LongLong );
783 mErrorMessage = QObject::tr(
"Unsupported type for field %1" )
784 .arg( attrField.
name() );
789 if (
mOgrDriverName == QLatin1String(
"SQLite" ) && name.compare( QLatin1String(
"ogc_fid" ), Qt::CaseInsensitive ) == 0 )
792 for ( i = 0; i < 10; i++ )
794 name = QStringLiteral(
"ogc_fid%1" ).arg( i );
797 for ( j = 0; j < fields.
size() && name.compare( fields.
at( j ).
name(), Qt::CaseInsensitive ) != 0; j++ )
800 if ( j == fields.
size() )
806 mErrorMessage = QObject::tr(
"No available replacement for internal fieldname ogc_fid found" ).arg( attrField.
name() );
811 QgsMessageLog::logMessage( QObject::tr(
"Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr(
"OGR" ) );
818 OGR_Fld_SetWidth( fld.get(), ogrWidth );
821 if ( ogrPrecision >= 0 )
823 OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
826 if ( ogrSubType != OFSTNone )
827 OGR_Fld_SetSubType( fld.get(), ogrSubType );
831 " type " + QString( QVariant::typeToName( attrField.
type() ) ) +
832 " width " + QString::number( ogrWidth ) +
833 " precision " + QString::number( ogrPrecision ), 2 );
834 if ( OGR_L_CreateField(
mLayer, fld.get(),
true ) != OGRERR_NONE )
837 mErrorMessage = QObject::tr(
"Creation of field %1 failed (OGR error: %2)" )
838 .arg( attrField.
name(),
839 QString::fromUtf8( CPLGetLastErrorMsg() ) );
844 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
845 QgsDebugMsgLevel( QStringLiteral(
"returned field index for %1: %2" ).arg( name ).arg( ogrIdx ), 2 );
846 if ( ogrIdx < 0 || existingIdxs.contains( ogrIdx ) )
849 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
854 mErrorMessage = QObject::tr(
"Created field %1 not found (OGR error: %2)" )
855 .arg( attrField.
name(),
856 QString::fromUtf8( CPLGetLastErrorMsg() ) );
862 existingIdxs.insert( ogrIdx );
870 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
873 QString name( attrField.
name() );
874 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
886 int fidIdx = fields.
lookupField( QStringLiteral(
"FID" ) );
897 *newFilename = vectorFileName;
900 mUsingTransaction =
true;
901 if ( OGRERR_NONE != OGR_L_StartTransaction(
mLayer ) )
903 mUsingTransaction =
false;
913 class QgsVectorFileWriterMetadataContainer
917 QgsVectorFileWriterMetadataContainer()
919 QMap<QString, QgsVectorFileWriter::Option *> datasetOptions;
920 QMap<QString, QgsVectorFileWriter::Option *> layerOptions;
923 datasetOptions.clear();
924 layerOptions.clear();
926 driverMetadata.insert( QStringLiteral(
"AVCE00" ),
928 QStringLiteral(
"Arc/Info ASCII Coverage" ),
929 QObject::tr(
"Arc/Info ASCII Coverage" ),
930 QStringLiteral(
"*.e00" ),
931 QStringLiteral(
"e00" ),
938 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,3,0)
942 datasetOptions.clear();
943 layerOptions.clear();
946 QObject::tr(
"New BNA files are created by the "
947 "systems default line termination conventions. "
948 "This may be overridden here." ),
950 << QStringLiteral(
"CRLF" )
951 << QStringLiteral(
"LF" ),
957 QObject::tr(
"By default, BNA files are created in multi-line format. "
958 "For each record, the first line contains the identifiers and the "
959 "type/number of coordinates to follow. Each following line contains "
960 "a pair of coordinates." ),
965 QObject::tr(
"BNA records may contain from 2 to 4 identifiers per record. "
966 "Some software packages only support a precise number of identifiers. "
967 "You can override the default value (2) by a precise value." ),
969 << QStringLiteral(
"2" )
970 << QStringLiteral(
"3" )
971 << QStringLiteral(
"4" )
972 << QStringLiteral(
"NB_SOURCE_FIELDS" ),
973 QStringLiteral(
"2" )
977 QObject::tr(
"The BNA writer will try to recognize ellipses and circles when writing a polygon. "
978 "This will only work if the feature has previously been read from a BNA file. "
979 "As some software packages do not support ellipses/circles in BNA data file, "
980 "it may be useful to tell the writer by specifying ELLIPSES_AS_ELLIPSES=NO not "
981 "to export them as such, but keep them as polygons." ),
986 QObject::tr(
"Limit the number of coordinate pairs per line in multiline format." ),
991 QObject::tr(
"Set the number of decimal for coordinates. Default value is 10." ),
995 driverMetadata.insert( QStringLiteral(
"BNA" ),
997 QStringLiteral(
"Atlas BNA" ),
998 QObject::tr(
"Atlas BNA" ),
999 QStringLiteral(
"*.bna" ),
1000 QStringLiteral(
"bna" ),
1008 datasetOptions.clear();
1009 layerOptions.clear();
1012 QObject::tr(
"By default when creating new .csv files they "
1013 "are created with the line termination conventions "
1014 "of the local platform (CR/LF on Win32 or LF on all other systems). "
1015 "This may be overridden through the use of the LINEFORMAT option." ),
1017 << QStringLiteral(
"CRLF" )
1018 << QStringLiteral(
"LF" ),
1024 QObject::tr(
"By default, the geometry of a feature written to a .csv file is discarded. "
1025 "It is possible to export the geometry in its WKT representation by "
1026 "specifying GEOMETRY=AS_WKT. It is also possible to export point geometries "
1027 "into their X,Y,Z components by specifying GEOMETRY=AS_XYZ, GEOMETRY=AS_XY "
1028 "or GEOMETRY=AS_YX." ),
1030 << QStringLiteral(
"AS_WKT" )
1031 << QStringLiteral(
"AS_XYZ" )
1032 << QStringLiteral(
"AS_XY" )
1033 << QStringLiteral(
"AS_YX" ),
1039 QObject::tr(
"Create the associated .csvt file to describe the type of each "
1040 "column of the layer and its optional width and precision." ),
1045 QObject::tr(
"Field separator character." ),
1047 << QStringLiteral(
"COMMA" )
1048 << QStringLiteral(
"SEMICOLON" )
1049 << QStringLiteral(
"TAB" ),
1050 QStringLiteral(
"COMMA" )
1054 QObject::tr(
"Double-quote strings. IF_AMBIGUOUS means that string values that look like numbers will be quoted." ),
1056 << QStringLiteral(
"IF_NEEDED" )
1057 << QStringLiteral(
"IF_AMBIGUOUS" )
1058 << QStringLiteral(
"ALWAYS" ),
1059 QStringLiteral(
"IF_AMBIGUOUS" )
1063 QObject::tr(
"Write a UTF-8 Byte Order Mark (BOM) at the start of the file." ),
1067 driverMetadata.insert( QStringLiteral(
"CSV" ),
1069 QStringLiteral(
"Comma Separated Value [CSV]" ),
1070 QObject::tr(
"Comma Separated Value [CSV]" ),
1071 QStringLiteral(
"*.csv" ),
1072 QStringLiteral(
"csv" ),
1078 #if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0)
1080 datasetOptions.clear();
1081 layerOptions.clear();
1083 driverMetadata.insert( QStringLiteral(
"FlatGeobuf" ),
1085 QStringLiteral(
"FlatGeobuf" ),
1086 QObject::tr(
"FlatGeobuf" ),
1087 QStringLiteral(
"*.fgb" ),
1088 QStringLiteral(
"fgb" ),
1091 QStringLiteral(
"UTF-8" )
1097 datasetOptions.clear();
1098 layerOptions.clear();
1101 QObject::tr(
"Override the type of shapefile created. "
1102 "Can be one of NULL for a simple .dbf file with no .shp file, POINT, "
1103 "ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or "
1104 "MULTIPOINTZ for 3D;" ) +
1105 QObject::tr(
" POINTM, ARCM, POLYGONM or MULTIPOINTM for measured geometries"
1106 " and POINTZM, ARCZM, POLYGONZM or MULTIPOINTZM for 3D measured"
1108 QObject::tr(
" MULTIPATCH files are supported since GDAL 2.2." ) +
1111 << QStringLiteral(
"NULL" )
1112 << QStringLiteral(
"POINT" )
1113 << QStringLiteral(
"ARC" )
1114 << QStringLiteral(
"POLYGON" )
1115 << QStringLiteral(
"MULTIPOINT" )
1116 << QStringLiteral(
"POINTZ" )
1117 << QStringLiteral(
"ARCZ" )
1118 << QStringLiteral(
"POLYGONZ" )
1119 << QStringLiteral(
"MULTIPOINTZ" )
1120 << QStringLiteral(
"POINTM" )
1121 << QStringLiteral(
"ARCM" )
1122 << QStringLiteral(
"POLYGONM" )
1123 << QStringLiteral(
"MULTIPOINTM" )
1124 << QStringLiteral(
"POINTZM" )
1125 << QStringLiteral(
"ARCZM" )
1126 << QStringLiteral(
"POLYGONZM" )
1127 << QStringLiteral(
"MULTIPOINTZM" )
1128 << QStringLiteral(
"MULTIPATCH" )
1138 QObject::tr(
"Set the encoding value in the DBF file. "
1139 "The default value is LDID/87. It is not clear "
1140 "what other values may be appropriate." ),
1148 QObject::tr(
"Set to YES to resize fields to their optimal size." ),
1152 driverMetadata.insert( QStringLiteral(
"ESRI" ),
1154 QStringLiteral(
"ESRI Shapefile" ),
1155 QObject::tr(
"ESRI Shapefile" ),
1156 QStringLiteral(
"*.shp" ),
1157 QStringLiteral(
"shp" ),
1164 datasetOptions.clear();
1165 layerOptions.clear();
1167 driverMetadata.insert( QStringLiteral(
"DBF File" ),
1169 QStringLiteral(
"DBF File" ),
1170 QObject::tr(
"DBF File" ),
1171 QStringLiteral(
"*.dbf" ),
1172 QStringLiteral(
"dbf" ),
1179 datasetOptions.clear();
1180 layerOptions.clear();
1182 driverMetadata.insert( QStringLiteral(
"FMEObjects Gateway" ),
1184 QStringLiteral(
"FMEObjects Gateway" ),
1185 QObject::tr(
"FMEObjects Gateway" ),
1186 QStringLiteral(
"*.fdd" ),
1187 QStringLiteral(
"fdd" ),
1194 datasetOptions.clear();
1195 layerOptions.clear();
1198 QObject::tr(
"Set to YES to write a bbox property with the bounding box "
1199 "of the geometries at the feature and feature collection level." ),
1204 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1205 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1210 QObject::tr(
"Whether to use RFC 7946 standard. "
1211 "If disabled GeoJSON 2008 initial version will be used. "
1212 "Default is NO (thus GeoJSON 2008). See also Documentation (via Help button)" ),
1216 driverMetadata.insert( QStringLiteral(
"GeoJSON" ),
1218 QStringLiteral(
"GeoJSON" ),
1219 QObject::tr(
"GeoJSON" ),
1220 QStringLiteral(
"*.geojson" ),
1221 QStringLiteral(
"geojson" ),
1224 QStringLiteral(
"UTF-8" )
1229 datasetOptions.clear();
1230 layerOptions.clear();
1233 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1234 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1239 QObject::tr(
"Whether to start records with the RS=0x1E character (RFC 8142 standard). "
1240 "Defaults to NO: Newline Delimited JSON (geojsonl). \n"
1241 "If set to YES: RFC 8142 standard: GeoJSON Text Sequences (geojsons)." ),
1245 driverMetadata.insert( QStringLiteral(
"GeoJSONSeq" ),
1247 QStringLiteral(
"GeoJSON - Newline Delimited" ),
1248 QObject::tr(
"GeoJSON - Newline Delimited" ),
1249 QStringLiteral(
"*.geojsonl *.geojsons *.json" ),
1250 QStringLiteral(
"json" ),
1253 QStringLiteral(
"UTF-8" )
1258 datasetOptions.clear();
1259 layerOptions.clear();
1262 QObject::tr(
"whether the document must be in RSS 2.0 or Atom 1.0 format. "
1263 "Default value : RSS" ),
1265 << QStringLiteral(
"RSS" )
1266 << QStringLiteral(
"ATOM" ),
1267 QStringLiteral(
"RSS" )
1271 QObject::tr(
"The encoding of location information. Default value : SIMPLE. "
1272 "W3C_GEO only supports point geometries. "
1273 "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
1275 << QStringLiteral(
"SIMPLE" )
1276 << QStringLiteral(
"GML" )
1277 << QStringLiteral(
"W3C_GEO" ),
1278 QStringLiteral(
"SIMPLE" )
1282 QObject::tr(
"If defined to YES, extension fields will be written. "
1283 "If the field name not found in the base schema matches "
1284 "the foo_bar pattern, foo will be considered as the namespace "
1285 "of the element, and a <foo:bar> element will be written. "
1286 "Otherwise, elements will be written in the <ogr:> namespace." ),
1291 QObject::tr(
"If defined to NO, only <entry> or <item> elements will be written. "
1292 "The user will have to provide the appropriate header and footer of the document." ),
1297 QObject::tr(
"XML content that will be put between the <channel> element and the "
1298 "first <item> element for a RSS document, or between the xml tag and "
1299 "the first <entry> element for an Atom document." ),
1304 QObject::tr(
"Value put inside the <title> element in the header. "
1305 "If not provided, a dummy value will be used as that element is compulsory." ),
1310 QObject::tr(
"Value put inside the <description> element in the header. "
1311 "If not provided, a dummy value will be used as that element is compulsory." ),
1316 QObject::tr(
"Value put inside the <link> element in the header. "
1317 "If not provided, a dummy value will be used as that element is compulsory." ),
1322 QObject::tr(
"Value put inside the <updated> element in the header. "
1323 "Should be formatted as a XML datetime. "
1324 "If not provided, a dummy value will be used as that element is compulsory." ),
1329 QObject::tr(
"Value put inside the <author><name> element in the header. "
1330 "If not provided, a dummy value will be used as that element is compulsory." ),
1335 QObject::tr(
"Value put inside the <id> element in the header. "
1336 "If not provided, a dummy value will be used as that element is compulsory." ),
1340 driverMetadata.insert( QStringLiteral(
"GeoRSS" ),
1342 QStringLiteral(
"GeoRSS" ),
1343 QObject::tr(
"GeoRSS" ),
1344 QStringLiteral(
"*.xml" ),
1345 QStringLiteral(
"xml" ),
1348 QStringLiteral(
"UTF-8" )
1353 datasetOptions.clear();
1354 layerOptions.clear();
1357 QObject::tr(
"If provided, this URI will be inserted as the schema location. "
1358 "Note that the schema file isn't actually accessed by OGR, so it "
1359 "is up to the user to ensure it will match the schema of the OGR "
1360 "produced GML data file." ),
1365 QObject::tr(
"This writes a GML application schema file to a corresponding "
1366 ".xsd file (with the same basename). If INTERNAL is used the "
1367 "schema is written within the GML file, but this is experimental "
1368 "and almost certainly not valid XML. "
1369 "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
1371 << QStringLiteral(
"EXTERNAL" )
1372 << QStringLiteral(
"INTERNAL" )
1373 << QStringLiteral(
"OFF" ),
1374 QStringLiteral(
"EXTERNAL" )
1378 QObject::tr(
"This is the prefix for the application target namespace." ),
1379 QStringLiteral(
"ogr" )
1383 QObject::tr(
"Can be set to TRUE to avoid writing the prefix of the "
1384 "application target namespace in the GML file." ),
1389 QObject::tr(
"Defaults to 'http://ogr.maptools.org/'. "
1390 "This is the application target namespace." ),
1391 QStringLiteral(
"http://ogr.maptools.org/" )
1395 QObject::tr(
"If not specified, GML2 will be used." ),
1397 << QStringLiteral(
"GML3" )
1398 << QStringLiteral(
"GML3Deegree" )
1399 << QStringLiteral(
"GML3.2" ),
1405 QObject::tr(
"Only valid when FORMAT=GML3/GML3Degree/GML3.2. Default to YES. "
1406 "If YES, SRS with EPSG authority will be written with the "
1407 "'urn:ogc:def:crs:EPSG::' prefix. In the case the SRS is a "
1408 "geographic SRS without explicit AXIS order, but that the same "
1409 "SRS authority code imported with ImportFromEPSGA() should be "
1410 "treated as lat/long, then the function will take care of coordinate "
1411 "order swapping. If set to NO, SRS with EPSG authority will be "
1412 "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
1417 QObject::tr(
"only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
1418 "If set to NO, the <gml:boundedBy> element will not be written for "
1424 QObject::tr(
"Default to YES. If YES, the output will be indented with spaces "
1425 "for more readability, but at the expense of file size." ),
1430 driverMetadata.insert( QStringLiteral(
"GML" ),
1432 QStringLiteral(
"Geography Markup Language [GML]" ),
1433 QObject::tr(
"Geography Markup Language [GML]" ),
1434 QStringLiteral(
"*.gml" ),
1435 QStringLiteral(
"gml" ),
1438 QStringLiteral(
"UTF-8" )
1443 datasetOptions.clear();
1444 layerOptions.clear();
1447 QObject::tr(
"Human-readable identifier (e.g. short name) for the layer content" ),
1452 QObject::tr(
"Human-readable description for the layer content" ),
1457 QObject::tr(
"Name for the feature identifier column" ),
1458 QStringLiteral(
"fid" )
1462 QObject::tr(
"Name for the geometry column" ),
1463 QStringLiteral(
"geom" )
1467 QObject::tr(
"If a spatial index must be created." ),
1471 driverMetadata.insert( QStringLiteral(
"GPKG" ),
1473 QStringLiteral(
"GeoPackage" ),
1474 QObject::tr(
"GeoPackage" ),
1475 QStringLiteral(
"*.gpkg" ),
1476 QStringLiteral(
"gpkg" ),
1479 QStringLiteral(
"UTF-8" )
1484 datasetOptions.clear();
1485 layerOptions.clear();
1487 driverMetadata.insert( QStringLiteral(
"GMT" ),
1489 QStringLiteral(
"Generic Mapping Tools [GMT]" ),
1490 QObject::tr(
"Generic Mapping Tools [GMT]" ),
1491 QStringLiteral(
"*.gmt" ),
1492 QStringLiteral(
"gmt" ),
1499 datasetOptions.clear();
1500 layerOptions.clear();
1503 QObject::tr(
"By default when writing a layer whose features are of "
1504 "type wkbLineString, the GPX driver chooses to write "
1505 "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1506 "they will be written as tracks." ),
1511 QObject::tr(
"By default when writing a layer whose features are of "
1512 "type wkbMultiLineString, the GPX driver chooses to write "
1513 "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1514 "they will be written as routes, provided that the multilines "
1515 "are composed of only one single line." ),
1520 QObject::tr(
"If GPX_USE_EXTENSIONS=YES is specified, "
1521 "extra fields will be written inside the <extensions> tag." ),
1526 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1527 "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1528 QStringLiteral(
"ogr" )
1532 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1533 "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1534 QStringLiteral(
"http://osgeo.org/gdal" )
1538 QObject::tr(
"By default files are created with the line termination "
1539 "conventions of the local platform (CR/LF on win32 or LF "
1540 "on all other systems). This may be overridden through use "
1541 "of the LINEFORMAT layer creation option which may have a value "
1542 "of CRLF (DOS format) or LF (Unix format)." ),
1544 << QStringLiteral(
"CRLF" )
1545 << QStringLiteral(
"LF" ),
1550 driverMetadata.insert( QStringLiteral(
"GPX" ),
1552 QStringLiteral(
"GPS eXchange Format [GPX]" ),
1553 QObject::tr(
"GPS eXchange Format [GPX]" ),
1554 QStringLiteral(
"*.gpx" ),
1555 QStringLiteral(
"gpx" ),
1558 QStringLiteral(
"UTF-8" )
1563 datasetOptions.clear();
1564 layerOptions.clear();
1566 driverMetadata.insert( QStringLiteral(
"Interlis 1" ),
1568 QStringLiteral(
"INTERLIS 1" ),
1569 QObject::tr(
"INTERLIS 1" ),
1570 QStringLiteral(
"*.itf *.xml *.ili" ),
1571 QStringLiteral(
"ili" ),
1578 datasetOptions.clear();
1579 layerOptions.clear();
1581 driverMetadata.insert( QStringLiteral(
"Interlis 2" ),
1583 QStringLiteral(
"INTERLIS 2" ),
1584 QObject::tr(
"INTERLIS 2" ),
1585 QStringLiteral(
"*.xtf *.xml *.ili" ),
1586 QStringLiteral(
"ili" ),
1593 datasetOptions.clear();
1594 layerOptions.clear();
1597 QObject::tr(
"Allows you to specify the field to use for the KML <name> element." ),
1598 QStringLiteral(
"Name" )
1602 QObject::tr(
"Allows you to specify the field to use for the KML <description> element." ),
1603 QStringLiteral(
"Description" )
1607 QObject::tr(
"Allows you to specify the AltitudeMode to use for KML geometries. "
1608 "This will only affect 3D geometries and must be one of the valid KML options." ),
1610 << QStringLiteral(
"clampToGround" )
1611 << QStringLiteral(
"relativeToGround" )
1612 << QStringLiteral(
"absolute" ),
1613 QStringLiteral(
"relativeToGround" )
1617 QObject::tr(
"The DOCUMENT_ID datasource creation option can be used to specified "
1618 "the id of the root <Document> node. The default value is root_doc." ),
1619 QStringLiteral(
"root_doc" )
1622 driverMetadata.insert( QStringLiteral(
"KML" ),
1624 QStringLiteral(
"Keyhole Markup Language [KML]" ),
1625 QObject::tr(
"Keyhole Markup Language [KML]" ),
1626 QStringLiteral(
"*.kml" ),
1627 QStringLiteral(
"kml" ),
1630 QStringLiteral(
"UTF-8" )
1635 datasetOptions.clear();
1636 layerOptions.clear();
1638 auto insertMapInfoOptions = []( QMap<QString, QgsVectorFileWriter::Option *> &datasetOptions, QMap<QString, QgsVectorFileWriter::Option *> &layerOptions )
1641 QObject::tr(
"Use this to turn on 'quick spatial index mode'. "
1642 "In this mode writing files can be about 5 times faster, "
1643 "but spatial queries can be up to 30 times slower." ),
1645 << QStringLiteral(
"QUICK" )
1646 << QStringLiteral(
"OPTIMIZED" ),
1647 QStringLiteral(
"QUICK" ),
1652 QObject::tr(
"(multiples of 512): Block size for .map files. Defaults "
1653 "to 512. MapInfo 15.2 and above creates .tab files with a "
1654 "blocksize of 16384 bytes. Any MapInfo version should be "
1655 "able to handle block sizes from 512 to 32256." ),
1659 QObject::tr(
"xmin,ymin,xmax,ymax: Define custom layer bounds to increase the "
1660 "accuracy of the coordinates. Note: the geometry of written "
1661 "features must be within the defined box." ),
1665 insertMapInfoOptions( datasetOptions, layerOptions );
1667 driverMetadata.insert( QStringLiteral(
"MapInfo File" ),
1669 QStringLiteral(
"Mapinfo" ),
1670 QObject::tr(
"Mapinfo TAB" ),
1671 QStringLiteral(
"*.tab" ),
1672 QStringLiteral(
"tab" ),
1677 datasetOptions.clear();
1678 layerOptions.clear();
1679 insertMapInfoOptions( datasetOptions, layerOptions );
1682 driverMetadata.insert( QStringLiteral(
"MapInfo MIF" ),
1684 QStringLiteral(
"Mapinfo" ),
1685 QObject::tr(
"Mapinfo MIF" ),
1686 QStringLiteral(
"*.mif" ),
1687 QStringLiteral(
"mif" ),
1694 datasetOptions.clear();
1695 layerOptions.clear();
1698 QObject::tr(
"Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1699 "seed file should be used. This option is ignored if the SEED option is provided." ),
1704 QObject::tr(
"Override the seed file to use." ),
1709 QObject::tr(
"Indicate whether the whole seed file should be copied. "
1710 "If not, only the first three elements will be copied." ),
1715 QObject::tr(
"Indicates whether the color table should be copied from the seed file." ),
1720 QObject::tr(
"Override the master unit name from the seed file with "
1721 "the provided one or two character unit name." ),
1726 QObject::tr(
"Override the sub unit name from the seed file with the provided "
1727 "one or two character unit name." ),
1732 QObject::tr(
"Override the number of subunits per master unit. "
1733 "By default the seed file value is used." ),
1738 QObject::tr(
"Override the number of UORs (Units of Resolution) "
1739 "per sub unit. By default the seed file value is used." ),
1744 QObject::tr(
"ORIGIN=x,y,z: Override the origin of the design plane. "
1745 "By default the origin from the seed file is used." ),
1749 driverMetadata.insert( QStringLiteral(
"DGN" ),
1751 QStringLiteral(
"Microstation DGN" ),
1752 QObject::tr(
"Microstation DGN" ),
1753 QStringLiteral(
"*.dgn" ),
1754 QStringLiteral(
"dgn" ),
1761 datasetOptions.clear();
1762 layerOptions.clear();
1765 QObject::tr(
"Should update files be incorporated into the base data on the fly." ),
1767 << QStringLiteral(
"APPLY" )
1768 << QStringLiteral(
"IGNORE" ),
1769 QStringLiteral(
"APPLY" )
1773 QObject::tr(
"Should multipoint soundings be split into many single point sounding features. "
1774 "Multipoint geometries are not well handled by many formats, "
1775 "so it can be convenient to split single sounding features with many points "
1776 "into many single point features." ),
1781 QObject::tr(
"Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1782 "of the sounding. This should only be enabled when SPLIT_MULTIPOINT is "
1788 QObject::tr(
"Should all the low level geometry primitives be returned as special "
1789 "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1794 QObject::tr(
"If enabled, numeric attributes assigned an empty string as a value will "
1795 "be preserved as a special numeric value. This option should not generally "
1796 "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1801 QObject::tr(
"Should LNAM and LNAM_REFS fields be attached to features capturing "
1802 "the feature to feature relationships in the FFPT group of the S-57 file." ),
1807 QObject::tr(
"Should additional attributes relating features to their underlying "
1808 "geometric primitives be attached. These are the values of the FSPT group, "
1809 "and are primarily needed when doing S-57 to S-57 translations." ),
1814 QObject::tr(
"Should attribute values be recoded to UTF-8 from the character encoding "
1815 "specified in the S57 DSSI record." ),
1821 driverMetadata.insert( QStringLiteral(
"S57" ),
1823 QStringLiteral(
"S-57 Base file" ),
1824 QObject::tr(
"S-57 Base file" ),
1825 QStringLiteral(
"*.000" ),
1826 QStringLiteral(
"000" ),
1833 datasetOptions.clear();
1834 layerOptions.clear();
1836 driverMetadata.insert( QStringLiteral(
"SDTS" ),
1838 QStringLiteral(
"Spatial Data Transfer Standard [SDTS]" ),
1839 QObject::tr(
"Spatial Data Transfer Standard [SDTS]" ),
1840 QStringLiteral(
"*catd.ddf" ),
1841 QStringLiteral(
"ddf" ),
1848 datasetOptions.clear();
1849 layerOptions.clear();
1852 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1853 "tables in a new database. By default these metadata tables are created "
1854 "when a new database is created." ),
1860 QStringLiteral(
"NO" )
1865 QStringLiteral(
"NO" )
1869 QObject::tr(
"Controls the format used for the geometry column. Defaults to WKB. "
1870 "This is generally more space and processing efficient, but harder "
1871 "to inspect or use in simple applications than WKT (Well Known Text)." ),
1873 << QStringLiteral(
"WKB" )
1874 << QStringLiteral(
"WKT" ),
1875 QStringLiteral(
"WKB" )
1879 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
1880 "in SQLite. Laundered names will be converted to lower case and some special "
1881 "characters(' - #) will be changed to underscores." ),
1886 QStringLiteral(
"NO" )
1890 QStringLiteral(
"NO" )
1898 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
1899 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1900 "for databases that have big string blobs. However, use with care, since "
1901 "the value of such columns will be seen as compressed binary content with "
1902 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1903 "modifying or querying compressed columns, compression/decompression is "
1904 "done transparently. However, such columns cannot be (easily) queried with "
1905 "an attribute filter or WHERE clause. Note: in table definition, such columns "
1906 "have the 'VARCHAR_deflate' declaration type." ),
1910 driverMetadata.insert( QStringLiteral(
"SQLite" ),
1912 QStringLiteral(
"SQLite" ),
1913 QObject::tr(
"SQLite" ),
1914 QStringLiteral(
"*.sqlite" ),
1915 QStringLiteral(
"sqlite" ),
1918 QStringLiteral(
"UTF-8" )
1923 datasetOptions.clear();
1924 layerOptions.clear();
1927 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
1928 "tables in a new database. By default these metadata tables are created "
1929 "when a new database is created." ),
1934 QStringLiteral(
"YES" )
1938 QObject::tr(
"Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
1939 "Set to NO for regular SQLite databases." ),
1944 QStringLiteral(
"SPATIALITE" )
1948 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
1949 "in SQLite. Laundered names will be converted to lower case and some special "
1950 "characters(' - #) will be changed to underscores." ),
1955 QObject::tr(
"If the database is of the SpatiaLite flavor, and if OGR is linked "
1956 "against libspatialite, this option can be used to control if a spatial "
1957 "index must be created." ),
1962 QObject::tr(
"If the format of the geometry BLOB is of the SpatiaLite flavor, "
1963 "this option can be used to control if the compressed format for "
1964 "geometries (LINESTRINGs, POLYGONs) must be used." ),
1969 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
1970 "When this option isn't specified and that a SRS is associated with the "
1971 "layer, a search is made in the spatial_ref_sys to find a match for the "
1972 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
1973 "the spatial_ref_sys table. When the SRID option is specified, this "
1974 "search (and the eventual insertion of a new entry) will not be done: "
1975 "the specified SRID is used as such." ),
1980 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
1981 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
1982 "for databases that have big string blobs. However, use with care, since "
1983 "the value of such columns will be seen as compressed binary content with "
1984 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
1985 "modifying or queryings compressed columns, compression/decompression is "
1986 "done transparently. However, such columns cannot be (easily) queried with "
1987 "an attribute filter or WHERE clause. Note: in table definition, such columns "
1988 "have the 'VARCHAR_deflate' declaration type." ),
1992 driverMetadata.insert( QStringLiteral(
"SpatiaLite" ),
1994 QStringLiteral(
"SpatiaLite" ),
1995 QObject::tr(
"SpatiaLite" ),
1996 QStringLiteral(
"*.sqlite" ),
1997 QStringLiteral(
"sqlite" ),
2000 QStringLiteral(
"UTF-8" )
2004 datasetOptions.clear();
2005 layerOptions.clear();
2008 QObject::tr(
"Override the header file used - in place of header.dxf." ),
2013 QObject::tr(
"Override the trailer file used - in place of trailer.dxf." ),
2017 driverMetadata.insert( QStringLiteral(
"DXF" ),
2019 QStringLiteral(
"AutoCAD DXF" ),
2020 QObject::tr(
"AutoCAD DXF" ),
2021 QStringLiteral(
"*.dxf" ),
2022 QStringLiteral(
"dxf" ),
2029 datasetOptions.clear();
2030 layerOptions.clear();
2033 QObject::tr(
"Indicates the GeoConcept export file extension. "
2034 "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
2036 << QStringLiteral(
"GXT" )
2037 << QStringLiteral(
"TXT" ),
2038 QStringLiteral(
"GXT" )
2042 QObject::tr(
"Path to the GCT: the GCT file describes the GeoConcept types definitions: "
2043 "In this file, every line must start with //# followed by a keyword. "
2044 "Lines starting with // are comments." ),
2049 QObject::tr(
"Defines the feature to be created. The TYPE corresponds to one of the Name "
2050 "found in the GCT file for a type section. The SUBTYPE corresponds to one of "
2051 "the Name found in the GCT file for a sub-type section within the previous "
2056 driverMetadata.insert( QStringLiteral(
"Geoconcept" ),
2058 QStringLiteral(
"Geoconcept" ),
2059 QObject::tr(
"Geoconcept" ),
2060 QStringLiteral(
"*.gxt *.txt" ),
2061 QStringLiteral(
"gxt" ),
2068 datasetOptions.clear();
2069 layerOptions.clear();
2072 QObject::tr(
"When this option is set, the new layer will be created inside the named "
2073 "FeatureDataset folder. If the folder does not already exist, it will be created." ),
2078 QObject::tr(
"Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
2079 QStringLiteral(
"SHAPE" )
2083 QObject::tr(
"Name of the OID column to create. Defaults to 'OBJECTID'." ),
2084 QStringLiteral(
"OBJECTID" )
2087 driverMetadata.insert( QStringLiteral(
"FileGDB" ),
2089 QStringLiteral(
"ESRI FileGDB" ),
2090 QObject::tr(
"ESRI FileGDB" ),
2091 QStringLiteral(
"*.gdb" ),
2092 QStringLiteral(
"gdb" ),
2095 QStringLiteral(
"UTF-8" )
2100 datasetOptions.clear();
2101 layerOptions.clear();
2104 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2105 "to STRING, all fields will be of String type." ),
2107 << QStringLiteral(
"AUTO" )
2108 << QStringLiteral(
"STRING" ),
2109 QStringLiteral(
"AUTO" ),
2114 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2115 "if the first line might be the name of columns. If set to FORCE, the driver "
2116 "will consider the first line as the header line. If set to "
2117 "DISABLE, it will be considered as the first feature. Otherwise "
2118 "auto-detection will occur." ),
2120 << QStringLiteral(
"FORCE" )
2121 << QStringLiteral(
"DISABLE" )
2122 << QStringLiteral(
"AUTO" ),
2123 QStringLiteral(
"AUTO" ),
2127 driverMetadata.insert( QStringLiteral(
"XLSX" ),
2129 QStringLiteral(
"MS Office Open XML spreadsheet" ),
2130 QObject::tr(
"MS Office Open XML spreadsheet [XLSX]" ),
2131 QStringLiteral(
"*.xlsx" ),
2132 QStringLiteral(
"xlsx" ),
2135 QStringLiteral(
"UTF-8" )
2140 datasetOptions.clear();
2141 layerOptions.clear();
2144 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2145 "to STRING, all fields will be of String type." ),
2147 << QStringLiteral(
"AUTO" )
2148 << QStringLiteral(
"STRING" ),
2149 QStringLiteral(
"AUTO" ),
2154 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2155 "if the first line might be the name of columns. If set to FORCE, the driver "
2156 "will consider the first line as the header line. If set to "
2157 "DISABLE, it will be considered as the first feature. Otherwise "
2158 "auto-detection will occur." ),
2160 << QStringLiteral(
"FORCE" )
2161 << QStringLiteral(
"DISABLE" )
2162 << QStringLiteral(
"AUTO" ),
2163 QStringLiteral(
"AUTO" ),
2167 driverMetadata.insert( QStringLiteral(
"ODS" ),
2169 QStringLiteral(
"Open Document Spreadsheet" ),
2170 QObject::tr(
"Open Document Spreadsheet [ODS]" ),
2171 QStringLiteral(
"*.ods" ),
2172 QStringLiteral(
"ods" ),
2175 QStringLiteral(
"UTF-8" )
2180 datasetOptions.clear();
2181 layerOptions.clear();
2184 QObject::tr(
"Line termination character sequence." ),
2186 << QStringLiteral(
"CRLF" )
2187 << QStringLiteral(
"LF" ),
2188 QStringLiteral(
"LF" ),
2194 QObject::tr(
"Format of geometry columns." ),
2196 << QStringLiteral(
"geometry" )
2197 << QStringLiteral(
"geography" ),
2198 QStringLiteral(
"geometry" ),
2203 QObject::tr(
"Controls whether layer and field names will be laundered for easier use. "
2204 "Laundered names will be converted to lower case and some special "
2205 "characters(' - #) will be changed to underscores." ),
2210 QObject::tr(
"Name for the geometry column. Defaults to wkb_geometry "
2211 "for GEOM_TYPE=geometry or the_geog for GEOM_TYPE=geography" ) ) );
2214 QObject::tr(
"Name of schema into which to create the new table" ) ) );
2217 QObject::tr(
"Whether to explicitly emit the CREATE SCHEMA statement to create the specified schema." ),
2222 QObject::tr(
"Whether to explicitly recreate the table if necessary." ),
2227 QObject::tr(
"Whether to explicitly destroy tables before recreating them." ),
2229 << QStringLiteral(
"YES" )
2230 << QStringLiteral(
"NO" )
2231 << QStringLiteral(
"IF_EXISTS" ),
2232 QStringLiteral(
"YES" ),
2237 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
2238 "When this option isn't specified and that a SRS is associated with the "
2239 "layer, a search is made in the spatial_ref_sys to find a match for the "
2240 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
2241 "the spatial_ref_sys table. When the SRID option is specified, this "
2242 "search (and the eventual insertion of a new entry) will not be done: "
2243 "the specified SRID is used as such." ),
2248 QObject::tr(
"Can be set to 2.0 or 2.2 for PostGIS 2.0/2.2 compatibility. "
2249 "Important to set it correctly if using non-linear geometry types" ),
2250 QStringLiteral(
"2.2" )
2253 driverMetadata.insert( QStringLiteral(
"PGDUMP" ),
2255 QStringLiteral(
"PostgreSQL SQL dump" ),
2256 QObject::tr(
"PostgreSQL SQL dump" ),
2257 QStringLiteral(
"*.sql" ),
2258 QStringLiteral(
"sql" ),
2261 QStringLiteral(
"UTF-8" )
2267 QgsVectorFileWriterMetadataContainer(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2268 QgsVectorFileWriterMetadataContainer &operator=(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2269 ~QgsVectorFileWriterMetadataContainer()
2271 for (
auto it = driverMetadata.constBegin(); it != driverMetadata.constEnd(); ++it )
2273 for (
auto optionIt = it.value().driverOptions.constBegin(); optionIt != it.value().driverOptions.constEnd(); ++optionIt )
2274 delete optionIt.value();
2275 for (
auto optionIt = it.value().layerOptions.constBegin(); optionIt != it.value().layerOptions.constEnd(); ++optionIt )
2276 delete optionIt.value();
2280 QMap<QString, QgsVectorFileWriter::MetaData> driverMetadata;
2287 static QgsVectorFileWriterMetadataContainer sDriverMetadata;
2288 QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.driverMetadata.constBegin();
2290 for ( ; it != sDriverMetadata.driverMetadata.constEnd(); ++it )
2292 if ( it.key() == QLatin1String(
"PGDUMP" ) &&
2293 driverName != QLatin1String(
"PGDUMP" ) &&
2294 driverName != QLatin1String(
"PostgreSQL SQL dump" ) )
2299 if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
2314 return QStringList();
2323 return QStringList();
2330 OGRwkbGeometryType ogrType =
static_cast<OGRwkbGeometryType
>( type );
2356 QgsFeatureList::iterator fIt = features.begin();
2358 for ( ; fIt != features.end(); ++fIt )
2383 QString styleString;
2384 QString currentStyle;
2386 QgsSymbolList::const_iterator symbolIt = symbols.constBegin();
2387 for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
2389 int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
2390 for (
int i = 0; i < nSymbolLayers; ++i )
2393 QMap< QgsSymbolLayer *, QString >::const_iterator it =
mSymbolLayerTable.find( ( *symbolIt )->symbolLayer( i ) );
2399 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2400 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2402 currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );
2406 if ( symbolIt != symbols.constBegin() || i != 0 )
2408 styleString.append(
';' );
2410 styleString.append( currentStyle );
2414 OGR_F_SetStyleString( poFeature.get(), currentStyle.toLocal8Bit().constData() );
2415 if ( !writeFeature(
mLayer, poFeature.get() ) )
2422 OGR_F_SetStyleString( poFeature.get(), styleString.toLocal8Bit().constData() );
2427 if ( !writeFeature(
mLayer, poFeature.get() ) )
2446 int fldIdx = it.key();
2447 int ogrField = it.value();
2449 QVariant attrValue = feature.
attribute( fldIdx );
2452 if ( !attrValue.isValid() || attrValue.isNull() )
2461 #ifdef OGRNullMarker
2462 OGR_F_SetFieldNull( poFeature.get(), ogrField );
2477 mErrorMessage = QObject::tr(
"Error converting value (%1) for attribute field %2: %3" )
2478 .arg( feature.
attribute( fldIdx ).toString(),
2488 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2490 case QVariant::LongLong:
2491 OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
2493 case QVariant::Bool:
2494 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2496 case QVariant::String:
2497 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2499 case QVariant::Double:
2500 OGR_F_SetFieldDouble( poFeature.get(), ogrField, attrValue.toDouble() );
2502 case QVariant::Date:
2503 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2504 attrValue.toDate().year(),
2505 attrValue.toDate().month(),
2506 attrValue.toDate().day(),
2509 case QVariant::DateTime:
2512 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toDateTime().toString( QStringLiteral(
"yyyy/MM/dd hh:mm:ss.zzz" ) ) ).constData() );
2516 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2517 attrValue.toDateTime().date().year(),
2518 attrValue.toDateTime().date().month(),
2519 attrValue.toDateTime().date().day(),
2520 attrValue.toDateTime().time().hour(),
2521 attrValue.toDateTime().time().minute(),
2522 attrValue.toDateTime().time().second(),
2526 case QVariant::Time:
2529 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2533 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2535 attrValue.toTime().hour(),
2536 attrValue.toTime().minute(),
2537 attrValue.toTime().second(),
2542 case QVariant::ByteArray:
2544 const QByteArray ba = attrValue.toByteArray();
2545 OGR_F_SetFieldBinary( poFeature.get(), ogrField, ba.size(),
const_cast< GByte *
>(
reinterpret_cast< const GByte *
>( ba.data() ) ) );
2549 case QVariant::Invalid:
2552 case QVariant::StringList:
2557 const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
2559 if ( !doc.isNull() )
2561 jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).constData() );
2563 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( jsonString.constData() ) );
2567 QStringList list = attrValue.toStringList();
2568 if ( mSupportedListSubTypes.contains( QVariant::String ) )
2570 int count = list.count();
2571 char **lst =
new char *[count + 1];
2575 for (
const QString &
string : list )
2577 lst[pos] = CPLStrdup(
mCodec->fromUnicode(
string ).data() );
2581 lst[count] =
nullptr;
2582 OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
2587 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( list.join(
',' ) ).constData() );
2592 case QVariant::List:
2596 const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
2598 if ( !doc.isNull() )
2600 jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).data() );
2602 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( jsonString.constData() ) );
2609 QStringList list = attrValue.toStringList();
2610 if ( mSupportedListSubTypes.contains( QVariant::String ) )
2612 int count = list.count();
2613 char **lst =
new char *[count + 1];
2617 for (
const QString &
string : list )
2619 lst[pos] = CPLStrdup(
mCodec->fromUnicode(
string ).data() );
2623 lst[count] =
nullptr;
2624 OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
2629 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( list.join(
',' ) ).constData() );
2635 const QVariantList list = attrValue.toList();
2636 if ( mSupportedListSubTypes.contains( QVariant::Int ) )
2638 const int count = list.count();
2639 int *lst =
new int[count];
2643 for (
const QVariant &value : list )
2645 lst[pos] = value.toInt();
2649 OGR_F_SetFieldIntegerList( poFeature.get(), ogrField, count, lst );
2654 QStringList strings;
2655 strings.reserve( list.size() );
2656 for (
const QVariant &value : list )
2658 strings << QString::number( value.toInt() );
2660 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
2666 const QVariantList list = attrValue.toList();
2667 if ( mSupportedListSubTypes.contains( QVariant::Double ) )
2669 const int count = list.count();
2670 double *lst =
new double[count];
2674 for (
const QVariant &value : list )
2676 lst[pos] = value.toDouble();
2680 OGR_F_SetFieldDoubleList( poFeature.get(), ogrField, count, lst );
2685 QStringList strings;
2686 strings.reserve( list.size() );
2687 for (
const QVariant &value : list )
2689 strings << QString::number( value.toDouble() );
2691 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
2697 const QVariantList list = attrValue.toList();
2698 if ( mSupportedListSubTypes.contains( QVariant::LongLong ) )
2700 const int count = list.count();
2701 long long *lst =
new long long[count];
2705 for (
const QVariant &value : list )
2707 lst[pos] = value.toLongLong();
2711 OGR_F_SetFieldInteger64List( poFeature.get(), ogrField, count, lst );
2716 QStringList strings;
2717 strings.reserve( list.size() );
2718 for (
const QVariant &value : list )
2720 strings << QString::number( value.toLongLong() );
2722 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
2730 mErrorMessage = QObject::tr(
"Invalid variant type for field %1[%2]: received %3 with type %4" )
2733 .arg( attrValue.typeName(),
2734 attrValue.toString() );
2747 if ( mCoordinateTransform )
2752 geom.
transform( *mCoordinateTransform );
2770 OGRGeometryH mGeom2 =
nullptr;
2816 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2817 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2823 QByteArray wkb( geom.
asWkb() );
2824 OGRErr err = OGR_G_ImportFromWkb( mGeom2,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
2825 if ( err != OGRERR_NONE )
2827 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2828 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2835 OGR_F_SetGeometryDirectly( poFeature.get(), mGeom2 );
2841 OGRErr err = OGR_G_ImportFromWkb( ogrGeom,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
2842 if ( err != OGRERR_NONE )
2844 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
2845 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2852 OGR_F_SetGeometryDirectly( poFeature.get(), ogrGeom );
2867 for (
int i = 0; i < attributes.size(); i++ )
2869 if ( omap.find( i ) != omap.end() )
2874 bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
2876 if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
2878 mErrorMessage = QObject::tr(
"Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
2888 if ( mUsingTransaction )
2890 if ( OGRERR_NONE != OGR_L_CommitTransaction(
mLayer ) )
2892 QgsDebugMsg( QStringLiteral(
"Error while committing transaction on OGRLayer." ) );
2896 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0) && GDAL_VERSION_NUM <= GDAL_COMPUTE_VERSION(3,1,3)
2900 QString drvName = GDALGetDriverShortName( GDALGetDatasetDriver(
mDS.get() ) );
2901 if ( drvName == QLatin1String(
"XLSX" ) ||
2902 drvName == QLatin1String(
"ODS" ) )
2904 CPLSetThreadLocalConfigOption(
"CPL_CREATE_ZIP64",
"NO" );
2906 CPLSetThreadLocalConfigOption(
"CPL_CREATE_ZIP64",
nullptr );
2921 const QString &fileName,
2922 const QString &fileEncoding,
2924 const QString &driverName,
2926 QString *errorMessage,
2927 const QStringList &datasourceOptions,
2928 const QStringList &layerOptions,
2929 bool skipAttributeCreation,
2930 QString *newFilename,
2932 double symbologyScale,
2942 if ( destCRS.
isValid() && layer )
2968 const QString &fileName,
2969 const QString &fileEncoding,
2971 const QString &driverName,
2973 QString *errorMessage,
2974 const QStringList &datasourceOptions,
2975 const QStringList &layerOptions,
2976 bool skipAttributeCreation,
2977 QString *newFilename,
2979 double symbologyScale,
3010 : driverName( QStringLiteral(
"GPKG" ) )
3018 if ( !layer || !layer->
isValid() )
3025 details.sourceCrs = layer->
crs();
3026 details.sourceWkbType = layer->
wkbType();
3027 details.sourceFields = layer->
fields();
3036 if ( details.storageType == QLatin1String(
"ESRI Shapefile" ) )
3044 details.geometryTypeScanIterator = layer->
getFeatures( req );
3048 details.renderContext.setExpressionContext( details.expressionContext );
3049 details.renderContext.setRendererScale( options.
symbologyScale );
3051 details.shallTransform =
false;
3056 details.shallTransform =
true;
3061 details.outputCrs = details.sourceCrs;
3064 details.destWkbType = details.sourceWkbType;
3078 details.attributes.clear();
3079 else if ( details.attributes.isEmpty() )
3081 const QgsAttributeList allAttributes = details.sourceFields.allAttributesList();
3082 for (
int idx : allAttributes )
3084 QgsField fld = details.sourceFields.at( idx );
3085 if ( details.providerType == QLatin1String(
"oracle" ) && fld.
typeName().contains( QLatin1String(
"SDO_GEOMETRY" ) ) )
3087 details.attributes.append( idx );
3091 if ( !details.attributes.isEmpty() )
3093 for (
int attrIdx : std::as_const( details.attributes ) )
3095 if ( details.sourceFields.exists( attrIdx ) )
3099 details.outputFields.append(
field );
3103 QgsDebugMsg( QStringLiteral(
"No such source field with index '%1' available." ).arg( attrIdx ) );
3110 if ( details.providerType == QLatin1String(
"spatialite" ) )
3112 for (
int i = 0; i < details.outputFields.size(); i++ )
3114 if ( details.outputFields.at( i ).type() == QVariant::LongLong )
3119 if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < std::numeric_limits<int>::max() )
3121 details.outputFields[i].setType( QVariant::Int );
3129 addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
3139 bool useFilterRect =
true;
3140 if ( details.shallTransform )
3147 filterRect = extentTransform.
transformBoundingBox( filterRect, Qgis::TransformDirection::Reverse );
3151 useFilterRect =
false;
3154 if ( useFilterRect )
3160 details.filterRectEngine->prepareGeometry();
3162 details.sourceFeatureIterator = layer->
getFeatures( req );
3176 int lastProgressReport = 0;
3177 long long total = details.featureCount;
3180 if ( details.providerType == QLatin1String(
"ogr" ) && !details.dataSourceUri.isEmpty() )
3182 QString srcFileName( details.providerUriParams.value( QStringLiteral(
"path" ) ).toString() );
3183 if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
3187 if ( !( ( options.
driverName == QLatin1String(
"GPKG" ) ||
3188 options.
driverName == QLatin1String(
"SpatiaLite" ) ||
3189 options.
driverName == QLatin1String(
"SQLite" ) ) &&
3190 options.
layerName != details.providerUriParams.value( QStringLiteral(
"layerName" ) ) ) )
3193 *
errorMessage = QObject::tr(
"Cannot overwrite a OGR layer in place" );
3213 int newProgress =
static_cast<int>( ( 5.0 * scanned ) / total );
3214 if ( newProgress != lastProgressReport )
3216 lastProgressReport = newProgress;
3231 QString tempNewFilename;
3232 QString tempNewLayer;
3234 std::unique_ptr< QgsVectorFileWriter > writer(
create( fileName, details.outputFields, destWkbType, details.outputCrs, transformContext, options, QgsFeatureSink::SinkFlags(), &tempNewFilename, &tempNewLayer ) );
3238 *newFilename = tempNewFilename;
3241 *newLayer = tempNewLayer;
3281 int n = 0, errors = 0;
3290 writer->startRender( details.renderer.get(), details.sourceFields );
3292 writer->resetMap( details.attributes );
3294 writer->mFields = details.sourceFields;
3298 int initialProgress = lastProgressReport;
3299 while ( details.sourceFeatureIterator.nextFeature( fet ) )
3310 int newProgress =
static_cast<int>( initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total );
3311 if ( newProgress < 100 && newProgress != lastProgressReport )
3313 lastProgressReport = newProgress;
3318 if ( details.shallTransform )
3331 QString msg = QObject::tr(
"Failed to transform a point while drawing a feature with ID '%1'. Writing stopped. (Exception: %2)" )
3332 .arg( fet.
id() ).arg( e.
what() );
3349 if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
3356 *
errorMessage = QObject::tr(
"Feature write errors:" );
3362 if ( errors > 1000 )
3366 *
errorMessage += QObject::tr(
"Stopping after %n error(s)",
nullptr, errors );
3376 writer->stopRender();
3380 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
3385 bool metadataFailure =
false;
3390 {QStringLiteral(
"path" ), tempNewFilename },
3391 {QStringLiteral(
"layerName" ), tempNewLayer }
3405 metadataFailure =
true;
3416 metadataFailure =
true;
3424 const QString &fileName,
3426 QString *newFilename,
3430 QgsVectorFileWriter::PreparedWriterDetails details;
3431 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3439 const QString &fileName,
3442 QString *newFilename,
3446 QgsVectorFileWriter::PreparedWriterDetails details;
3447 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3456 QgsVectorFileWriter::PreparedWriterDetails details;
3457 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3466 QFileInfo fi( fileName );
3467 QDir dir = fi.dir();
3470 for (
const char *suffix : {
".shp",
".shx",
".dbf",
".prj",
".qix",
".qpj",
".cpg",
".sbn",
".sbx",
".idm",
".ind" } )
3472 filter << fi.completeBaseName() + suffix;
3476 const auto constEntryList = dir.entryList( filter );
3477 for (
const QString &file : constEntryList )
3479 QFile f( dir.canonicalPath() +
'/' + file );
3482 QgsDebugMsg( QStringLiteral(
"Removing file %1 failed: %2" ).arg( file, f.errorString() ) );
3498 static QReadWriteLock sFilterLock;
3499 static QMap< VectorFormatOptions, QList< QgsVectorFileWriter::FilterFormatDetails > > sFilters;
3503 const auto it = sFilters.constFind( options );
3504 if ( it != sFilters.constEnd() )
3508 QList< QgsVectorFileWriter::FilterFormatDetails > results;
3511 int const drvCount = OGRGetDriverCount();
3513 for (
int i = 0; i < drvCount; ++i )
3515 OGRSFDriverH drv = OGRGetDriver( i );
3518 QString drvName = OGR_Dr_GetName( drv );
3520 GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
3521 char **metadata =
nullptr;
3524 metadata = GDALGetMetadata( gdalDriver,
nullptr );
3527 bool nonSpatialFormat = CSLFetchBoolean( metadata, GDAL_DCAP_NONSPATIAL,
false );
3529 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
3534 if ( nonSpatialFormat )
3539 if ( filterString.isEmpty() )
3546 globs = metadata.
glob.toLower().split(
' ' );
3552 details.
globs = globs;
3561 if ( options & SortRecommended )
3563 if ( a.driverName == QLatin1String(
"GPKG" ) )
3565 else if ( b.driverName == QLatin1String(
"GPKG" ) )
3567 else if ( a.driverName == QLatin1String(
"ESRI Shapefile" ) )
3569 else if ( b.driverName == QLatin1String(
"ESRI Shapefile" ) )
3576 sFilters.insert( options, results );
3583 QSet< QString > extensions;
3585 const QRegularExpression rx( QStringLiteral(
"\\*\\.(.*)$" ) );
3589 for (
const QString &glob : format.globs )
3591 const QRegularExpressionMatch match = rx.match( glob );
3592 if ( !match.hasMatch() )
3595 const QString matched = match.captured( 1 );
3596 extensions.insert( matched );
3600 QStringList extensionList = qgis::setToList( extensions );
3602 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
3604 if ( options & SortRecommended )
3606 if ( a == QLatin1String(
"gpkg" ) )
3608 else if ( b == QLatin1String(
"gpkg" ) )
3610 else if ( a == QLatin1String(
"shp" ) )
3612 else if ( b == QLatin1String(
"shp" ) )
3616 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
3619 return extensionList;
3624 QList< QgsVectorFileWriter::DriverDetails > results;
3627 const int drvCount = OGRGetDriverCount();
3629 QStringList writableDrivers;
3630 for (
int i = 0; i < drvCount; ++i )
3632 OGRSFDriverH drv = OGRGetDriver( i );
3635 QString drvName = OGR_Dr_GetName( drv );
3641 if ( drvName == QLatin1String(
"ODS" ) || drvName == QLatin1String(
"XLSX" ) || drvName == QLatin1String(
"XLS" ) )
3645 if ( drvName == QLatin1String(
"ESRI Shapefile" ) )
3647 writableDrivers << QStringLiteral(
"DBF file" );
3649 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
3652 if ( drvName == QLatin1String(
"MapInfo File" ) )
3654 writableDrivers << QStringLiteral(
"MapInfo MIF" );
3656 else if ( drvName == QLatin1String(
"SQLite" ) )
3663 QString option = QStringLiteral(
"SPATIALITE=YES" );
3664 char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ),
nullptr };
3665 OGRSFDriverH poDriver;
3667 poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
3670 gdal::ogr_datasource_unique_ptr ds( OGR_Dr_CreateDataSource( poDriver, QStringLiteral(
"/vsimem/spatialitetest.sqlite" ).toUtf8().constData(), options ) );
3673 writableDrivers << QStringLiteral(
"SpatiaLite" );
3674 OGR_Dr_DeleteDataSource( poDriver, QStringLiteral(
"/vsimem/spatialitetest.sqlite" ).toUtf8().constData() );
3677 CPLFree( options[0] );
3679 writableDrivers << drvName;
3684 results.reserve( writableDrivers.count() );
3685 for (
const QString &drvName : std::as_const( writableDrivers ) )
3699 if ( options & SortRecommended )
3701 if ( a.driverName == QLatin1String(
"GPKG" ) )
3703 else if ( b.driverName == QLatin1String(
"GPKG" ) )
3705 else if ( a.driverName == QLatin1String(
"ESRI Shapefile" ) )
3707 else if ( b.driverName == QLatin1String(
"ESRI Shapefile" ) )
3711 return a.
longName.toLower().localeAwareCompare( b.
longName.toLower() ) < 0;
3718 QString ext = extension.trimmed();
3719 if ( ext.isEmpty() )
3722 if ( ext.startsWith(
'.' ) )
3726 int const drvCount = GDALGetDriverCount();
3728 for (
int i = 0; i < drvCount; ++i )
3730 GDALDriverH drv = GDALGetDriver( i );
3736 QString drvName = GDALGetDriverShortName( drv );
3737 QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
3739 const auto constDriverExtensions = driverExtensions;
3740 for (
const QString &driver : constDriverExtensions )
3742 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
3753 QString filterString;
3757 if ( !filterString.isEmpty() )
3758 filterString += QLatin1String(
";;" );
3760 filterString += details.filterString;
3762 return filterString;
3771 return QStringLiteral(
"%1 (%2 %3)" ).arg( metadata.
trLongName,
3772 metadata.
glob.toLower(),
3773 metadata.
glob.toUpper() );
3778 if ( codecName == QLatin1String(
"System" ) )
3779 return QStringLiteral(
"LDID/0" );
3781 const QRegularExpression re( QRegularExpression::anchoredPattern( QString(
"(CP|windows-|ISO[ -])(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
3782 const QRegularExpressionMatch match = re.match( codecName );
3783 if ( match.hasMatch() )
3785 QString
c = match.captured( 2 ).remove(
'-' );
3787 ( void )
c.toInt( &isNumber );
3815 OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
3816 OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
3819 int nTotalLevels = 0;
3821 QgsSymbolList::iterator symbolIt = symbolList.begin();
3822 for ( ; symbolIt != symbolList.end(); ++symbolIt )
3824 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3825 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
3827 int nLevels = ( *symbolIt )->symbolLayerCount();
3828 for (
int i = 0; i < nLevels; ++i )
3830 mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
3831 OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
3832 ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
3836 OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
3842 if ( !details.renderer )
3847 QHash< QgsSymbol *, QList<QgsFeature> > features;
3856 startRender( details.renderer.get(), details.sourceFields );
3876 QString msg = QObject::tr(
"Failed to transform, writing stopped. (Exception: %1)" )
3887 featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
3888 if ( !featureSymbol )
3893 QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
3894 if ( it == features.end() )
3896 it = features.insert( featureSymbol, QList<QgsFeature>() );
3898 it.value().append( fet );
3903 QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
3904 for (
int i = 0; i < symbols.count(); i++ )
3910 if ( level < 0 || level >= 1000 )
3913 while ( level >= levels.count() )
3915 levels[level].append( item );
3920 int nTotalFeatures = 0;
3923 for (
int l = 0; l < levels.count(); l++ )
3926 for (
int i = 0; i < level.count(); i++ )
3929 QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.
symbol() );
3930 if ( levelIt == features.end() )
3936 double mmsf = mmScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3937 double musf = mapUnitScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
3939 int llayer = item.
layer();
3940 QList<QgsFeature> &featureList = levelIt.value();
3941 QList<QgsFeature>::iterator featureIt = featureList.begin();
3942 for ( ; featureIt != featureList.end(); ++featureIt )
3952 QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
3953 if ( !styleString.isEmpty() )
3955 OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
3956 if ( !writeFeature(
mLayer, ogrFeature.get() ) )
3969 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
3986 return 1000 / scale;
4003 return scale / 1000;
4011 mRenderer = createSymbologyRenderer( sourceRenderer );
4017 mRenderer->startRender( mRenderContext, fields );
4020 void QgsVectorFileWriter::stopRender()
4027 mRenderer->stopRender( mRenderContext );
4030 std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer(
QgsFeatureRenderer *sourceRenderer )
const
4036 if ( !sourceRenderer )
4041 return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->
clone() );
4048 const QSet<QString> rendererAttributes = renderer->
usedAttributes( context );
4049 for (
const QString &attr : rendererAttributes )
4054 attList.append( index );
4060 QStringList QgsVectorFileWriter::concatenateOptions(
const QMap<QString, QgsVectorFileWriter::Option *> &options )
4063 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
4065 for ( it = options.constBegin(); it != options.constEnd(); ++it )
4068 switch ( option->
type )
4075 list.append( QStringLiteral(
"%1=%2" ).arg( it.key() ).arg( opt->
defaultValue ) );
4085 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
defaultValue ) );
4095 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
defaultValue ) );
4104 list.append( QStringLiteral(
"%1=%2" ).arg( it.key(), opt->
mValue ) );
4115 OGRSFDriverH hDriver =
nullptr;
4118 return QgsVectorFileWriter::EditionCapabilities();
4119 QString drvName = OGR_Dr_GetName( hDriver );
4120 QgsVectorFileWriter::EditionCapabilities caps = QgsVectorFileWriter::EditionCapabilities();
4121 if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
4126 if ( !( drvName == QLatin1String(
"ESRI Shapefile" ) && QFile::exists( datasetName ) ) )
4129 if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
4133 int layer_count = OGR_DS_GetLayerCount( hDS.get() );
4136 OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
4139 if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
4142 if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
4153 const QString &layerNameIn )
4155 OGRSFDriverH hDriver =
nullptr;
4160 QString layerName( layerNameIn );
4161 if ( layerName.isEmpty() )
4162 layerName = QFileInfo( datasetName ).baseName();
4164 return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
4169 const QString &layerName,
4173 OGRSFDriverH hDriver =
nullptr;
4177 OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
4183 OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
4184 const auto constAttributes = attributes;
4185 for (
int idx : constAttributes )
4188 if ( OGR_FD_GetFieldIndex( defn, fld.
name().toUtf8().constData() ) < 0 )