24#include <cpl_string.h>
29#include <ogr_srs_api.h>
52#include <QJsonDocument>
55#include <QRegularExpression>
61using namespace Qt::StringLiterals;
79 const QString &fileEncoding,
83 const QString &driverName,
84 const QStringList &datasourceOptions,
85 const QStringList &layerOptions,
97 init( vectorFileName, fileEncoding, fields, geometryType,
98 srs, driverName, datasourceOptions, layerOptions, newFilename,
nullptr,
103 const QString &fileEncoding,
107 const QString &driverName,
108 const QStringList &datasourceOptions,
109 const QStringList &layerOptions,
110 QString *newFilename,
113 const QString &layerName,
119 bool includeConstraints,
120 bool setFieldDomains,
129 init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName,
130 datasourceOptions, layerOptions, newFilename, fieldValueConverter,
131 layerName, action, newLayer, sinkFlags, transformContext, fieldNameSource, sourceDatabaseProviderConnection );
135 const QString &fileName,
142 QString *newFilename,
156 if ( driverName ==
"MapInfo MIF"_L1 )
160 GDALDriverH gdalDriver = GDALGetDriverByName( driverName.toLocal8Bit().constData() );
164 CSLConstList
driverMetadata = GDALGetMetadata( gdalDriver,
nullptr );
168#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
169 return CSLFetchBoolean(
driverMetadata, GDAL_DCAP_FEATURE_STYLES_WRITE,
false );
171 return CSLFetchBoolean(
driverMetadata, GDAL_DCAP_FEATURE_STYLES,
false );
175void QgsVectorFileWriter::init( QString vectorFileName,
176 QString fileEncoding,
180 const QString &driverName,
181 QStringList datasourceOptions,
182 QStringList layerOptions,
183 QString *newFilename,
184 FieldValueConverter *fieldValueConverter,
185 const QString &layerNameIn,
186 ActionOnExistingFile action,
187 QString *newLayer, SinkFlags sinkFlags,
191#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,5,0)
192 ( void )sourceDatabaseProviderConnection;
197 if ( vectorFileName.isEmpty() )
204 if ( driverName ==
"MapInfo MIF"_L1 )
208 else if ( driverName ==
"SpatiaLite"_L1 )
211 if ( !datasourceOptions.contains( u
"SPATIALITE=YES"_s ) )
213 datasourceOptions.append( u
"SPATIALITE=YES"_s );
216 else if ( driverName ==
"DBF file"_L1 )
219 if ( !layerOptions.contains( u
"SHPT=NULL"_s ) )
221 layerOptions.append( u
"SHPT=NULL"_s );
223 srs = QgsCoordinateReferenceSystem();
230#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,3,1)
231 QString fidFieldName;
234 for (
const QString &layerOption : layerOptions )
236 if ( layerOption.startsWith(
"FID="_L1 ) )
238 fidFieldName = layerOption.mid( 4 );
242 if ( fidFieldName.isEmpty() )
243 fidFieldName = u
"fid"_s;
248 OGRSFDriverH poDriver;
251 poDriver = OGRGetDriverByName(
mOgrDriverName.toLocal8Bit().constData() );
255 mErrorMessage = QObject::tr(
"OGR driver for '%1' not found (OGR error: %2)" )
257 QString::fromUtf8( CPLGetLastErrorMsg() ) );
262 mOgrDriverLongName = QString( GDALGetMetadataItem( poDriver, GDAL_DMD_LONGNAME,
nullptr ) );
269 if ( layerOptions.join( QString() ).toUpper().indexOf(
"ENCODING="_L1 ) == -1 )
274 if ( driverName ==
"ESRI Shapefile"_L1 && !vectorFileName.endsWith(
".shp"_L1, Qt::CaseInsensitive ) )
276 vectorFileName +=
".shp"_L1;
278 else if ( driverName ==
"DBF file"_L1 && !vectorFileName.endsWith(
".dbf"_L1, Qt::CaseInsensitive ) )
280 vectorFileName +=
".dbf"_L1;
290 QStringList allExts = metadata.glob.split(
' ', Qt::SkipEmptyParts );
292 const auto constAllExts = allExts;
293 for (
const QString &ext : constAllExts )
296 if ( vectorFileName.endsWith( ext.mid( 1 ), Qt::CaseInsensitive ) )
305 allExts = metadata.ext.split(
' ', Qt::SkipEmptyParts );
306 vectorFileName +=
'.' + allExts[0];
312 if ( vectorFileName.endsWith(
".gdb"_L1, Qt::CaseInsensitive ) )
314 QDir dir( vectorFileName );
317 QFileInfoList fileList = dir.entryInfoList(
318 QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst );
319 const auto constFileList = fileList;
320 for (
const QFileInfo &info : constFileList )
322 QFile::remove( info.absoluteFilePath() );
325 QDir().rmdir( vectorFileName );
329 QFile::remove( vectorFileName );
334 if ( metadataFound && !metadata.compulsoryEncoding.isEmpty() )
336 if ( fileEncoding.compare( metadata.compulsoryEncoding, Qt::CaseInsensitive ) != 0 )
338 QgsDebugMsgLevel( u
"forced %1 encoding for %2"_s.arg( metadata.compulsoryEncoding, driverName ), 2 );
339 fileEncoding = metadata.compulsoryEncoding;
344 char **options =
nullptr;
345 if ( !datasourceOptions.isEmpty() )
347 options =
new char *[ datasourceOptions.size() + 1 ];
348 for (
int i = 0; i < datasourceOptions.size(); i++ )
351 options[i] = CPLStrdup( datasourceOptions[i].toUtf8().constData() );
353 options[ datasourceOptions.size()] =
nullptr;
360 mDS.reset( OGR_Dr_CreateDataSource( poDriver, vectorFileName.toUtf8().constData(), options ) );
362 mDS.reset( OGROpen( vectorFileName.toUtf8().constData(), TRUE,
nullptr ) );
366 for (
int i = 0; i < datasourceOptions.size(); i++ )
367 CPLFree( options[i] );
376 mErrorMessage = QObject::tr(
"Creation of data source failed (OGR error: %1)" )
377 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
379 mErrorMessage = QObject::tr(
"Opening of data source in update mode failed (OGR error: %1)" )
380 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
384 QString layerName( layerNameIn );
385 if ( layerName.isEmpty() )
386 layerName = QFileInfo( vectorFileName ).baseName();
390 const int layer_count = OGR_DS_GetLayerCount(
mDS.get() );
391 for (
int i = 0; i < layer_count; i++ )
393 OGRLayerH hLayer = OGR_DS_GetLayer(
mDS.get(), i );
394 if ( EQUAL( OGR_L_GetName( hLayer ), layerName.toUtf8().constData() ) )
396 if ( OGR_DS_DeleteLayer(
mDS.get(), i ) != OGRERR_NONE )
399 mErrorMessage = QObject::tr(
"Overwriting of existing layer failed (OGR error: %1)" )
400 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
418 mCodec = QTextCodec::codecForName( fileEncoding.toLocal8Bit().constData() );
421 QgsDebugError(
"error finding QTextCodec for " + fileEncoding );
423 QgsSettings settings;
424 QString enc = settings.
value( u
"UI/encoding"_s,
"System" ).toString();
425 mCodec = QTextCodec::codecForName( enc.toLocal8Bit().constData() );
429 mCodec = QTextCodec::codecForLocale();
435 if ( driverName ==
"KML"_L1 || driverName ==
"LIBKML"_L1 || driverName ==
"GPX"_L1 )
437 if ( srs.
authid() !=
"EPSG:4326"_L1 )
441 mCoordinateTransform = std::make_unique<QgsCoordinateTransform>( srs, wgs84, transformContext );
452 int optIndex = layerOptions.indexOf(
"FEATURE_DATASET="_L1 );
453 if ( optIndex != -1 )
455 layerOptions.removeAt( optIndex );
458 if ( !layerOptions.isEmpty() )
460 options =
new char *[ layerOptions.size() + 1 ];
461 for (
int i = 0; i < layerOptions.size(); i++ )
464 options[i] = CPLStrdup( layerOptions[i].toUtf8().constData() );
466 options[ layerOptions.size()] =
nullptr;
470 CPLSetConfigOption(
"SHAPE_ENCODING",
"" );
474 mLayer = OGR_DS_CreateLayer(
mDS.get(), layerName.toUtf8().constData(),
mOgrRef, wkbType, options );
477 *newLayer = OGR_L_GetName(
mLayer );
478 if ( driverName ==
"GPX"_L1 )
485 if ( !EQUAL( layerName.toUtf8().constData(),
"track_points" ) &&
486 !EQUAL( layerName.toUtf8().constData(),
"route_points" ) )
488 *newLayer = u
"waypoints"_s;
495 const char *pszForceGPXTrack
496 = CSLFetchNameValue( options,
"FORCE_GPX_TRACK" );
497 if ( pszForceGPXTrack && CPLTestBool( pszForceGPXTrack ) )
498 *newLayer = u
"tracks"_s;
500 *newLayer = u
"routes"_s;
507 const char *pszForceGPXRoute
508 = CSLFetchNameValue( options,
"FORCE_GPX_ROUTE" );
509 if ( pszForceGPXRoute && CPLTestBool( pszForceGPXRoute ) )
510 *newLayer = u
"routes"_s;
512 *newLayer = u
"tracks"_s;
522 else if ( driverName ==
"DGN"_L1 )
524 mLayer = OGR_DS_GetLayerByName(
mDS.get(),
"elements" );
528 mLayer = OGR_DS_GetLayerByName(
mDS.get(), layerName.toUtf8().constData() );
533 for (
int i = 0; i < layerOptions.size(); i++ )
534 CPLFree( options[i] );
543 QString layerName = vectorFileName.left( vectorFileName.indexOf(
".shp"_L1, Qt::CaseInsensitive ) );
544 QFile prjFile( layerName +
".qpj" );
545 if ( prjFile.exists() )
553 mErrorMessage = QObject::tr(
"Creation of layer failed (OGR error: %1)" )
554 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
556 mErrorMessage = QObject::tr(
"Opening of layer failed (OGR error: %1)" )
557 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
562 OGRFeatureDefnH defn = OGR_L_GetLayerDefn(
mLayer );
571 QSet<int> existingIdxs;
575#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
576 if (
const char *pszCreateFieldDefnFlags = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
nullptr ) )
578 char **papszTokens = CSLTokenizeString2( pszCreateFieldDefnFlags,
" ", 0 );
579 if ( CSLFindString( papszTokens,
"AlternativeName" ) >= 0 )
583 if ( CSLFindString( papszTokens,
"Comment" ) >= 0 )
587 CSLDestroy( papszTokens );
597#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
598 QSet<QString> existingDestDomainNames;
599 if ( sourceDatabaseProviderConnection )
601 char **domainNames = GDALDatasetGetFieldDomainNames(
mDS.get(),
nullptr );
602 for (
const char *
const *iterDomainNames = domainNames; iterDomainNames && *iterDomainNames; ++iterDomainNames )
604 existingDestDomainNames.insert( QString::fromUtf8( *iterDomainNames ) );
606 CSLDestroy( domainNames );
609#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
610 QSet< QString > usedAlternativeNames;
613 const QString ogrFidColumnName { OGR_L_GetFIDColumn(
mLayer ) };
614 const int fidNameIndex = OGR_FD_GetFieldIndex( defn, ogrFidColumnName.toUtf8() );
617 const bool promoteFidColumnToAttribute = !ogrFidColumnName.isEmpty() && fidNameIndex < 0 && fields.
lookupField( ogrFidColumnName ) >= 0;
618 int offsetRoomForFid = promoteFidColumnToAttribute ? 1 : 0;
620 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
622 QgsField attrField = fields.
at( fldIdx );
624 if ( fieldValueConverter )
626 attrField = fieldValueConverter->fieldDefinition( fields.
at( fldIdx ) );
631 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( attrField.
name() ) );
640 switch ( fieldNameSource )
643 name = attrField.
name();
647 name = !attrField.
alias().isEmpty() ? attrField.
alias() : attrField.
name();
651 OGRFieldType ogrType = OFTString;
652 OGRFieldSubType ogrSubType = OFSTNone;
653 int ogrWidth = attrField.
length();
654 int ogrPrecision = attrField.
precision();
655 if ( ogrPrecision > 0 )
658 switch ( attrField.
type() )
660 case QMetaType::Type::LongLong:
662 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
663 if ( pszDataTypes && strstr( pszDataTypes,
"Integer64" ) )
664 ogrType = OFTInteger64;
667 ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
671 case QMetaType::Type::QString:
673 if ( ( ogrWidth <= 0 || ogrWidth > 255 ) &&
mOgrDriverName ==
"ESRI Shapefile"_L1 )
677 case QMetaType::Type::Int:
678 ogrType = OFTInteger;
679 ogrWidth = ogrWidth > 0 && ogrWidth <= 10 ? ogrWidth : 10;
683 case QMetaType::Type::Bool:
684 ogrType = OFTInteger;
685 ogrSubType = OFSTBoolean;
690 case QMetaType::Type::Double:
691#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,3,1)
692 if (
mOgrDriverName ==
"GPKG"_L1 && attrField.
precision() == 0 && attrField.
name().compare( fidFieldName, Qt::CaseInsensitive ) == 0 )
695 ogrType = OFTInteger64;
702 case QMetaType::Type::QDate:
706 case QMetaType::Type::QTime:
718 case QMetaType::Type::QDateTime:
726 ogrType = OFTDateTime;
730 case QMetaType::Type::QByteArray:
734 case QMetaType::Type::QStringList:
740 ogrSubType = OFSTJSON;
744 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
745 if ( pszDataTypes && strstr( pszDataTypes,
"StringList" ) )
747 ogrType = OFTStringList;
748 mSupportedListSubTypes.insert( QMetaType::Type::QString );
758 case QMetaType::Type::QVariantMap:
761 const char *pszDataSubTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATASUBTYPES,
nullptr );
762 if ( pszDataSubTypes && strstr( pszDataSubTypes,
"JSON" ) )
765 ogrSubType = OFSTJSON;
773 case QMetaType::Type::QVariantList:
778 ogrSubType = OFSTJSON;
783 if ( attrField.
subType() == QMetaType::Type::QString )
785 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
786 if ( pszDataTypes && strstr( pszDataTypes,
"StringList" ) )
788 ogrType = OFTStringList;
789 mSupportedListSubTypes.insert( QMetaType::Type::QString );
798 else if ( attrField.
subType() == QMetaType::Type::Int )
800 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
801 if ( pszDataTypes && strstr( pszDataTypes,
"IntegerList" ) )
803 ogrType = OFTIntegerList;
804 mSupportedListSubTypes.insert( QMetaType::Type::Int );
813 else if ( attrField.
subType() == QMetaType::Type::Double )
815 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
816 if ( pszDataTypes && strstr( pszDataTypes,
"RealList" ) )
818 ogrType = OFTRealList;
819 mSupportedListSubTypes.insert( QMetaType::Type::Double );
828 else if ( attrField.
subType() == QMetaType::Type::LongLong )
830 const char *pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr );
831 if ( pszDataTypes && strstr( pszDataTypes,
"Integer64List" ) )
833 ogrType = OFTInteger64List;
834 mSupportedListSubTypes.insert( QMetaType::Type::LongLong );
848 mErrorMessage = QObject::tr(
"Unsupported type for field %1" )
849 .arg( attrField.
name() );
854 if (
mOgrDriverName ==
"SQLite"_L1 && name.compare(
"ogc_fid"_L1, Qt::CaseInsensitive ) == 0 )
857 for ( i = 0; i < 10; i++ )
859 name = u
"ogc_fid%1"_s.arg( i );
862 for ( j = 0; j < fields.
size() && name.compare( fields.
at( j ).
name(), Qt::CaseInsensitive ) != 0; j++ )
865 if ( j == fields.
size() )
871 mErrorMessage = QObject::tr(
"No available replacement for internal fieldname ogc_fid found" ).arg( attrField.
name() );
876 QgsMessageLog::logMessage( QObject::tr(
"Reserved attribute name ogc_fid replaced with %1" ).arg( name ), QObject::tr(
"OGR" ) );
883 OGR_Fld_SetWidth( fld.get(), ogrWidth );
886 if ( ogrPrecision >= 0 )
888 OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
891 if ( ogrSubType != OFSTNone )
892 OGR_Fld_SetSubType( fld.get(), ogrSubType );
894#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,6,0)
895 if ( !attrField.
alias().isEmpty() )
897 QString alternativeName = attrField.
alias();
899 while ( usedAlternativeNames.contains( alternativeName ) )
902 alternativeName = attrField.
alias() + u
" (%1)"_s.arg( ++counter );
904 OGR_Fld_SetAlternativeName( fld.get(),
mCodec->fromUnicode( alternativeName ).constData() );
905 usedAlternativeNames.insert( alternativeName );
908#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
909 OGR_Fld_SetComment( fld.get(),
mCodec->fromUnicode( attrField.
comment() ).constData() );
916 OGR_Fld_SetNullable( fld.get(),
false );
920 OGR_Fld_SetUnique( fld.get(),
true );
923#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,5,0)
927 if ( !domainName.isEmpty() )
929 bool canSetFieldDomainName =
false;
930 if ( existingDestDomainNames.contains( domainName ) )
934 canSetFieldDomainName =
true;
936 else if ( GDALDatasetTestCapability(
mDS.get(), ODsCAddFieldDomain ) )
946 std::unique_ptr<QgsFieldDomain> domain( sourceDatabaseProviderConnection->
fieldDomain( domainName ) );
952 char *pszFailureReason =
nullptr;
953 if ( GDALDatasetAddFieldDomain(
mDS.get(), hFieldDomain, &pszFailureReason ) )
955 existingDestDomainNames.insert( domainName );
956 canSetFieldDomainName =
true;
960 QgsDebugError( u
"cannot create field domain: %1"_s.arg( pszFailureReason ) );
962 CPLFree( pszFailureReason );
963 OGR_FldDomain_Destroy( hFieldDomain );
967 catch ( QgsProviderConnectionException & )
969 QgsDebugError( u
"Cannot retrieve field domain: %1"_s.arg( domainName ) );
972 if ( canSetFieldDomainName )
974 OGR_Fld_SetDomainName( fld.get(), domainName.toUtf8().toStdString().c_str() );
982 " type " + QString( QVariant::typeToName( attrField.
type() ) ) +
983 " width " + QString::number( ogrWidth ) +
984 " precision " + QString::number( ogrPrecision ), 2 );
985 if ( OGR_L_CreateField(
mLayer, fld.get(),
true ) != OGRERR_NONE )
988 mErrorMessage = QObject::tr(
"Creation of field %1 (%2) failed (OGR error: %3)" )
989 .arg( attrField.
name(),
990 QVariant::typeToName( attrField.
type() ),
991 QString::fromUtf8( CPLGetLastErrorMsg() ) );
996 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
997 QgsDebugMsgLevel( u
"returned field index for %1: %2"_s.arg( name ).arg( ogrIdx ), 2 );
998 if ( ogrIdx < 0 || existingIdxs.contains( ogrIdx ) )
1001 ogrIdx = OGR_FD_GetFieldCount( defn ) - 1;
1006 mErrorMessage = QObject::tr(
"Created field %1 not found (OGR error: %2)" )
1007 .arg( attrField.
name(),
1008 QString::fromUtf8( CPLGetLastErrorMsg() ) );
1014 if ( promoteFidColumnToAttribute )
1016 if ( ogrFidColumnName.compare( attrField.
name(), Qt::CaseInsensitive ) == 0 )
1019 offsetRoomForFid = 0;
1024 ogrIdx += offsetRoomForFid;
1028 existingIdxs.insert( ogrIdx );
1036 for (
int fldIdx = 0; fldIdx < fields.
count(); ++fldIdx )
1038 QgsField attrField = fields.
at( fldIdx );
1039 QString name( attrField.
name() );
1040 int ogrIdx = OGR_FD_GetFieldIndex( defn,
mCodec->fromUnicode( name ) );
1063 *newFilename = vectorFileName;
1066 mUsingTransaction =
true;
1067 if ( OGRERR_NONE != OGR_L_StartTransaction(
mLayer ) )
1069 mUsingTransaction =
false;
1079class QgsVectorFileWriterMetadataContainer
1083 QgsVectorFileWriterMetadataContainer()
1085 QMap<QString, QgsVectorFileWriter::Option *> datasetOptions;
1086 QMap<QString, QgsVectorFileWriter::Option *> layerOptions;
1089 datasetOptions.clear();
1090 layerOptions.clear();
1093 QObject::tr(
"Compression method." ),
1095 << u
"UNCOMPRESSED"_s
1103 QObject::tr(
"Geometry encoding." ),
1113 QObject::tr(
"Maximum number of rows per batch." ),
1118 QObject::tr(
"Name for the feature identifier column" ),
1123 QObject::tr(
"Name for the geometry column" ),
1127 driverMetadata.insert( u
"Arrow"_s,
1130 QObject::tr(
"(Geo)Arrow" ),
1131 u
"*.arrow *.feather *.arrows *.ipc"_s,
1140 datasetOptions.clear();
1141 layerOptions.clear();
1143 driverMetadata.insert( u
"AVCE00"_s,
1145 u
"Arc/Info ASCII Coverage"_s,
1146 QObject::tr(
"Arc/Info ASCII Coverage" ),
1155 datasetOptions.clear();
1156 layerOptions.clear();
1159 QObject::tr(
"By default when creating new .csv files they "
1160 "are created with the line termination conventions "
1161 "of the local platform (CR/LF on Win32 or LF on all other systems). "
1162 "This may be overridden through the use of the LINEFORMAT option." ),
1171 QObject::tr(
"By default, the geometry of a feature written to a .csv file is discarded. "
1172 "It is possible to export the geometry in its WKT representation by "
1173 "specifying GEOMETRY=AS_WKT. It is also possible to export point geometries "
1174 "into their X,Y,Z components by specifying GEOMETRY=AS_XYZ, GEOMETRY=AS_XY "
1175 "or GEOMETRY=AS_YX." ),
1186 QObject::tr(
"Name of geometry column. Only used if GEOMETRY=AS_WKT. Defaults to 'WKT'." ),
1191 QObject::tr(
"Create the associated .csvt file to describe the type of each "
1192 "column of the layer and its optional width and precision. "
1193 "This option also creates a .prj file which stores coordinate system information." ),
1198 QObject::tr(
"Field separator character." ),
1204#
if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
1211 QObject::tr(
"Double-quote strings. IF_AMBIGUOUS means that string values that look like numbers will be quoted." ),
1214 << u
"IF_AMBIGUOUS"_s
1220 QObject::tr(
"Write a UTF-8 Byte Order Mark (BOM) at the start of the file." ),
1224#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
1226 QObject::tr(
"Whether to write a header line with the field names." ),
1231 driverMetadata.insert( u
"CSV"_s,
1233 u
"Comma Separated Value [CSV]"_s,
1234 QObject::tr(
"Comma Separated Value [CSV]" ),
1243 datasetOptions.clear();
1244 layerOptions.clear();
1246 driverMetadata.insert( u
"FlatGeobuf"_s,
1249 QObject::tr(
"FlatGeobuf" ),
1259 datasetOptions.clear();
1260 layerOptions.clear();
1263 QObject::tr(
"Override the type of shapefile created. "
1264 "Can be one of NULL for a simple .dbf file with no .shp file, POINT, "
1265 "ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or "
1266 "MULTIPOINTZ for 3D;" ) +
1267 QObject::tr(
" POINTM, ARCM, POLYGONM or MULTIPOINTM for measured geometries"
1268 " and POINTZM, ARCZM, POLYGONZM or MULTIPOINTZM for 3D measured"
1270 QObject::tr(
" MULTIPATCH files are supported since GDAL 2.2." ) +
1289 << u
"MULTIPOINTZM"_s
1300 QObject::tr(
"Set the encoding value in the DBF file. "
1301 "The default value is LDID/87. It is not clear "
1302 "what other values may be appropriate." ),
1310 QObject::tr(
"Set to YES to resize fields to their optimal size." ),
1314 driverMetadata.insert( u
"ESRI"_s,
1316 u
"ESRI Shapefile"_s,
1317 QObject::tr(
"ESRI Shapefile" ),
1326 datasetOptions.clear();
1327 layerOptions.clear();
1329 driverMetadata.insert( u
"DBF File"_s,
1332 QObject::tr(
"DBF File" ),
1341 datasetOptions.clear();
1342 layerOptions.clear();
1345 QObject::tr(
"Set to YES to write a bbox property with the bounding box "
1346 "of the geometries at the feature and feature collection level." ),
1351 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1352 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1357 QObject::tr(
"Whether to use RFC 7946 standard. "
1358 "If disabled GeoJSON 2008 initial version will be used. "
1359 "Default is NO (thus GeoJSON 2008). See also Documentation (via Help button)" ),
1363 driverMetadata.insert( u
"GeoJSON"_s,
1366 QObject::tr(
"GeoJSON" ),
1376 datasetOptions.clear();
1377 layerOptions.clear();
1380 QObject::tr(
"Maximum number of figures after decimal separator to write in coordinates. "
1381 "Defaults to 15. Truncation will occur to remove trailing zeros." ),
1386 QObject::tr(
"Whether to start records with the RS=0x1E character (RFC 8142 standard). "
1387 "Defaults to NO: Newline Delimited JSON (geojsonl). \n"
1388 "If set to YES: RFC 8142 standard: GeoJSON Text Sequences (geojsons)." ),
1392 driverMetadata.insert( u
"GeoJSONSeq"_s,
1394 u
"GeoJSON - Newline Delimited"_s,
1395 QObject::tr(
"GeoJSON - Newline Delimited" ),
1396 u
"*.geojsonl *.geojsons *.json"_s,
1397 u
"geojsonl geojsons json"_s,
1405 datasetOptions.clear();
1406 layerOptions.clear();
1409 QObject::tr(
"whether the document must be in RSS 2.0 or Atom 1.0 format. "
1410 "Default value : RSS" ),
1418 QObject::tr(
"The encoding of location information. Default value : SIMPLE. "
1419 "W3C_GEO only supports point geometries. "
1420 "SIMPLE or W3C_GEO only support geometries in geographic WGS84 coordinates." ),
1429 QObject::tr(
"If defined to YES, extension fields will be written. "
1430 "If the field name not found in the base schema matches "
1431 "the foo_bar pattern, foo will be considered as the namespace "
1432 "of the element, and a <foo:bar> element will be written. "
1433 "Otherwise, elements will be written in the <ogr:> namespace." ),
1438 QObject::tr(
"If defined to NO, only <entry> or <item> elements will be written. "
1439 "The user will have to provide the appropriate header and footer of the document." ),
1444 QObject::tr(
"XML content that will be put between the <channel> element and the "
1445 "first <item> element for a RSS document, or between the xml tag and "
1446 "the first <entry> element for an Atom document." ),
1451 QObject::tr(
"Value put inside the <title> element in the header. "
1452 "If not provided, a dummy value will be used as that element is compulsory." ),
1457 QObject::tr(
"Value put inside the <description> element in the header. "
1458 "If not provided, a dummy value will be used as that element is compulsory." ),
1463 QObject::tr(
"Value put inside the <link> element in the header. "
1464 "If not provided, a dummy value will be used as that element is compulsory." ),
1469 QObject::tr(
"Value put inside the <updated> element in the header. "
1470 "Should be formatted as a XML datetime. "
1471 "If not provided, a dummy value will be used as that element is compulsory." ),
1476 QObject::tr(
"Value put inside the <author><name> element in the header. "
1477 "If not provided, a dummy value will be used as that element is compulsory." ),
1482 QObject::tr(
"Value put inside the <id> element in the header. "
1483 "If not provided, a dummy value will be used as that element is compulsory." ),
1487 driverMetadata.insert( u
"GeoRSS"_s,
1490 QObject::tr(
"GeoRSS" ),
1500 datasetOptions.clear();
1501 layerOptions.clear();
1504 QObject::tr(
"If provided, this URI will be inserted as the schema location. "
1505 "Note that the schema file isn't actually accessed by OGR, so it "
1506 "is up to the user to ensure it will match the schema of the OGR "
1507 "produced GML data file." ),
1512 QObject::tr(
"This writes a GML application schema file to a corresponding "
1513 ".xsd file (with the same basename). If INTERNAL is used the "
1514 "schema is written within the GML file, but this is experimental "
1515 "and almost certainly not valid XML. "
1516 "OFF disables schema generation (and is implicit if XSISCHEMAURI is used)." ),
1525 QObject::tr(
"This is the prefix for the application target namespace." ),
1530 QObject::tr(
"Can be set to TRUE to avoid writing the prefix of the "
1531 "application target namespace in the GML file." ),
1536 QObject::tr(
"Defaults to 'http://ogr.maptools.org/'. "
1537 "This is the application target namespace." ),
1538 u
"http://ogr.maptools.org/"_s
1542 QObject::tr(
"GML version to use." ),
1552 QObject::tr(
"Only valid when FORMAT=GML3/GML3Degree/GML3.2. Default to YES. "
1553 "If YES, SRS with EPSG authority will be written with the "
1554 "'urn:ogc:def:crs:EPSG::' prefix. In the case the SRS is a "
1555 "geographic SRS without explicit AXIS order, but that the same "
1556 "SRS authority code imported with ImportFromEPSGA() should be "
1557 "treated as lat/long, then the function will take care of coordinate "
1558 "order swapping. If set to NO, SRS with EPSG authority will be "
1559 "written with the 'EPSG:' prefix, even if they are in lat/long order." ),
1564 QObject::tr(
"only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES. "
1565 "If set to NO, the <gml:boundedBy> element will not be written for "
1571 QObject::tr(
"Default to YES. If YES, the output will be indented with spaces "
1572 "for more readability, but at the expense of file size." ),
1577 driverMetadata.insert( u
"GML"_s,
1579 u
"Geography Markup Language [GML]"_s,
1580 QObject::tr(
"Geography Markup Language [GML]" ),
1590 datasetOptions.clear();
1591 layerOptions.clear();
1594 QObject::tr(
"Human-readable identifier (e.g. short name) for the layer content" ),
1599 QObject::tr(
"Human-readable description for the layer content" ),
1604 QObject::tr(
"Name for the feature identifier column" ),
1609 QObject::tr(
"Name for the geometry column" ),
1614 QObject::tr(
"If a spatial index must be created." ),
1618 driverMetadata.insert( u
"GPKG"_s,
1621 QObject::tr(
"GeoPackage" ),
1622#
if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
1623 u
"*.gpkg *.gpkg.zip"_s,
1635 datasetOptions.clear();
1636 layerOptions.clear();
1638 driverMetadata.insert( u
"GMT"_s,
1640 u
"Generic Mapping Tools [GMT]"_s,
1641 QObject::tr(
"Generic Mapping Tools [GMT]" ),
1650 datasetOptions.clear();
1651 layerOptions.clear();
1654 QObject::tr(
"By default when writing a layer whose features are of "
1655 "type wkbLineString, the GPX driver chooses to write "
1656 "them as routes. If FORCE_GPX_TRACK=YES is specified, "
1657 "they will be written as tracks." ),
1662 QObject::tr(
"By default when writing a layer whose features are of "
1663 "type wkbMultiLineString, the GPX driver chooses to write "
1664 "them as tracks. If FORCE_GPX_ROUTE=YES is specified, "
1665 "they will be written as routes, provided that the multilines "
1666 "are composed of only one single line." ),
1671 QObject::tr(
"If GPX_USE_EXTENSIONS=YES is specified, "
1672 "extra fields will be written inside the <extensions> tag." ),
1677 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS_URL "
1678 "is set. The namespace value used for extension tags. By default, 'ogr'." ),
1683 QObject::tr(
"Only used if GPX_USE_EXTENSIONS=YES and GPX_EXTENSIONS_NS "
1684 "is set. The namespace URI. By default, 'http://osgeo.org/gdal'." ),
1685 u
"http://osgeo.org/gdal"_s
1689 QObject::tr(
"By default files are created with the line termination "
1690 "conventions of the local platform (CR/LF on win32 or LF "
1691 "on all other systems). This may be overridden through use "
1692 "of the LINEFORMAT layer creation option which may have a value "
1693 "of CRLF (DOS format) or LF (Unix format)." ),
1701 driverMetadata.insert( u
"GPX"_s,
1703 u
"GPS eXchange Format [GPX]"_s,
1704 QObject::tr(
"GPS eXchange Format [GPX]" ),
1714 datasetOptions.clear();
1715 layerOptions.clear();
1717 driverMetadata.insert( u
"Interlis 1"_s,
1720 QObject::tr(
"INTERLIS 1" ),
1721 u
"*.itf *.xml *.ili"_s,
1729 datasetOptions.clear();
1730 layerOptions.clear();
1732 driverMetadata.insert( u
"Interlis 2"_s,
1735 QObject::tr(
"INTERLIS 2" ),
1736 u
"*.xtf *.xml *.ili"_s,
1744 datasetOptions.clear();
1745 layerOptions.clear();
1748 QObject::tr(
"Allows you to specify the field to use for the KML <name> element." ),
1753 QObject::tr(
"Allows you to specify the field to use for the KML <description> element." ),
1758 QObject::tr(
"Allows you to specify the AltitudeMode to use for KML geometries. "
1759 "This will only affect 3D geometries and must be one of the valid KML options." ),
1761 << u
"clampToGround"_s
1762 << u
"relativeToGround"_s
1764 u
"relativeToGround"_s
1768 QObject::tr(
"The DOCUMENT_ID datasource creation option can be used to specified "
1769 "the id of the root <Document> node. The default value is root_doc." ),
1773 driverMetadata.insert( u
"KML"_s,
1775 u
"Keyhole Markup Language [KML]"_s,
1776 QObject::tr(
"Keyhole Markup Language [KML]" ),
1786 datasetOptions.clear();
1787 layerOptions.clear();
1789 auto insertMapInfoOptions = []( QMap<QString, QgsVectorFileWriter::Option *> &datasetOptions, QMap<QString, QgsVectorFileWriter::Option *> &layerOptions )
1792 QObject::tr(
"Use this to turn on 'quick spatial index mode'. "
1793 "In this mode writing files can be about 5 times faster, "
1794 "but spatial queries can be up to 30 times slower." ),
1803 QObject::tr(
"(multiples of 512): Block size for .map files. Defaults "
1804 "to 512. MapInfo 15.2 and above creates .tab files with a "
1805 "blocksize of 16384 bytes. Any MapInfo version should be "
1806 "able to handle block sizes from 512 to 32256." ),
1810 QObject::tr(
"xmin,ymin,xmax,ymax: Define custom layer bounds to increase the "
1811 "accuracy of the coordinates. Note: the geometry of written "
1812 "features must be within the defined box." ),
1816 insertMapInfoOptions( datasetOptions, layerOptions );
1818 driverMetadata.insert( u
"MapInfo File"_s,
1819 QgsVectorFileWriter::MetaData(
1821 QObject::tr(
"Mapinfo TAB" ),
1828 datasetOptions.clear();
1829 layerOptions.clear();
1830 insertMapInfoOptions( datasetOptions, layerOptions );
1833 driverMetadata.insert( u
"MapInfo MIF"_s,
1834 QgsVectorFileWriter::MetaData(
1836 QObject::tr(
"Mapinfo MIF" ),
1845 datasetOptions.clear();
1846 layerOptions.clear();
1848 datasetOptions.insert( u
"3D"_s,
new QgsVectorFileWriter::BoolOption(
1849 QObject::tr(
"Determine whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) "
1850 "seed file should be used. This option is ignored if the SEED option is provided." ),
1854 datasetOptions.insert( u
"SEED"_s,
new QgsVectorFileWriter::StringOption(
1855 QObject::tr(
"Override the seed file to use." ),
1859 datasetOptions.insert( u
"COPY_WHOLE_SEED_FILE"_s,
new QgsVectorFileWriter::BoolOption(
1860 QObject::tr(
"Indicate whether the whole seed file should be copied. "
1861 "If not, only the first three elements will be copied." ),
1865 datasetOptions.insert( u
"COPY_SEED_FILE_COLOR_TABLE"_s,
new QgsVectorFileWriter::BoolOption(
1866 QObject::tr(
"Indicates whether the color table should be copied from the seed file." ),
1870 datasetOptions.insert( u
"MASTER_UNIT_NAME"_s,
new QgsVectorFileWriter::StringOption(
1871 QObject::tr(
"Override the master unit name from the seed file with "
1872 "the provided one or two character unit name." ),
1876 datasetOptions.insert( u
"SUB_UNIT_NAME"_s,
new QgsVectorFileWriter::StringOption(
1877 QObject::tr(
"Override the sub unit name from the seed file with the provided "
1878 "one or two character unit name." ),
1882 datasetOptions.insert( u
"SUB_UNITS_PER_MASTER_UNIT"_s,
new QgsVectorFileWriter::IntOption(
1883 QObject::tr(
"Override the number of subunits per master unit. "
1884 "By default the seed file value is used." ),
1888 datasetOptions.insert( u
"UOR_PER_SUB_UNIT"_s,
new QgsVectorFileWriter::IntOption(
1889 QObject::tr(
"Override the number of UORs (Units of Resolution) "
1890 "per sub unit. By default the seed file value is used." ),
1894 datasetOptions.insert( u
"ORIGIN"_s,
new QgsVectorFileWriter::StringOption(
1895 QObject::tr(
"ORIGIN=x,y,z: Override the origin of the design plane. "
1896 "By default the origin from the seed file is used." ),
1900 driverMetadata.insert( u
"DGN"_s,
1901 QgsVectorFileWriter::MetaData(
1902 u
"Microstation DGN"_s,
1903 QObject::tr(
"Microstation DGN" ),
1912 datasetOptions.clear();
1913 layerOptions.clear();
1915 datasetOptions.insert( u
"UPDATES"_s,
new QgsVectorFileWriter::SetOption(
1916 QObject::tr(
"Should update files be incorporated into the base data on the fly." ),
1923 datasetOptions.insert( u
"SPLIT_MULTIPOINT"_s,
new QgsVectorFileWriter::BoolOption(
1924 QObject::tr(
"Should multipoint soundings be split into many single point sounding features. "
1925 "Multipoint geometries are not well handled by many formats, "
1926 "so it can be convenient to split single sounding features with many points "
1927 "into many single point features." ),
1931 datasetOptions.insert( u
"ADD_SOUNDG_DEPTH"_s,
new QgsVectorFileWriter::BoolOption(
1932 QObject::tr(
"Should a DEPTH attribute be added on SOUNDG features and assign the depth "
1933 "of the sounding. This should only be enabled when SPLIT_MULTIPOINT is "
1938 datasetOptions.insert( u
"RETURN_PRIMITIVES"_s,
new QgsVectorFileWriter::BoolOption(
1939 QObject::tr(
"Should all the low level geometry primitives be returned as special "
1940 "IsolatedNode, ConnectedNode, Edge and Face layers." ),
1944 datasetOptions.insert( u
"PRESERVE_EMPTY_NUMBERS"_s,
new QgsVectorFileWriter::BoolOption(
1945 QObject::tr(
"If enabled, numeric attributes assigned an empty string as a value will "
1946 "be preserved as a special numeric value. This option should not generally "
1947 "be needed, but may be useful when translated S-57 to S-57 losslessly." ),
1951 datasetOptions.insert( u
"LNAM_REFS"_s,
new QgsVectorFileWriter::BoolOption(
1952 QObject::tr(
"Should LNAM and LNAM_REFS fields be attached to features capturing "
1953 "the feature to feature relationships in the FFPT group of the S-57 file." ),
1957 datasetOptions.insert( u
"RETURN_LINKAGES"_s,
new QgsVectorFileWriter::BoolOption(
1958 QObject::tr(
"Should additional attributes relating features to their underlying "
1959 "geometric primitives be attached. These are the values of the FSPT group, "
1960 "and are primarily needed when doing S-57 to S-57 translations." ),
1964 datasetOptions.insert( u
"RECODE_BY_DSSI"_s,
new QgsVectorFileWriter::BoolOption(
1965 QObject::tr(
"Should attribute values be recoded to UTF-8 from the character encoding "
1966 "specified in the S57 DSSI record." ),
1972 driverMetadata.insert( u
"S57"_s,
1973 QgsVectorFileWriter::MetaData(
1974 u
"S-57 Base file"_s,
1975 QObject::tr(
"S-57 Base file" ),
1984 datasetOptions.clear();
1985 layerOptions.clear();
1987 driverMetadata.insert( u
"SDTS"_s,
1988 QgsVectorFileWriter::MetaData(
1989 u
"Spatial Data Transfer Standard [SDTS]"_s,
1990 QObject::tr(
"Spatial Data Transfer Standard [SDTS]" ),
1999 datasetOptions.clear();
2000 layerOptions.clear();
2002 datasetOptions.insert( u
"METADATA"_s,
new QgsVectorFileWriter::BoolOption(
2003 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
2004 "tables in a new database. By default these metadata tables are created "
2005 "when a new database is created." ),
2010 datasetOptions.insert( u
"SPATIALITE"_s,
new QgsVectorFileWriter::HiddenOption(
2015 datasetOptions.insert( u
"INIT_WITH_EPSG"_s,
new QgsVectorFileWriter::HiddenOption(
2019 layerOptions.insert( u
"FORMAT"_s,
new QgsVectorFileWriter::SetOption(
2020 QObject::tr(
"Controls the format used for the geometry column. Defaults to WKB. "
2021 "This is generally more space and processing efficient, but harder "
2022 "to inspect or use in simple applications than WKT (Well Known Text)." ),
2029 layerOptions.insert( u
"LAUNDER"_s,
new QgsVectorFileWriter::BoolOption(
2030 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
2031 "in SQLite. Laundered names will be converted to lower case and some special "
2032 "characters(' - #) will be changed to underscores." ),
2036 layerOptions.insert( u
"SPATIAL_INDEX"_s,
new QgsVectorFileWriter::HiddenOption(
2040 layerOptions.insert( u
"COMPRESS_GEOM"_s,
new QgsVectorFileWriter::HiddenOption(
2044 layerOptions.insert( u
"SRID"_s,
new QgsVectorFileWriter::HiddenOption(
2048 layerOptions.insert( u
"COMPRESS_COLUMNS"_s,
new QgsVectorFileWriter::StringOption(
2049 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
2050 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
2051 "for databases that have big string blobs. However, use with care, since "
2052 "the value of such columns will be seen as compressed binary content with "
2053 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
2054 "modifying or querying compressed columns, compression/decompression is "
2055 "done transparently. However, such columns cannot be (easily) queried with "
2056 "an attribute filter or WHERE clause. Note: in table definition, such columns "
2057 "have the 'VARCHAR_deflate' declaration type." ),
2061 driverMetadata.insert( u
"SQLite"_s,
2062 QgsVectorFileWriter::MetaData(
2064 QObject::tr(
"SQLite" ),
2074 datasetOptions.clear();
2075 layerOptions.clear();
2077 datasetOptions.insert( u
"METADATA"_s,
new QgsVectorFileWriter::BoolOption(
2078 QObject::tr(
"Can be used to avoid creating the geometry_columns and spatial_ref_sys "
2079 "tables in a new database. By default these metadata tables are created "
2080 "when a new database is created." ),
2084 datasetOptions.insert( u
"SPATIALITE"_s,
new QgsVectorFileWriter::HiddenOption(
2088 datasetOptions.insert( u
"INIT_WITH_EPSG"_s,
new QgsVectorFileWriter::BoolOption(
2089 QObject::tr(
"Insert the content of the EPSG CSV files into the spatial_ref_sys table. "
2090 "Set to NO for regular SQLite databases." ),
2094 layerOptions.insert( u
"FORMAT"_s,
new QgsVectorFileWriter::HiddenOption(
2098 layerOptions.insert( u
"LAUNDER"_s,
new QgsVectorFileWriter::BoolOption(
2099 QObject::tr(
"Controls whether layer and field names will be laundered for easier use "
2100 "in SQLite. Laundered names will be converted to lower case and some special "
2101 "characters(' - #) will be changed to underscores." ),
2105 layerOptions.insert( u
"SPATIAL_INDEX"_s,
new QgsVectorFileWriter::BoolOption(
2106 QObject::tr(
"If the database is of the SpatiaLite flavor, and if OGR is linked "
2107 "against libspatialite, this option can be used to control if a spatial "
2108 "index must be created." ),
2112 layerOptions.insert( u
"COMPRESS_GEOM"_s,
new QgsVectorFileWriter::BoolOption(
2113 QObject::tr(
"If the format of the geometry BLOB is of the SpatiaLite flavor, "
2114 "this option can be used to control if the compressed format for "
2115 "geometries (LINESTRINGs, POLYGONs) must be used." ),
2119 layerOptions.insert( u
"SRID"_s,
new QgsVectorFileWriter::StringOption(
2120 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
2121 "When this option isn't specified and that a SRS is associated with the "
2122 "layer, a search is made in the spatial_ref_sys to find a match for the "
2123 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
2124 "the spatial_ref_sys table. When the SRID option is specified, this "
2125 "search (and the eventual insertion of a new entry) will not be done: "
2126 "the specified SRID is used as such." ),
2130 layerOptions.insert( u
"COMPRESS_COLUMNS"_s,
new QgsVectorFileWriter::StringOption(
2131 QObject::tr(
"column_name1[,column_name2, …] A list of (String) columns that "
2132 "must be compressed with ZLib DEFLATE algorithm. This might be beneficial "
2133 "for databases that have big string blobs. However, use with care, since "
2134 "the value of such columns will be seen as compressed binary content with "
2135 "other SQLite utilities (or previous OGR versions). With OGR, when inserting, "
2136 "modifying or queryings compressed columns, compression/decompression is "
2137 "done transparently. However, such columns cannot be (easily) queried with "
2138 "an attribute filter or WHERE clause. Note: in table definition, such columns "
2139 "have the 'VARCHAR_deflate' declaration type." ),
2143 driverMetadata.insert( u
"SpatiaLite"_s,
2144 QgsVectorFileWriter::MetaData(
2146 QObject::tr(
"SpatiaLite" ),
2155 datasetOptions.clear();
2156 layerOptions.clear();
2158 datasetOptions.insert( u
"HEADER"_s,
new QgsVectorFileWriter::StringOption(
2159 QObject::tr(
"Override the header file used - in place of header.dxf." ),
2163 datasetOptions.insert( u
"TRAILER"_s,
new QgsVectorFileWriter::StringOption(
2164 QObject::tr(
"Override the trailer file used - in place of trailer.dxf." ),
2168#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,11,0)
2169 datasetOptions.insert( u
"INSUNITS"_s,
new QgsVectorFileWriter::SetOption(
2170 QObject::tr(
"Drawing units for the model space ($INSUNITS system variable)." ),
2173 << u
"HEADER_VALUE"_s
2180 << u
"US_SURVEY_FEET"_s,
2184 datasetOptions.insert( u
"MEASUREMENT"_s,
new QgsVectorFileWriter::SetOption(
2185 QObject::tr(
"Whether the current drawing uses imperial or metric hatch "
2186 "pattern and linetype ($MEASUREMENT system variable)." ),
2188 << u
"HEADER_VALUE"_s
2195 driverMetadata.insert( u
"DXF"_s,
2196 QgsVectorFileWriter::MetaData(
2198 QObject::tr(
"AutoCAD DXF" ),
2207 datasetOptions.clear();
2208 layerOptions.clear();
2210 datasetOptions.insert( u
"EXTENSION"_s,
new QgsVectorFileWriter::SetOption(
2211 QObject::tr(
"Indicates the GeoConcept export file extension. "
2212 "TXT was used by earlier releases of GeoConcept. GXT is currently used." ),
2219 datasetOptions.insert( u
"CONFIG"_s,
new QgsVectorFileWriter::StringOption(
2220 QObject::tr(
"Path to the GCT: the GCT file describes the GeoConcept types definitions: "
2221 "In this file, every line must start with //# followed by a keyword. "
2222 "Lines starting with // are comments." ),
2226 datasetOptions.insert( u
"FEATURETYPE"_s,
new QgsVectorFileWriter::StringOption(
2227 QObject::tr(
"Defines the feature to be created. The TYPE corresponds to one of the Name "
2228 "found in the GCT file for a type section. The SUBTYPE corresponds to one of "
2229 "the Name found in the GCT file for a sub-type section within the previous "
2234 driverMetadata.insert( u
"Geoconcept"_s,
2235 QgsVectorFileWriter::MetaData(
2237 QObject::tr(
"Geoconcept" ),
2246 datasetOptions.clear();
2247 layerOptions.clear();
2249#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,9,0)
2250 layerOptions.insert( u
"TARGET_ARCGIS_VERSION"_s,
new QgsVectorFileWriter::SetOption(
2251 QObject::tr(
"Selects which ArcGIS version this dataset should be compatible with. ALL is used by default and means any ArcGIS 10.x or ArcGIS Pro version. Using ARCGIS_PRO_3_2_OR_LATER is required to export 64-bit integer fields as such, otherwise they will be converted as Real fields. ARCGIS_PRO_3_2_OR_LATER also supports proper Date and Time field types." ),
2254 << u
"ARCGIS_PRO_3_2_OR_LATER"_s,
2259 layerOptions.insert( u
"FEATURE_DATASET"_s,
new QgsVectorFileWriter::StringOption(
2260 QObject::tr(
"When this option is set, the new layer will be created inside the named "
2261 "FeatureDataset folder. If the folder does not already exist, it will be created." ),
2265 layerOptions.insert( u
"LAYER_ALIAS"_s,
new QgsVectorFileWriter::StringOption(
2266 QObject::tr(
"Set layer name alias." ),
2270 layerOptions.insert( u
"GEOMETRY_NAME"_s,
new QgsVectorFileWriter::StringOption(
2271 QObject::tr(
"Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
2275 layerOptions.insert( u
"GEOMETRY_NULLABLE"_s,
new QgsVectorFileWriter::BoolOption(
2276 QObject::tr(
"Whether the values of the geometry column can be NULL. Can be set to NO so that geometry is required. Default to 'YES'." ),
2280 layerOptions.insert( u
"FID"_s,
new QgsVectorFileWriter::StringOption(
2281 QObject::tr(
"Name of the OID column to create. Defaults to 'OBJECTID'." ),
2297 layerOptions.insert( u
"COLUMN_TYPES"_s,
new QgsVectorFileWriter::StringOption(
2298 QObject::tr(
"A list of strings of format field_name=fgdb_field_type (separated by comma) to force the FileGDB column type of fields to be created." ),
2302 layerOptions.insert( u
"DOCUMENTATION"_s,
new QgsVectorFileWriter::StringOption(
2303 QObject::tr(
"XML documentation for the layer." ),
2306 layerOptions.insert( u
"CONFIGURATION_KEYWORD"_s,
new QgsVectorFileWriter::SetOption(
2307 QObject::tr(
"Customize how data is stored. By default text in UTF-8 and data up to 1TB." ),
2308 {u
"DEFAULTS"_s, u
"MAX_FILE_SIZE_4GB"_s, u
"MAX_FILE_SIZE_256TB"_s},
2313 layerOptions.insert( u
"CREATE_SHAPE_AREA_AND_LENGTH_FIELDS"_s,
new QgsVectorFileWriter::BoolOption(
2314 QObject::tr(
" Defaults to NO (through CreateLayer() API). When this option is set, a Shape_Area and Shape_Length special fields will be created for polygonal layers (Shape_Length only for linear layers). These fields will automatically be populated with the feature’s area or length whenever a new feature is added to the dataset or an existing feature is amended. When using ogr2ogr with a source layer that has Shape_Area/Shape_Length special fields, and this option is not explicitly specified, it will be automatically set, so that the resulting FileGeodatabase has those fields properly tagged." ),
2318 driverMetadata.insert( u
"OpenFileGDB"_s,
2319 QgsVectorFileWriter::MetaData(
2320 u
"ESRI File Geodatabase"_s,
2321 QObject::tr(
"ESRI File Geodatabase" ),
2330#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,11,0)
2332 datasetOptions.clear();
2333 layerOptions.clear();
2335 layerOptions.insert( u
"FEATURE_DATASET"_s,
new QgsVectorFileWriter::StringOption(
2336 QObject::tr(
"When this option is set, the new layer will be created inside the named "
2337 "FeatureDataset folder. If the folder does not already exist, it will be created." ),
2341 layerOptions.insert( u
"GEOMETRY_NAME"_s,
new QgsVectorFileWriter::StringOption(
2342 QObject::tr(
"Set name of geometry column in new layer. Defaults to 'SHAPE'." ),
2346 layerOptions.insert( u
"FID"_s,
new QgsVectorFileWriter::StringOption(
2347 QObject::tr(
"Name of the OID column to create. Defaults to 'OBJECTID'." ),
2351 driverMetadata.insert( u
"FileGDB"_s,
2352 QgsVectorFileWriter::MetaData(
2354 QObject::tr(
"ESRI FileGDB" ),
2365 datasetOptions.clear();
2366 layerOptions.clear();
2368 layerOptions.insert( u
"OGR_XLSX_FIELD_TYPES"_s,
new QgsVectorFileWriter::SetOption(
2369 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2370 "to STRING, all fields will be of String type." ),
2378 layerOptions.insert( u
"OGR_XLSX_HEADERS"_s,
new QgsVectorFileWriter::SetOption(
2379 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2380 "if the first line might be the name of columns. If set to FORCE, the driver "
2381 "will consider the first line as the header line. If set to "
2382 "DISABLE, it will be considered as the first feature. Otherwise "
2383 "auto-detection will occur." ),
2392 driverMetadata.insert( u
"XLSX"_s,
2393 QgsVectorFileWriter::MetaData(
2394 u
"MS Office Open XML spreadsheet"_s,
2395 QObject::tr(
"MS Office Open XML spreadsheet [XLSX]" ),
2405 datasetOptions.clear();
2406 layerOptions.clear();
2408 layerOptions.insert( u
"OGR_ODS_FIELD_TYPES"_s,
new QgsVectorFileWriter::SetOption(
2409 QObject::tr(
"By default, the driver will try to detect the data type of fields. If set "
2410 "to STRING, all fields will be of String type." ),
2418 layerOptions.insert( u
"OGR_ODS_HEADERS"_s,
new QgsVectorFileWriter::SetOption(
2419 QObject::tr(
"By default, the driver will read the first lines of each sheet to detect "
2420 "if the first line might be the name of columns. If set to FORCE, the driver "
2421 "will consider the first line as the header line. If set to "
2422 "DISABLE, it will be considered as the first feature. Otherwise "
2423 "auto-detection will occur." ),
2432 driverMetadata.insert( u
"ODS"_s,
2433 QgsVectorFileWriter::MetaData(
2434 u
"Open Document Spreadsheet"_s,
2435 QObject::tr(
"Open Document Spreadsheet [ODS]" ),
2445 datasetOptions.clear();
2446 layerOptions.clear();
2448 QStringList compressionMethods;
2449 const QStringList searchCompressions =
2457 if ( GDALDriverH hParquetDrv = GDALGetDriverByName(
"PARQUET" ) )
2459 if (
const char *xml = GDALGetMetadataItem( hParquetDrv, GDAL_DS_LAYER_CREATIONOPTIONLIST,
nullptr ) )
2461 for (
const QString &comp : searchCompressions )
2463 QRegularExpression re(
"<Value[^>]*>\\s*" + comp +
"\\s*</Value>" );
2464 if ( re.match( QString::fromUtf8( xml ) ).hasMatch() )
2466 compressionMethods << comp;
2472 layerOptions.insert( u
"COMPRESSION"_s,
new QgsVectorFileWriter::SetOption(
2473 QObject::tr(
"Compression method." ),
2479#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,12,0)
2480 layerOptions.insert( u
"COMPRESSION_LEVEL"_s,
new QgsVectorFileWriter::IntOption(
2481 QObject::tr(
"Compression level." ),
2486#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,9,0)
2487 layerOptions.insert( u
"SORT_BY_BBOX"_s,
new QgsVectorFileWriter::BoolOption(
2488 QObject::tr(
"Whether to sort by spatial location. Enables faster spatial filtering on reading." ),
2492 layerOptions.insert( u
"WRITE_COVERING_BBOX"_s,
new QgsVectorFileWriter::BoolOption(
2493 QObject::tr(
"Whether to write the bounding box of geometries into columns." ),
2498 layerOptions.insert( u
"GEOMETRY_ENCODING"_s,
new QgsVectorFileWriter::SetOption(
2499 QObject::tr(
"Geometry encoding." ),
2508 layerOptions.insert( u
"ROW_GROUP_SIZE"_s,
new QgsVectorFileWriter::IntOption(
2509 QObject::tr(
"Maximum number of rows per group." ),
2513 layerOptions.insert( u
"FID"_s,
new QgsVectorFileWriter::StringOption(
2514 QObject::tr(
"Name for the feature identifier column" ),
2518 layerOptions.insert( u
"GEOMETRY_NAME"_s,
new QgsVectorFileWriter::StringOption(
2519 QObject::tr(
"Name for the geometry column" ),
2523 layerOptions.insert( u
"EDGES"_s,
new QgsVectorFileWriter::SetOption(
2524 QObject::tr(
"Name of the coordinate system for the edges." ),
2532 driverMetadata.insert( u
"Parquet"_s,
2533 QgsVectorFileWriter::MetaData(
2535 QObject::tr(
"(Geo)Parquet" ),
2545 datasetOptions.clear();
2546 layerOptions.clear();
2548 datasetOptions.insert( u
"LINEFORMAT"_s,
new QgsVectorFileWriter::SetOption(
2549 QObject::tr(
"Line termination character sequence." ),
2558 layerOptions.insert( u
"GEOM_TYPE"_s,
new QgsVectorFileWriter::SetOption(
2559 QObject::tr(
"Format of geometry columns." ),
2567 layerOptions.insert( u
"LAUNDER"_s,
new QgsVectorFileWriter::BoolOption(
2568 QObject::tr(
"Controls whether layer and field names will be laundered for easier use. "
2569 "Laundered names will be converted to lower case and some special "
2570 "characters(' - #) will be changed to underscores." ),
2574 layerOptions.insert( u
"GEOMETRY_NAME"_s,
new QgsVectorFileWriter::StringOption(
2575 QObject::tr(
"Name for the geometry column. Defaults to wkb_geometry "
2576 "for GEOM_TYPE=geometry or the_geog for GEOM_TYPE=geography" ) ) );
2578 layerOptions.insert( u
"SCHEMA"_s,
new QgsVectorFileWriter::StringOption(
2579 QObject::tr(
"Name of schema into which to create the new table" ) ) );
2581 layerOptions.insert( u
"CREATE_SCHEMA"_s,
new QgsVectorFileWriter::BoolOption(
2582 QObject::tr(
"Whether to explicitly emit the CREATE SCHEMA statement to create the specified schema." ),
2586 layerOptions.insert( u
"CREATE_TABLE"_s,
new QgsVectorFileWriter::BoolOption(
2587 QObject::tr(
"Whether to explicitly recreate the table if necessary." ),
2591 layerOptions.insert( u
"DROP_TABLE"_s,
new QgsVectorFileWriter::SetOption(
2592 QObject::tr(
"Whether to explicitly destroy tables before recreating them." ),
2601 layerOptions.insert( u
"SRID"_s,
new QgsVectorFileWriter::StringOption(
2602 QObject::tr(
"Used to force the SRID number of the SRS associated with the layer. "
2603 "When this option isn't specified and that a SRS is associated with the "
2604 "layer, a search is made in the spatial_ref_sys to find a match for the "
2605 "SRS, and, if there is no match, a new entry is inserted for the SRS in "
2606 "the spatial_ref_sys table. When the SRID option is specified, this "
2607 "search (and the eventual insertion of a new entry) will not be done: "
2608 "the specified SRID is used as such." ),
2612 layerOptions.insert( u
"POSTGIS_VERSION"_s,
new QgsVectorFileWriter::StringOption(
2613 QObject::tr(
"Can be set to 2.0 or 2.2 for PostGIS 2.0/2.2 compatibility. "
2614 "Important to set it correctly if using non-linear geometry types" ),
2618 driverMetadata.insert( u
"PGDUMP"_s,
2619 QgsVectorFileWriter::MetaData(
2620 u
"PostgreSQL SQL dump"_s,
2621 QObject::tr(
"PostgreSQL SQL dump" ),
2632 QgsVectorFileWriterMetadataContainer(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2633 QgsVectorFileWriterMetadataContainer &operator=(
const QgsVectorFileWriterMetadataContainer &other ) =
delete;
2634 ~QgsVectorFileWriterMetadataContainer()
2636 for (
auto it = driverMetadata.constBegin(); it != driverMetadata.constEnd(); ++it )
2638 for (
auto optionIt = it.value().driverOptions.constBegin(); optionIt != it.value().driverOptions.constEnd(); ++optionIt )
2639 delete optionIt.value();
2640 for (
auto optionIt = it.value().layerOptions.constBegin(); optionIt != it.value().layerOptions.constEnd(); ++optionIt )
2641 delete optionIt.value();
2645 QMap<QString, QgsVectorFileWriter::MetaData> driverMetadata;
2652 static QgsVectorFileWriterMetadataContainer sDriverMetadata;
2653 QMap<QString, MetaData>::ConstIterator it = sDriverMetadata.driverMetadata.constBegin();
2655 for ( ; it != sDriverMetadata.driverMetadata.constEnd(); ++it )
2657 if ( it.key() ==
"PGDUMP"_L1 &&
2658 driverName !=
"PGDUMP"_L1 &&
2659 driverName !=
"PostgreSQL SQL dump"_L1 )
2664 if ( it.key().startsWith( driverName ) || it.value().longName.startsWith( driverName ) )
2679 return QStringList();
2688 return QStringList();
2695 OGRwkbGeometryType ogrType =
static_cast<OGRwkbGeometryType
>( type );
2726 return mCapabilities;
2736 QgsFeatureList::iterator fIt = features.begin();
2738 for ( ; fIt != features.end(); ++fIt )
2760 mRenderContext.expressionContext().setFeature( feature );
2763 QString styleString;
2764 QString currentStyle;
2766 QgsSymbolList::const_iterator symbolIt = symbols.constBegin();
2767 for ( ; symbolIt != symbols.constEnd(); ++symbolIt )
2769 int nSymbolLayers = ( *symbolIt )->symbolLayerCount();
2770 for (
int i = 0; i < nSymbolLayers; ++i )
2773 QMap< QgsSymbolLayer *, QString >::const_iterator it =
mSymbolLayerTable.find( ( *symbolIt )->symbolLayer( i ) );
2779 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2780 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), outputUnit );
2782 currentStyle = ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf );
2788 if ( symbolIt != symbols.constBegin() || i != 0 )
2790 styleString.append(
';' );
2792 styleString.append( currentStyle );
2797 OGR_F_SetStyleString( poFeature.get(), currentStyle.toLocal8Bit().constData() );
2798 if ( !writeFeature(
mLayer, poFeature.get() ) )
2810 OGR_F_SetStyleString( poFeature.get(), styleString.toLocal8Bit().constData() );
2818 if ( !writeFeature(
mLayer, poFeature.get() ) )
2842 int fldIdx = it.key();
2843 int ogrField = it.value();
2845 QVariant attrValue = feature.
attribute( fldIdx );
2850 OGR_F_UnsetField( poFeature.get(), ogrField );
2863 OGR_F_SetFieldNull( poFeature.get(), ogrField );
2878 mErrorMessage = QObject::tr(
"Error converting value (%1) for attribute field %2: %3" )
2879 .arg( feature.
attribute( fldIdx ).toString(),
2886 switch ( field.
type() )
2888 case QMetaType::Type::Int:
2889 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2891 case QMetaType::Type::LongLong:
2892 OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
2894 case QMetaType::Type::Bool:
2895 OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
2897 case QMetaType::Type::QString:
2898 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2900 case QMetaType::Type::Double:
2901 OGR_F_SetFieldDouble( poFeature.get(), ogrField, attrValue.toDouble() );
2903 case QMetaType::Type::QDate:
2904 OGR_F_SetFieldDateTime( poFeature.get(), ogrField,
2905 attrValue.toDate().year(),
2906 attrValue.toDate().month(),
2907 attrValue.toDate().day(),
2910 case QMetaType::Type::QDateTime:
2913 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toDateTime().toString( u
"yyyy/MM/dd hh:mm:ss.zzz"_s ) ).constData() );
2917 const QDateTime dt = attrValue.toDateTime();
2918 const QDate date = dt.date();
2919 const QTime time = dt.time();
2920 OGR_F_SetFieldDateTimeEx( poFeature.get(), ogrField,
2926 static_cast<float>( time.second() +
static_cast< double >( time.msec() ) / 1000 ),
2930 case QMetaType::Type::QTime:
2933 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( attrValue.toString() ).constData() );
2937 const QTime time = attrValue.toTime();
2938 OGR_F_SetFieldDateTimeEx( poFeature.get(), ogrField,
2942 static_cast<float>( time.second() +
static_cast< double >( time.msec() ) / 1000 ),
2947 case QMetaType::Type::QByteArray:
2949 const QByteArray ba = attrValue.toByteArray();
2950 OGR_F_SetFieldBinary( poFeature.get(), ogrField, ba.size(),
const_cast< GByte *
>(
reinterpret_cast< const GByte *
>( ba.data() ) ) );
2954 case QMetaType::Type::UnknownType:
2957 case QMetaType::Type::QStringList:
2962 const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
2964 if ( !doc.isNull() )
2966 jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).constData() );
2968 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( jsonString.constData() ) );
2972 QStringList list = attrValue.toStringList();
2973 if ( mSupportedListSubTypes.contains( QMetaType::Type::QString ) )
2975 int count = list.count();
2976 char **lst =
new char *[count + 1];
2980 for (
const QString &
string : list )
2982 lst[pos] = CPLStrdup(
mCodec->fromUnicode(
string ).data() );
2986 lst[count] =
nullptr;
2987 OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
2992 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( list.join(
',' ) ).constData() );
2997 case QMetaType::Type::QVariantList:
3001 const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
3003 if ( !doc.isNull() )
3005 jsonString = QString::fromUtf8( doc.toJson( QJsonDocument::Compact ).data() );
3007 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( jsonString.constData() ) );
3012 if ( field.
subType() == QMetaType::Type::QString )
3014 QStringList list = attrValue.toStringList();
3015 if ( mSupportedListSubTypes.contains( QMetaType::Type::QString ) )
3017 int count = list.count();
3018 char **lst =
new char *[count + 1];
3022 for (
const QString &
string : list )
3024 lst[pos] = CPLStrdup(
mCodec->fromUnicode(
string ).data() );
3028 lst[count] =
nullptr;
3029 OGR_F_SetFieldStringList( poFeature.get(), ogrField, lst );
3034 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( list.join(
',' ) ).constData() );
3038 else if ( field.
subType() == QMetaType::Type::Int )
3040 const QVariantList list = attrValue.toList();
3041 if ( mSupportedListSubTypes.contains( QMetaType::Type::Int ) )
3043 const int count = list.count();
3044 int *lst =
new int[count];
3048 for (
const QVariant &value : list )
3050 lst[pos] = value.toInt();
3054 OGR_F_SetFieldIntegerList( poFeature.get(), ogrField, count, lst );
3059 QStringList strings;
3060 strings.reserve( list.size() );
3061 for (
const QVariant &value : list )
3063 strings << QString::number( value.toInt() );
3065 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
3069 else if ( field.
subType() == QMetaType::Type::Double )
3071 const QVariantList list = attrValue.toList();
3072 if ( mSupportedListSubTypes.contains( QMetaType::Type::Double ) )
3074 const int count = list.count();
3075 double *lst =
new double[count];
3079 for (
const QVariant &value : list )
3081 lst[pos] = value.toDouble();
3085 OGR_F_SetFieldDoubleList( poFeature.get(), ogrField, count, lst );
3090 QStringList strings;
3091 strings.reserve( list.size() );
3092 for (
const QVariant &value : list )
3094 strings << QString::number( value.toDouble() );
3096 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
3100 else if ( field.
subType() == QMetaType::Type::LongLong )
3102 const QVariantList list = attrValue.toList();
3103 if ( mSupportedListSubTypes.contains( QMetaType::Type::LongLong ) )
3105 const int count = list.count();
3106 long long *lst =
new long long[count];
3110 for (
const QVariant &value : list )
3112 lst[pos] = value.toLongLong();
3116 OGR_F_SetFieldInteger64List( poFeature.get(), ogrField, count, lst );
3121 QStringList strings;
3122 strings.reserve( list.size() );
3123 for (
const QVariant &value : list )
3125 strings << QString::number( value.toLongLong() );
3127 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( strings.join(
',' ) ).constData() );
3134 case QMetaType::Type::QVariantMap:
3137 const char *pszDataSubTypes = GDALGetMetadataItem( OGRGetDriverByName(
mOgrDriverName.toLocal8Bit().constData() ), GDAL_DMD_CREATIONFIELDDATASUBTYPES,
nullptr );
3138 if ( pszDataSubTypes && strstr( pszDataSubTypes,
"JSON" ) )
3140 const QJsonDocument doc = QJsonDocument::fromVariant( attrValue );
3142 if ( !doc.isNull() )
3144 const QByteArray json { doc.toJson( QJsonDocument::Compact ) };
3145 jsonString = QString::fromUtf8( json.data() );
3147 OGR_F_SetFieldString( poFeature.get(), ogrField,
mCodec->fromUnicode( jsonString.constData() ) );
3157 mErrorMessage = QObject::tr(
"Invalid variant type for field %1[%2]: received %3 with type %4" )
3158 .arg(
mFields.at( fldIdx ).name() )
3160 .arg( attrValue.typeName(),
3161 attrValue.toString() );
3173 QgsGeometry geom = feature.
geometry();
3174 if ( mCoordinateTransform )
3179 geom.
transform( *mCoordinateTransform );
3181 catch ( QgsCsException & )
3197 OGRGeometryH mGeom2 =
nullptr;
3226 geom.
get()->
addZValue( std::numeric_limits<double>::quiet_NaN() );
3233 geom.
get()->
addMValue( std::numeric_limits<double>::quiet_NaN() );
3253 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
3254 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
3264 QByteArray wkb( geom.
asWkb( wkbFlags ) );
3265 OGRErr err = OGR_G_ImportFromWkb( mGeom2,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
3266 if ( err != OGRERR_NONE )
3268 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
3269 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
3276 OGR_F_SetGeometryDirectly( poFeature.get(), mGeom2 );
3284 QByteArray wkb( geom.
asWkb( wkbFlags ) );
3286 OGRErr err = OGR_G_ImportFromWkb( ogrGeom,
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( wkb.constData() ) ), wkb.length() );
3287 if ( err != OGRERR_NONE )
3289 mErrorMessage = QObject::tr(
"Feature geometry not imported (OGR error: %1)" )
3290 .arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
3297 OGR_F_SetGeometryDirectly( poFeature.get(), ogrGeom );
3312 for (
int i = 0; i < attributes.size(); i++ )
3314 if ( omap.find( i ) != omap.end() )
3319bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
3321 if ( OGR_L_CreateFeature( layer, feature ) != OGRERR_NONE )
3323 mErrorMessage = QObject::tr(
"Feature creation error (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
3333 if ( mUsingTransaction )
3335 if ( OGRERR_NONE != OGR_L_CommitTransaction(
mLayer ) )
3337 QgsDebugError( u
"Error while committing transaction on OGRLayer."_s );
3350 const QString &fileName,
3351 const QString &fileEncoding,
3353 const QString &driverName,
3356 const QStringList &datasourceOptions,
3357 const QStringList &layerOptions,
3358 bool skipAttributeCreation,
3359 QString *newFilename,
3402 const QString &fileName,
3403 const QString &fileEncoding,
3405 const QString &driverName,
3408 const QStringList &datasourceOptions,
3409 const QStringList &layerOptions,
3410 bool skipAttributeCreation,
3411 QString *newFilename,
3452 if ( !layer || !layer->
isValid() )
3459 details.sourceCrs = layer->
crs();
3460 details.sourceWkbType = layer->
wkbType();
3461 details.sourceFields = layer->
fields();
3470 if ( details.storageType ==
"ESRI Shapefile"_L1 )
3478 details.geometryTypeScanIterator = layer->
getFeatures( req );
3485 details.shallTransform =
false;
3490 details.shallTransform =
true;
3495 details.outputCrs = details.sourceCrs;
3498 details.destWkbType = details.sourceWkbType;
3512 details.attributes.clear();
3513 else if ( details.attributes.isEmpty() )
3516 for (
int idx : allAttributes )
3518 QgsField fld = details.sourceFields.
at( idx );
3519 if ( details.providerType ==
"oracle"_L1 && fld.
typeName().contains(
"SDO_GEOMETRY"_L1 ) )
3521 details.attributes.append( idx );
3525 if ( !details.attributes.isEmpty() )
3527 for (
int attrIdx : std::as_const( details.attributes ) )
3529 if ( details.sourceFields.
exists( attrIdx ) )
3531 QgsField field = details.sourceFields.
at( attrIdx );
3533 details.outputFields.
append( field );
3537 QgsDebugError( u
"No such source field with index '%1' available."_s.arg( attrIdx ) );
3544 if ( details.providerType ==
"spatialite"_L1 )
3546 for (
int i = 0; i < details.outputFields.
size(); i++ )
3548 if ( details.outputFields.
at( i ).
type() == QMetaType::Type::LongLong )
3553 if ( std::max( std::llabs( min.toLongLong() ), std::llabs( max.toLongLong() ) ) < std::numeric_limits<int>::max() )
3555 details.outputFields[i].setType( QMetaType::Type::Int );
3563 addRendererAttributes( details.renderer.get(), details.renderContext, details.sourceFields, details.attributes );
3565 QgsFeatureRequest req;
3573 bool useFilterRect =
true;
3574 if ( details.shallTransform )
3579 QgsCoordinateTransform extentTransform = options.
ct;
3583 catch ( QgsCsException & )
3585 useFilterRect =
false;
3588 if ( useFilterRect )
3594 details.filterRectEngine->prepareGeometry();
3596 details.sourceFeatureIterator = layer->
getFeatures( req );
3615 int lastProgressReport = 0;
3616 long long total = details.featureCount;
3619 if ( details.providerType ==
"ogr"_L1 && !details.dataSourceUri.isEmpty() )
3621 QString srcFileName( details.providerUriParams.value( u
"path"_s ).toString() );
3622 if ( QFile::exists( srcFileName ) && QFileInfo( fileName ).canonicalFilePath() == QFileInfo( srcFileName ).canonicalFilePath() )
3625 QgsDataSourceUri uri( details.dataSourceUri );
3629 options.
layerName != details.providerUriParams.value( u
"layerName"_s ) ) )
3632 *
errorMessage = QObject::tr(
"Cannot overwrite an OGR layer in place" );
3640 QgsFeatureIterator fit = details.geometryTypeScanIterator;
3652 int newProgress =
static_cast<int>( ( 5.0 * scanned ) / total );
3653 if ( newProgress != lastProgressReport )
3655 lastProgressReport = newProgress;
3670 QString tempNewFilename;
3671 QString tempNewLayer;
3673 QgsVectorFileWriter::SaveVectorOptions newOptions = options;
3679 std::unique_ptr< QgsVectorFileWriter > writer(
create( fileName, details.outputFields, destWkbType, details.outputCrs, transformContext, newOptions, sinkFlags, &tempNewFilename, &tempNewLayer ) );
3683 *newFilename = tempNewFilename;
3686 *newLayer = tempNewLayer;
3715 switch ( writer->symbologyExport() )
3719 QgsFeatureRenderer *r = details.renderer.get();
3733 int n = 0, errors = 0;
3742 writer->startRender( details.renderer.get(), details.sourceFields );
3744 writer->resetMap( details.attributes );
3746 writer->mFields = details.sourceFields;
3750 int initialProgress = lastProgressReport;
3751 while ( details.sourceFeatureIterator.nextFeature( fet ) )
3762 int newProgress =
static_cast<int>( initialProgress + ( ( 100.0 - initialProgress ) * saved ) / total );
3763 if ( newProgress < 100 && newProgress != lastProgressReport )
3765 lastProgressReport = newProgress;
3770 if ( details.shallTransform )
3781 catch ( QgsCsException &e )
3783 const QString msg = QObject::tr(
"Failed to transform feature with ID '%1'. Writing stopped. (Exception: %2)" )
3784 .arg( fet.
id() ).arg( e.
what() );
3801 if ( !writer->addFeatureWithStyle( fet, writer->mRenderer.get(), mapUnits ) )
3808 *
errorMessage = QObject::tr(
"Feature write errors:" );
3814 if ( errors > 1000 )
3818 *
errorMessage += QObject::tr(
"Stopping after %n error(s)",
nullptr, errors );
3828 writer->stopRender();
3832 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( n - errors ).arg( n );
3837 bool metadataFailure =
false;
3842 {u
"path"_s, tempNewFilename },
3843 {u
"layerName"_s, tempNewLayer }
3857 metadataFailure =
true;
3860 catch ( QgsNotSupportedException &e )
3868 metadataFailure =
true;
3876 const QString &fileName,
3878 QString *newFilename,
3882 QgsVectorFileWriter::PreparedWriterDetails details;
3883 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3891 const QString &fileName,
3894 QString *newFilename,
3898 QgsVectorFileWriter::PreparedWriterDetails details;
3899 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3908 QgsVectorFileWriter::PreparedWriterDetails details;
3909 WriterError err = prepareWriteAsVectorFormat( layer, options, details );
3918 QFileInfo fi( fileName );
3919 QDir dir = fi.dir();
3922 for (
const char *suffix : {
".shp",
".shx",
".dbf",
".prj",
".qix",
".qpj",
".cpg",
".sbn",
".sbx",
".idm",
".ind" } )
3924 filter << fi.completeBaseName() + suffix;
3928 const auto constEntryList = dir.entryList( filter );
3929 for (
const QString &file : constEntryList )
3931 QFile f( dir.canonicalPath() +
'/' + file );
3934 QgsDebugError( u
"Removing file %1 failed: %2"_s.arg( file, f.errorString() ) );
3950 QStringList driverNames;
3953 for (
int i = 0; i < GDALGetDriverCount(); ++i )
3955 GDALDriverH
driver = GDALGetDriver( i );
3962 const QString driverExtensions = GDALGetMetadataItem(
driver, GDAL_DMD_EXTENSIONS,
"" );
3963 if ( driverExtensions.isEmpty() )
3966 const QSet< QString > splitExtensions = qgis::listToSet( driverExtensions.split(
' ', Qt::SkipEmptyParts ) );
3967 if ( splitExtensions.intersects( multiLayerExtensions ) )
3969 driverNames << GDALGetDescription(
driver );
3977 static QReadWriteLock sFilterLock;
3978 static QMap< VectorFormatOptions, QList< QgsVectorFileWriter::FilterFormatDetails > > sFilters;
3982 const auto it = sFilters.constFind( options );
3983 if ( it != sFilters.constEnd() )
3987 QList< QgsVectorFileWriter::FilterFormatDetails > results;
3990 int const drvCount = OGRGetDriverCount();
3994 for (
int i = 0; i < drvCount; ++i )
3996 OGRSFDriverH drv = OGRGetDriver( i );
3999 const QString drvName = GDALGetDescription( drv );
4003 if ( !multiLayerDrivers.contains( drvName ) )
4007 GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
4008 bool nonSpatialFormat =
false;
4011 nonSpatialFormat = GDALGetMetadataItem( gdalDriver, GDAL_DCAP_NONSPATIAL,
nullptr );
4014 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
4019 if ( nonSpatialFormat )
4024 if ( filterString.isEmpty() )
4031 globs = metadata.
glob.toLower().split(
' ' );
4037 details.
globs = globs;
4046 if ( options & SortRecommended )
4048 if ( a.driverName ==
"GPKG"_L1 )
4050 else if ( b.driverName ==
"GPKG"_L1 )
4052 else if ( a.driverName ==
"ESRI Shapefile"_L1 )
4054 else if ( b.driverName ==
"ESRI Shapefile"_L1 )
4061 sFilters.insert( options, results );
4068 QSet< QString > extensions;
4070 const thread_local QRegularExpression rx( u
"\\*\\.(.*)$"_s );
4074 for (
const QString &glob : format.globs )
4076 const QRegularExpressionMatch match = rx.match( glob );
4077 if ( !match.hasMatch() )
4080 const QString matched = match.captured( 1 );
4081 extensions.insert( matched );
4085 QStringList extensionList( extensions.constBegin(), extensions.constEnd() );
4087 std::sort( extensionList.begin(), extensionList.end(), [options](
const QString & a,
const QString & b ) ->
bool
4089 if ( options & SortRecommended )
4091 if ( a ==
"gpkg"_L1 )
4093 else if ( b ==
"gpkg"_L1 )
4095 else if ( a ==
"shp"_L1 )
4097 else if ( b ==
"shp"_L1 )
4101 return a.toLower().localeAwareCompare( b.toLower() ) < 0;
4104 return extensionList;
4109 QList< QgsVectorFileWriter::DriverDetails > results;
4112 const int drvCount = OGRGetDriverCount();
4116 QStringList writableDrivers;
4117 for (
int i = 0; i < drvCount; ++i )
4119 OGRSFDriverH drv = OGRGetDriver( i );
4122 const QString drvName = GDALGetDescription( drv );
4126 if ( !multiLayerDrivers.contains( drvName ) )
4134 if ( drvName ==
"ODS"_L1 || drvName ==
"XLSX"_L1 || drvName ==
"XLS"_L1 )
4138 if ( drvName ==
"ESRI Shapefile"_L1 )
4140 writableDrivers << u
"DBF file"_s;
4142 if ( OGR_Dr_TestCapability( drv,
"CreateDataSource" ) != 0 )
4145 if ( drvName ==
"MapInfo File"_L1 )
4147 writableDrivers << u
"MapInfo MIF"_s;
4149 else if ( drvName ==
"SQLite"_L1 )
4156 QString option = u
"SPATIALITE=YES"_s;
4157 char *options[2] = { CPLStrdup( option.toLocal8Bit().constData() ),
nullptr };
4158 OGRSFDriverH poDriver;
4160 poDriver = OGRGetDriverByName( drvName.toLocal8Bit().constData() );
4166 writableDrivers << u
"SpatiaLite"_s;
4167 OGR_Dr_DeleteDataSource( poDriver, u
"/vsimem/spatialitetest.sqlite"_s.toUtf8().constData() );
4170 CPLFree( options[0] );
4172 writableDrivers << drvName;
4177 results.reserve( writableDrivers.count() );
4178 for (
const QString &drvName : std::as_const( writableDrivers ) )
4192 if ( options & SortRecommended )
4194 if ( a.driverName ==
"GPKG"_L1 )
4196 else if ( b.driverName ==
"GPKG"_L1 )
4198 else if ( a.driverName ==
"ESRI Shapefile"_L1 )
4200 else if ( b.driverName ==
"ESRI Shapefile"_L1 )
4204 return a.
longName.toLower().localeAwareCompare( b.
longName.toLower() ) < 0;
4211 QString ext = extension.trimmed();
4212 if ( ext.isEmpty() )
4215 if ( ext.startsWith(
'.' ) )
4219 int const drvCount = GDALGetDriverCount();
4221 for (
int i = 0; i < drvCount; ++i )
4223 GDALDriverH drv = GDALGetDriver( i );
4229 QString drvName = GDALGetDriverShortName( drv );
4230 QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
4232 const auto constDriverExtensions = driverExtensions;
4233 for (
const QString &
driver : constDriverExtensions )
4235 if (
driver.compare( ext, Qt::CaseInsensitive ) == 0 )
4246 QString filterString;
4250 if ( !filterString.isEmpty() )
4251 filterString +=
";;"_L1;
4253 filterString += details.filterString;
4255 return filterString;
4264 return u
"%1 (%2 %3)"_s.arg( metadata.
trLongName,
4265 metadata.
glob.toLower(),
4266 metadata.
glob.toUpper() );
4271 if ( codecName ==
"System"_L1 )
4274 const thread_local QRegularExpression re( QRegularExpression::anchoredPattern( QString(
"(CP|windows-|ISO[ -])(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
4275 const QRegularExpressionMatch match = re.match( codecName );
4276 if ( match.hasMatch() )
4278 QString
c = match.captured( 2 ).remove(
'-' );
4280 ( void )
c.toInt( &isNumber );
4294 QgsFeatureRenderer *renderer = vl->
renderer();
4308 OGRStyleTableH ogrStyleTable = OGR_STBL_Create();
4309 OGRStyleMgrH styleManager = OGR_SM_Create( ogrStyleTable );
4312 int nTotalLevels = 0;
4314 QgsSymbolList::iterator symbolIt = symbolList.begin();
4315 for ( ; symbolIt != symbolList.end(); ++symbolIt )
4317 double mmsf = mmScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
4318 double musf = mapUnitScaleFactor(
mSymbologyScale, ( *symbolIt )->outputUnit(), mapUnits );
4320 int nLevels = ( *symbolIt )->symbolLayerCount();
4321 for (
int i = 0; i < nLevels; ++i )
4323 mSymbolLayerTable.insert( ( *symbolIt )->symbolLayer( i ), QString::number( nTotalLevels ) );
4324 OGR_SM_AddStyle( styleManager, QString::number( nTotalLevels ).toLocal8Bit(),
4325 ( *symbolIt )->symbolLayer( i )->ogrFeatureStyle( mmsf, musf ).toLocal8Bit() );
4329 OGR_DS_SetStyleTableDirectly( ds, ogrStyleTable );
4333 const QgsCoordinateTransform &ct, QString *
errorMessage )
4335 if ( !details.renderer )
4338 mRenderContext.expressionContext() = details.expressionContext;
4340 QHash< QgsSymbol *, QList<QgsFeature> > features;
4349 startRender( details.renderer.get(), details.sourceFields );
4353 QgsSymbol *featureSymbol =
nullptr;
4367 catch ( QgsCsException &e )
4369 QString msg = QObject::tr(
"Failed to transform, writing stopped. (Exception: %1)" )
4378 mRenderContext.expressionContext().setFeature( fet );
4380 featureSymbol = mRenderer->symbolForFeature( fet, mRenderContext );
4381 if ( !featureSymbol )
4386 QHash< QgsSymbol *, QList<QgsFeature> >::iterator it = features.find( featureSymbol );
4387 if ( it == features.end() )
4389 it = features.insert( featureSymbol, QList<QgsFeature>() );
4391 it.value().append( fet );
4396 QgsSymbolList symbols = mRenderer->symbols( mRenderContext );
4397 for (
int i = 0; i < symbols.count(); i++ )
4399 QgsSymbol *sym = symbols[i];
4403 if ( level < 0 || level >= 1000 )
4405 QgsSymbolLevelItem item( sym, j );
4406 while ( level >= levels.count() )
4408 levels[level].append( item );
4413 int nTotalFeatures = 0;
4416 for (
int l = 0; l < levels.count(); l++ )
4419 for (
int i = 0; i < level.count(); i++ )
4421 QgsSymbolLevelItem &item = level[i];
4422 QHash< QgsSymbol *, QList<QgsFeature> >::iterator levelIt = features.find( item.
symbol() );
4423 if ( levelIt == features.end() )
4429 double mmsf = mmScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
4430 double musf = mapUnitScaleFactor(
mSymbologyScale, levelIt.key()->outputUnit(), mapUnits );
4432 int llayer = item.
layer();
4433 QList<QgsFeature> &featureList = levelIt.value();
4434 QList<QgsFeature>::iterator featureIt = featureList.begin();
4435 for ( ; featureIt != featureList.end(); ++featureIt )
4445 QString styleString = levelIt.key()->symbolLayer( llayer )->ogrFeatureStyle( mmsf, musf );
4446 if ( !styleString.isEmpty() )
4448 OGR_F_SetStyleString( ogrFeature.get(), styleString.toLocal8Bit().constData() );
4449 if ( !writeFeature(
mLayer, ogrFeature.get() ) )
4462 *
errorMessage += QObject::tr(
"\nOnly %1 of %2 features written." ).arg( nTotalFeatures - nErrors ).arg( nTotalFeatures );
4479 return 1000 / scale;
4496 return scale / 1000;
4502void QgsVectorFileWriter::startRender( QgsFeatureRenderer *sourceRenderer,
const QgsFields &fields )
4504 mRenderer = createSymbologyRenderer( sourceRenderer );
4510 mRenderer->startRender( mRenderContext, fields );
4513void QgsVectorFileWriter::stopRender()
4520 mRenderer->stopRender( mRenderContext );
4523std::unique_ptr<QgsFeatureRenderer> QgsVectorFileWriter::createSymbologyRenderer( QgsFeatureRenderer *sourceRenderer )
const
4536 if ( !sourceRenderer )
4541 return std::unique_ptr< QgsFeatureRenderer >( sourceRenderer->
clone() );
4544void QgsVectorFileWriter::addRendererAttributes( QgsFeatureRenderer *renderer, QgsRenderContext &context,
const QgsFields &fields,
QgsAttributeList &attList )
4548 const QSet<QString> rendererAttributes = renderer->
usedAttributes( context );
4549 for (
const QString &attr : rendererAttributes )
4554 attList.append( index );
4560QStringList QgsVectorFileWriter::concatenateOptions(
const QMap<QString, QgsVectorFileWriter::Option *> &options )
4563 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
4565 for ( it = options.constBegin(); it != options.constEnd(); ++it )
4567 QgsVectorFileWriter::Option *option = it.value();
4568 switch ( option->
type )
4572 QgsVectorFileWriter::IntOption *opt =
dynamic_cast<QgsVectorFileWriter::IntOption *
>( option );
4575 list.append( u
"%1=%2"_s.arg( it.key() ).arg( opt->
defaultValue ) );
4582 QgsVectorFileWriter::SetOption *opt =
dynamic_cast<QgsVectorFileWriter::SetOption *
>( option );
4585 list.append( u
"%1=%2"_s.arg( it.key(), opt->
defaultValue ) );
4592 QgsVectorFileWriter::StringOption *opt =
dynamic_cast<QgsVectorFileWriter::StringOption *
>( option );
4595 list.append( u
"%1=%2"_s.arg( it.key(), opt->
defaultValue ) );
4601 QgsVectorFileWriter::HiddenOption *opt =
dynamic_cast<QgsVectorFileWriter::HiddenOption *
>( option );
4602 if ( opt && !opt->
mValue.isEmpty() )
4604 list.append( u
"%1=%2"_s.arg( it.key(), opt->
mValue ) );
4615 OGRSFDriverH hDriver =
nullptr;
4619 const QString drvName = GDALGetDescription( hDriver );
4621 if ( OGR_DS_TestCapability( hDS.get(), ODsCCreateLayer ) )
4626 if ( !( drvName ==
"ESRI Shapefile"_L1 && QFile::exists( datasetName ) ) )
4629 if ( OGR_DS_TestCapability( hDS.get(), ODsCDeleteLayer ) )
4633 int layer_count = OGR_DS_GetLayerCount( hDS.get() );
4636 OGRLayerH hLayer = OGR_DS_GetLayer( hDS.get(), 0 );
4639 if ( OGR_L_TestCapability( hLayer, OLCSequentialWrite ) )
4642 if ( OGR_L_TestCapability( hLayer, OLCCreateField ) )
4653 const QString &layerNameIn )
4655 OGRSFDriverH hDriver =
nullptr;
4660 QString layerName( layerNameIn );
4661 if ( layerName.isEmpty() )
4662 layerName = QFileInfo( datasetName ).baseName();
4664 return OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
4669 const QString &layerName,
4673 OGRSFDriverH hDriver =
nullptr;
4677 OGRLayerH hLayer = OGR_DS_GetLayerByName( hDS.get(), layerName.toUtf8().constData() );
4683 OGRFeatureDefnH defn = OGR_L_GetLayerDefn( hLayer );
4684 const auto constAttributes = attributes;
4685 for (
int idx : constAttributes )
4688 if ( OGR_FD_GetFieldIndex( defn, fld.
name().toUtf8().constData() ) < 0 )
@ FieldComments
Writer can support field comments.
@ FieldAliases
Writer can support field aliases.
DistanceUnit
Units of distance.
QFlags< VectorFileWriterCapability > VectorFileWriterCapabilities
Capabilities supported by a QgsVectorFileWriter object.
RenderUnit
Rendering size units.
@ Millimeters
Millimeters.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPolygon25D
MultiPolygon25D.
@ GeometryCollectionZ
GeometryCollectionZ.
@ MultiLineString
MultiLineString.
@ MultiPolygonZ
MultiPolygonZ.
FeatureSymbologyExport
Options for exporting features considering their symbology.
@ PerFeature
Keeps the number of features and export symbology per feature.
@ PerSymbolLayer
Exports one feature per symbol layer (considering symbol levels).
@ NoSymbology
Export only data.
@ Reverse
Reverse/inverse transform (from destination to source).
Provides common functionality for database based connections.
virtual QgsFieldDomain * fieldDomain(const QString &name) const
Returns the field domain with the specified name from the provider.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
QFlags< WkbFlag > WkbFlags
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
@ FlagExportTrianglesAsPolygons
Triangles should be exported as polygon geometries.
@ FlagExportNanAsDoubleMin
Use -DOUBLE_MAX to represent NaN.
static void registerOgrDrivers()
Register OGR drivers ensuring this only happens once.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
Qgis::DistanceUnit mapUnits
Contains information about the context in which a coordinate transform is executed.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Abstract base class for all 2D vector feature renderers.
virtual QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const
Returns list of symbols used for rendering the feature.
virtual QgsSymbolList symbols(QgsRenderContext &context) const
Returns list of symbols used by the renderer.
bool usingSymbolLevels() const
virtual QgsFeatureRenderer::Capabilities capabilities()
Returns details about internals of this renderer.
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const =0
Returns a list of attributes required by this renderer.
@ SymbolLevels
Rendering with symbol levels (i.e. implements symbols(), symbolForFeature()).
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QFlags< SinkFlag > SinkFlags
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isUnsetValue(int fieldIdx) const
Returns true if the attribute at the specified index is an unset value.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
QString domainName() const
Returns the associated field domain name, for providers which support field domains.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
Encapsulate a field in an attribute table or data source.
QString typeName() const
Gets the field type.
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
void setName(const QString &name)
Set the field name.
QMetaType::Type subType() const
If the field is a collection, gets its element's type.
QgsFieldConstraints constraints
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Q_INVOKABLE bool exists(int i) const
Returns if a field index is valid.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QStringList multiLayerFileExtensions()
Returns a list of file extensions which potentially contain multiple layers representing GDAL raster ...
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Sets the current locale to the c locale for the lifetime of the object.
static void warning(const QString &msg)
Goes to qWarning.
static QgsAbstractDatabaseProviderConnection * databaseConnection(const QgsMapLayer *layer)
Creates and returns the (possibly nullptr) database connection for a layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsCoordinateReferenceSystem crs
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static OGRSpatialReferenceH crsToOGRSpatialReference(const QgsCoordinateReferenceSystem &crs)
Returns a OGRSpatialReferenceH corresponding to the specified crs object.
static std::unique_ptr< QgsFieldDomain > convertFieldDomain(OGRFieldDomainH domain)
Converts an OGR field domain definition to a QgsFieldDomain equivalent.
static int OGRTZFlagFromQt(const QDateTime &datetime)
Gets the value of OGRField::Date::TZFlag from the timezone of a QDateTime.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString encodeUri(const QString &providerKey, const QVariantMap &parts)
Reassembles a provider data source URI from its component paths (e.g.
A convenience class that simplifies locking and unlocking QReadWriteLocks.
void changeMode(Mode mode)
Change the mode of the lock to mode.
A rectangle specified with double values.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setRendererScale(double scale)
Sets the renderer map scale.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
int layer() const
The layer of this symbol level.
QgsSymbol * symbol() const
The symbol of this symbol level.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
An available option for configuring file writing for a particular output format, presenting an boolea...
Interface to convert raw field values to their user-friendly values.
FieldValueConverter()=default
virtual QVariant convert(int fieldIdxInLayer, const QVariant &value)
Convert the provided value, for field fieldIdxInLayer.
virtual QgsVectorFileWriter::FieldValueConverter * clone() const
Creates a clone of the FieldValueConverter.
virtual QgsField fieldDefinition(const QgsField &field)
Returns a possibly modified field definition.
An available option for configuring file writing for a particular output format, presenting an intege...
QgsVectorFileWriter::OptionType type
Options to pass to QgsVectorFileWriter::writeAsVectorFormat().
QString fileEncoding
Encoding to use.
bool forceMulti
Sets to true to force creation of multipart geometries.
QString driverName
OGR driver to use.
QgsCoordinateTransform ct
Transform to reproject exported geometries with, or invalid transform for no transformation.
QStringList attributesExportNames
Attributes export names.
QgsLayerMetadata layerMetadata
Layer metadata to save for the exported vector file.
QString layerName
Layer name. If let empty, it will be derived from the filename.
QgsRectangle filterExtent
If not empty, only features intersecting the extent will be saved.
bool includeConstraints
Set to true to transfer field constraints to the exported vector file.
const QgsAbstractDatabaseProviderConnection * sourceDatabaseProviderConnection
Source database provider connection, for field domains.
QgsVectorFileWriter::FieldValueConverter * fieldValueConverter
Field value converter.
QStringList layerOptions
List of OGR layer creation options.
Qgis::WkbType overrideGeometryType
Set to a valid geometry type to override the default geometry type for the layer.
bool includeZ
Sets to true to include z dimension in output. This option is only valid if overrideGeometryType is s...
Qgis::FeatureSymbologyExport symbologyExport
Symbology to export.
bool saveMetadata
Set to true to save layer metadata for the exported vector file.
QgsVectorFileWriter::ActionOnExistingFile actionOnExistingFile
Action on existing file.
QgsAttributeList attributes
Attributes to export (empty means all unless skipAttributeCreation is set).
bool onlySelectedFeatures
Write only selected features of layer.
QgsVectorFileWriter::FieldNameSource fieldNameSource
Source for exported field names.
bool skipAttributeCreation
Only write geometries.
bool setFieldDomains
Set to true to transfer field domains to the exported vector file.
double symbologyScale
Scale of symbology.
QStringList datasourceOptions
List of OGR data source creation options.
QgsFeedback * feedback
Optional feedback object allowing cancellation of layer save.
An available option for configuring file writing for a particular output format, presenting a choice ...
An available option for configuring file writing for a particular output format, presenting a freefor...
static QgsVectorFileWriter::WriterError writeAsVectorFormatV3(QgsVectorLayer *layer, const QString &fileName, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QString *errorMessage=nullptr, QString *newFilename=nullptr, QString *newLayer=nullptr)
Writes a layer out to a vector file.
Qgis::FeatureSymbologyExport mSymbologyExport
QString lastError() const override
Returns the most recent error encountered by the sink, e.g.
@ CanAddNewFieldsToExistingLayer
Flag to indicate that new fields can be added to an existing layer. Imply CanAppendToExistingLayer.
@ CanAppendToExistingLayer
Flag to indicate that new features can be added to an existing layer.
@ CanAddNewLayer
Flag to indicate that a new layer can be added to the dataset.
@ CanDeleteLayer
Flag to indicate that an existing layer can be deleted.
static QgsVectorFileWriter::EditionCapabilities editionCapabilities(const QString &datasetName)
Returns edition capabilities for an existing dataset name.
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a single feature to the sink.
static bool supportsFeatureStyles(const QString &driverName)
Returns true if the specified driverName supports feature styles.
Qgis::WkbType mWkbType
Geometry type which is being used.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
double mSymbologyScale
Scale for symbology export (e.g. for symbols units in map units).
QMap< int, int > mAttrIdxToOgrIdx
Map attribute indizes to OGR field indexes.
@ ErrAttributeTypeUnsupported
@ Canceled
Writing was interrupted by manual cancellation.
@ ErrAttributeCreationFailed
@ ErrSavingMetadata
Metadata saving failed.
gdal::ogr_datasource_unique_ptr mDS
static Q_DECL_DEPRECATED QgsVectorFileWriter::WriterError writeAsVectorFormatV2(QgsVectorLayer *layer, const QString &fileName, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QString *newFilename=nullptr, QString *newLayer=nullptr, QString *errorMessage=nullptr)
Writes a layer out to a vector file.
OGRGeometryH createEmptyGeometry(Qgis::WkbType wkbType)
QString mOgrDriverLongName
QFlags< EditionCapability > EditionCapabilities
Combination of CanAddNewLayer, CanAppendToExistingLayer, CanAddNewFieldsToExistingLayer or CanDeleteL...
~QgsVectorFileWriter() override
Close opened shapefile for writing.
static bool targetLayerExists(const QString &datasetName, const QString &layerName)
Returns whether the target layer already exists.
double symbologyScale() const
Returns the reference scale for output.
static QStringList defaultLayerOptions(const QString &driverName)
Returns a list of the default layer options for a specified driver.
static QString driverForExtension(const QString &extension)
Returns the OGR driver name for a specified file extension.
Qgis::VectorFileWriterCapabilities capabilities() const
Returns the capabilities supported by the writer.
static QList< QgsVectorFileWriter::FilterFormatDetails > supportedFiltersAndFormats(VectorFormatOptions options=SortRecommended)
Returns a list or pairs, with format filter string as first element and OGR format key as second elem...
OGRSpatialReferenceH mOgrRef
static bool driverMetadata(const QString &driverName, MetaData &driverMetadata)
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newFilename=nullptr, QString *newLayer=nullptr)
Create a new vector file writer.
QString driver() const
Returns the GDAL (short) driver name associated with the output file.
static bool deleteShapeFile(const QString &fileName)
Delete a shapefile (and its accompanying shx / dbf / prj / qix / qpj / cpg / sbn / sbx / idm / ind).
Q_DECL_DEPRECATED QgsVectorFileWriter(const QString &vectorFileName, const QString &fileEncoding, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs=QgsCoordinateReferenceSystem(), const QString &driverName="GPKG", const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), QString *newFilename=nullptr, Qgis::FeatureSymbologyExport symbologyExport=Qgis::FeatureSymbologyExport::NoSymbology, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newLayer=nullptr, const QgsCoordinateTransformContext &transformContext=QgsCoordinateTransformContext(), FieldNameSource fieldNameSource=Original)
Create a new vector file writer.
static Q_DECL_DEPRECATED QgsVectorFileWriter::WriterError writeAsVectorFormat(QgsVectorLayer *layer, const QString &fileName, const QString &fileEncoding, const QgsCoordinateReferenceSystem &destCRS=QgsCoordinateReferenceSystem(), const QString &driverName="GPKG", bool onlySelected=false, QString *errorMessage=nullptr, const QStringList &datasourceOptions=QStringList(), const QStringList &layerOptions=QStringList(), bool skipAttributeCreation=false, QString *newFilename=nullptr, Qgis::FeatureSymbologyExport symbologyExport=Qgis::FeatureSymbologyExport::NoSymbology, double symbologyScale=1.0, const QgsRectangle *filterExtent=nullptr, Qgis::WkbType overrideGeometryType=Qgis::WkbType::Unknown, bool forceMulti=false, bool includeZ=false, const QgsAttributeList &attributes=QgsAttributeList(), QgsVectorFileWriter::FieldValueConverter *fieldValueConverter=nullptr, QString *newLayer=nullptr)
Write contents of vector layer to an (OGR supported) vector format.
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
QgsVectorFileWriter::WriterError hasError() const
Checks whether there were any errors in constructor.
@ SupportsMultipleLayers
Filter to only formats which support multiple layers.
@ SkipNonSpatialFormats
Filter out any formats which do not have spatial support (e.g. those which cannot save geometries).
static bool areThereNewFieldsToCreate(const QString &datasetName, const QString &layerName, QgsVectorLayer *layer, const QgsAttributeList &attributes)
Returns whether there are among the attributes specified some that do not exist yet in the layer.
static QList< QgsVectorFileWriter::DriverDetails > ogrDriverList(VectorFormatOptions options=SortRecommended)
Returns the driver list that can be used for dialogs.
QString driverLongName() const
Returns the GDAL long driver name associated with the output file.
QFlags< VectorFormatOption > VectorFormatOptions
WriterError mError
Contains error value if construction was not successful.
Qgis::FeatureSymbologyExport symbologyExport() const
Returns the feature symbology export handling for the writer.
FieldNameSource
Source for exported field names.
@ PreferAlias
Use the field alias as the exported field name, wherever one is set. Otherwise use the original field...
@ Original
Use original field names.
bool mIncludeConstraints
Whether to transfer field constraints to output.
static QStringList defaultDatasetOptions(const QString &driverName)
Returns a list of the default dataset options for a specified driver.
bool addFeatureWithStyle(QgsFeature &feature, QgsFeatureRenderer *renderer, Qgis::DistanceUnit outputUnit=Qgis::DistanceUnit::Meters)
Adds a feature to the currently opened data source, using the style from a specified renderer.
static QStringList supportedFormatExtensions(VectorFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats, e.g "shp", "gpkg".
bool mSetFieldDomains
Whether to set field domains to output.
static QString convertCodecNameForEncodingOption(const QString &codecName)
Converts codec name to string passed to ENCODING layer creation option of OGR Shapefile.
FieldValueConverter * mFieldValueConverter
Field value converter.
QString errorMessage() const
Retrieves error message.
void setSymbologyScale(double scale)
Set reference scale for output.
static OGRwkbGeometryType ogrTypeFromWkbType(Qgis::WkbType type)
Gets the ogr geometry type from an internal QGIS wkb type enum.
QMap< QgsSymbolLayer *, QString > mSymbolLayerTable
static QString fileFilterString(VectorFormatOptions options=SortRecommended)
Returns filter string that can be used for dialogs.
ActionOnExistingFile
Enumeration to describe how to handle existing files.
@ CreateOrOverwriteLayer
Create or overwrite layer.
@ CreateOrOverwriteFile
Create or overwrite file.
@ AppendToLayerNoNewFields
Append features to existing layer, but do not create new fields.
@ AppendToLayerAddFields
Append features to existing layer, and create new fields if needed.
Represents a vector layer which manages a vector based dataset.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
static Qgis::WkbType to25D(Qgis::WkbType type)
Will convert the 25D version of the flat type if supported or Unknown if not supported.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Qgis::WkbType singleType(Qgis::WkbType type)
Returns the single type for a WKB type.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType multiType(Qgis::WkbType type)
Returns the multi type for a WKB type.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
std::unique_ptr< std::remove_pointer< OGRFeatureH >::type, OGRFeatureDeleter > ogr_feature_unique_ptr
Scoped OGR feature.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
QList< QgsFeature > QgsFeatureList
QList< int > QgsAttributeList
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QList< QgsSymbolLevel > QgsSymbolLevelOrder
QList< QgsSymbolLevelItem > QgsSymbolLevel
QList< QgsSymbol * > QgsSymbolList
QStringList multiLayerFormats()
Details of available driver formats.
QString longName
Descriptive, user friendly name for the driver.
QString driverName
Unique driver name.