38#include "qgsogrproviderutils.h"
47using namespace Qt::StringLiterals;
49#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
60#include <QJsonDocument>
65#include <QRegularExpression>
67#include "ogr_srs_api.h"
69#include "nlohmann/json.hpp"
73 OGR_DS_Destroy( source );
79 OGR_G_DestroyGeometry( geometry );
84 OGR_Fld_Destroy( definition );
89 OGR_F_Destroy( feature );
106 CPLPushErrorHandler( CPLQuietErrorHandler );
107 GDALDeleteDataset( driver, path.toUtf8().constData() );
108 CPLPopErrorHandler();
119 GDALDestroyWarpOptions( options );
122#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
125 GDALDestroyRelationship( relationship );
129static void setQTTimeZoneFromOGRTZFlag( QDateTime &dt,
int nTZFlag )
136 else if ( nTZFlag == 1 )
138 dt.setTimeSpec( Qt::LocalTime );
140 else if ( nTZFlag == 100 )
142 dt.setTimeSpec( Qt::UTC );
148 dt.setOffsetFromUtc( ( nTZFlag - 100 ) * 15 * 60 );
154 if ( !value || OGR_RawField_IsUnset( value ) || OGR_RawField_IsNull( value ) )
160 return value->Integer;
163 return value->Integer64;
170 return QString::fromUtf8( value->String );
173 return QDate( value->Date.Year, value->Date.Month, value->Date.Day );
177 float secondsPart = 0;
178 float millisecondPart = std::modf( value->Date.Second, &secondsPart );
179 return QTime( value->Date.Hour, value->Date.Minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) );
184 float secondsPart = 0;
185 float millisecondPart = std::modf( value->Date.Second, &secondsPart );
187 = QDateTime( QDate( value->Date.Year, value->Date.Month, value->Date.Day ), QTime( value->Date.Hour, value->Date.Minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) ) );
188 setQTTimeZoneFromOGRTZFlag( dt, value->Date.TZFlag );
194 Q_ASSERT_X(
false,
"QgsOgrUtils::OGRFieldtoVariant",
"OFTBinary type not supported" );
200 res.reserve( value->IntegerList.nCount );
201 for (
int i = 0; i < value->IntegerList.nCount; ++i )
202 res << value->IntegerList.paList[i];
206 case OFTInteger64List:
209 res.reserve( value->Integer64List.nCount );
210 for (
int i = 0; i < value->Integer64List.nCount; ++i )
211 res << value->Integer64List.paList[i];
218 res.reserve( value->RealList.nCount );
219 for (
int i = 0; i < value->RealList.nCount; ++i )
220 res << value->RealList.paList[i];
225 case OFTWideStringList:
228 res.reserve( value->StringList.nCount );
229 for (
int i = 0; i < value->StringList.nCount; ++i )
230 res << QString::fromUtf8( value->StringList.paList[i] );
239 if ( datetime.timeSpec() == Qt::LocalTime )
241 return 100 + datetime.offsetFromUtc() / ( 60 * 15 );
246 auto res = std::make_unique< OGRField >();
248 switch ( value.userType() )
250 case QMetaType::Type::UnknownType:
251 OGR_RawField_SetUnset( res.get() );
253 case QMetaType::Type::Bool:
255 const int val = value.toBool() ? 1 : 0;
256 if ( type == OFTInteger )
258 else if ( type == OFTInteger64 )
259 res->Integer64 = val;
260 else if ( type == OFTReal )
269 case QMetaType::Type::Int:
271 const int val = value.toInt();
272 if ( type == OFTInteger )
274 else if ( type == OFTInteger64 )
275 res->Integer64 = val;
276 else if ( type == OFTReal )
285 case QMetaType::Type::LongLong:
287 const qint64 val = value.toLongLong();
288 if ( type == OFTInteger )
290 if ( val <= std::numeric_limits<int>::max() && val >= std::numeric_limits<int>::min() )
292 res->Integer =
static_cast<int>( val );
300 else if ( type == OFTInteger64 )
301 res->Integer64 = val;
302 else if ( type == OFTReal )
304 res->Real =
static_cast<double>( val );
308 QgsDebugError(
"Unsupported output data type for LongLong" );
313 case QMetaType::Type::Double:
315 double val = value.toDouble();
316 if ( type == OFTInteger )
318 if ( val <= std::numeric_limits<int>::max() && val >= std::numeric_limits<int>::min() )
320 res->Integer =
static_cast<int>( val );
328 else if ( type == OFTInteger64 )
330 if ( val <=
static_cast<double>( std::numeric_limits<qint64>::max() ) && val >=
static_cast<double>( std::numeric_limits<qint64>::min() ) )
332 res->Integer64 =
static_cast<qint64
>( val );
340 else if ( type == OFTReal )
346 QgsDebugError(
"Unsupported output data type for LongLong" );
351 case QMetaType::Type::QChar:
352 case QMetaType::Type::QString:
354 if ( type == OFTString )
355 res->String = CPLStrdup( value.toString().toUtf8().constData() );
363 case QMetaType::Type::QDate:
365 if ( type == OFTDate )
367 const QDate date = value.toDate();
368 res->Date.Day = date.day();
369 res->Date.Month = date.month();
370 res->Date.Year =
static_cast<GInt16
>( date.year() );
371 res->Date.TZFlag = 0;
380 case QMetaType::Type::QTime:
382 if ( type == OFTTime )
384 const QTime time = value.toTime();
385 res->Date.Hour = time.hour();
386 res->Date.Minute = time.minute();
387 res->Date.Second =
static_cast<float>( time.second() +
static_cast< double >( time.msec() ) / 1000 );
388 res->Date.TZFlag = 0;
397 case QMetaType::Type::QDateTime:
399 if ( type == OFTDateTime )
401 const QDateTime dt = value.toDateTime();
402 const QDate date = dt.date();
403 res->Date.Day = date.day();
404 res->Date.Month = date.month();
405 res->Date.Year =
static_cast<GInt16
>( date.year() );
406 const QTime time = dt.time();
407 res->Date.Hour = time.hour();
408 res->Date.Minute = time.minute();
409 res->Date.Second =
static_cast<float>( time.second() +
static_cast< double >( time.msec() ) / 1000 );
414 QgsDebugError(
"Unsupported output data type for DateTime" );
421 QgsDebugError(
"Unhandled variant type in variantToOGRField" );
422 OGR_RawField_SetUnset( res.get() );
438 feature.
setId( OGR_F_GetFID( ogrFet ) );
461 int fieldCount = OGR_F_GetFieldCount( ogrFet );
462 for (
int i = 0; i < fieldCount; ++i )
464 OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
471 QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
472 QMetaType::Type varType;
473 switch ( OGR_Fld_GetType( fldDef ) )
476 if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
477 varType = QMetaType::Type::Bool;
479 varType = QMetaType::Type::Int;
482 varType = QMetaType::Type::LongLong;
485 varType = QMetaType::Type::Double;
488 varType = QMetaType::Type::QDate;
491 varType = QMetaType::Type::QTime;
494 varType = QMetaType::Type::QDateTime;
497 if ( OGR_Fld_GetSubType( fldDef ) == OFSTJSON )
498 varType = QMetaType::Type::QVariantMap;
500 varType = QMetaType::Type::QString;
503 varType = QMetaType::Type::QString;
513 if ( attIndex < 0 || attIndex >= fields.
count() )
526 if ( !ogrFet || attIndex < 0 )
533 OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
540 QgsDebugError( u
"ogrFet->GetFieldDefnRef(attindex) returns NULL"_s );
550 auto getJsonValue = [&]() ->
bool {
551 const char *json = OGR_F_GetFieldAsString( ogrFet, attIndex );
554 jsonContent = encoding->toUnicode( json ).toUtf8();
556 jsonContent = QString::fromUtf8( json ).toUtf8();
560 const nlohmann::json json_element = json::parse( jsonContent.toStdString() );
564 catch (
const json::parse_error &e )
571 if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
573 switch ( field.
type() )
575 case QMetaType::Type::QString:
577 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
580 value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
582 value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
587 if ( value.isNull() )
588 value = QVariant( u
""_s );
593 case QMetaType::Type::Int:
594 value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
596 case QMetaType::Type::Bool:
597 value = QVariant(
bool( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ) );
599 case QMetaType::Type::LongLong:
600 value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
602 case QMetaType::Type::Double:
603 value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
605 case QMetaType::Type::QDate:
606 case QMetaType::Type::QDateTime:
607 case QMetaType::Type::QTime:
609 int year, month, day, hour, minute, tzf;
611 float secondsPart = 0;
613 OGR_F_GetFieldAsDateTimeEx( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
614 float millisecondPart = std::modf( second, &secondsPart );
616 if ( field.
type() == QMetaType::Type::QDate )
617 value = QDate( year, month, day );
618 else if ( field.
type() == QMetaType::Type::QTime )
619 value = QTime( hour, minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) );
622 QDateTime dt = QDateTime( QDate( year, month, day ), QTime( hour, minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) ) );
623 setQTTimeZoneFromOGRTZFlag( dt, tzf );
629 case QMetaType::Type::QByteArray:
632 const GByte *b = OGR_F_GetFieldAsBinary( ogrFet, attIndex, &size );
636 QByteArray ba = QByteArray::fromRawData(
reinterpret_cast<const char *
>( b ), size );
643 case QMetaType::Type::QStringList:
645 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
648 char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
649 const int count = CSLCount( lst );
652 list.reserve( count );
653 for (
int i = 0; i < count; i++ )
656 list << encoding->toUnicode( lst[i] );
658 list << QString::fromUtf8( lst[i] );
666 case QMetaType::Type::QVariantList:
670 case QMetaType::Type::QString:
672 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
675 char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
676 const int count = CSLCount( lst );
679 list.reserve( count );
680 for (
int i = 0; i < count; i++ )
683 list << encoding->toUnicode( lst[i] );
685 list << QString::fromUtf8( lst[i] );
693 case QMetaType::Type::Int:
695 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
699 const int *lst = OGR_F_GetFieldAsIntegerList( ogrFet, attIndex, &count );
702 list.reserve( count );
703 for (
int i = 0; i < count; i++ )
713 case QMetaType::Type::Double:
715 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
719 const double *lst = OGR_F_GetFieldAsDoubleList( ogrFet, attIndex, &count );
722 list.reserve( count );
723 for (
int i = 0; i < count; i++ )
733 case QMetaType::Type::LongLong:
735 if ( field.
typeName() !=
"JSON"_L1 || !getJsonValue() )
739 const long long *lst = OGR_F_GetFieldAsInteger64List( ogrFet, attIndex, &count );
742 list.reserve( count );
743 for (
int i = 0; i < count; i++ )
755 Q_ASSERT_X(
false,
"QgsOgrUtils::getOgrFeatureAttribute",
"unsupported field type" );
764 case QMetaType::Type::QVariantMap:
769 value = QJsonDocument::fromJson( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
771 value = QJsonDocument::fromJson( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
775 Q_ASSERT_X(
false,
"QgsOgrUtils::getOgrFeatureAttribute",
"unsupported field type" );
798 for (
int idx = 0; idx < fields.
count(); ++idx )
814 OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
828 OGR_G_GetPointZM( geom, 0, &x, &y, &z, &m );
829 return std::make_unique< QgsPoint >( wkbType, x, y, z, m );
834 auto mp = std::make_unique< QgsMultiPoint >();
836 const int count = OGR_G_GetGeometryCount( geom );
837 mp->reserve( count );
838 for (
int i = 0; i < count; ++i )
850 int count = OGR_G_GetPointCount( geom );
851 QVector< double > x( count );
852 QVector< double > y( count );
854 double *pz =
nullptr;
860 double *pm =
nullptr;
867 OGR_G_GetPointsZM( geom, x.data(),
sizeof(
double ), y.data(),
sizeof(
double ), pz,
sizeof(
double ), pm,
sizeof(
double ) );
874 auto mp = std::make_unique< QgsMultiLineString >();
876 const int count = OGR_G_GetGeometryCount( geom );
877 mp->reserve( count );
878 for (
int i = 0; i < count; ++i )
888 auto polygon = std::make_unique< QgsPolygon >();
890 const int count = OGR_G_GetGeometryCount( geom );
896 for (
int i = 1; i < count; ++i )
906 auto polygon = std::make_unique< QgsMultiPolygon >();
908 const int count = OGR_G_GetGeometryCount( geom );
909 polygon->reserve( count );
910 for (
int i = 0; i < count; ++i )
920 auto polyhedralSurface = std::make_unique< QgsPolyhedralSurface >();
922 const int count = OGR_G_GetGeometryCount( geom );
923 for (
int i = 0; i < count; ++i )
928 return polyhedralSurface;
933 switch ( ogrGeomType )
945 case wkbMultiLineString:
947 case wkbMultiPolygon:
949 case wkbGeometryCollection:
951 case wkbCircularString:
953 case wkbCompoundCurve:
955 case wkbCurvePolygon:
959 case wkbMultiSurface:
965 case wkbPolyhedralSurface:
977 case wkbCircularStringZ:
979 case wkbCompoundCurveZ:
981 case wkbCurvePolygonZ:
985 case wkbMultiSurfaceZ:
991 case wkbPolyhedralSurfaceZ:
1000 case wkbLineStringM:
1004 case wkbMultiPointM:
1006 case wkbMultiLineStringM:
1008 case wkbMultiPolygonM:
1010 case wkbGeometryCollectionM:
1012 case wkbCircularStringM:
1014 case wkbCompoundCurveM:
1016 case wkbCurvePolygonM:
1018 case wkbMultiCurveM:
1020 case wkbMultiSurfaceM:
1026 case wkbPolyhedralSurfaceM:
1035 case wkbLineStringZM:
1039 case wkbMultiPointZM:
1041 case wkbMultiLineStringZM:
1043 case wkbMultiPolygonZM:
1045 case wkbGeometryCollectionZM:
1047 case wkbCircularStringZM:
1049 case wkbCompoundCurveZM:
1051 case wkbCurvePolygonZM:
1053 case wkbMultiCurveZM:
1055 case wkbMultiSurfaceZM:
1061 case wkbPolyhedralSurfaceZM:
1070 case wkbLineString25D:
1074 case wkbMultiPoint25D:
1076 case wkbMultiLineString25D:
1078 case wkbMultiPolygon25D:
1080 case wkbGeometryCollection25D:
1110 return wkbLineString;
1112 return wkbLineString25D;
1114 return wkbLineString25D;
1116 return wkbLineStringM;
1118 return wkbLineStringZM;
1123 return wkbPolygon25D;
1125 return wkbPolygon25D;
1129 return wkbPolygonZM;
1132 return wkbMultiPoint;
1134 return wkbMultiPoint25D;
1136 return wkbMultiPoint25D;
1138 return wkbMultiPointM;
1140 return wkbMultiPointZM;
1143 return wkbMultiLineString;
1145 return wkbMultiLineString25D;
1147 return wkbMultiLineString25D;
1149 return wkbMultiLineStringM;
1151 return wkbMultiLineStringZM;
1154 return wkbMultiPolygon;
1156 return wkbMultiPolygon25D;
1158 return wkbMultiPolygon25D;
1160 return wkbMultiPolygonM;
1162 return wkbMultiPolygonZM;
1165 return wkbGeometryCollection;
1167 return wkbGeometryCollection25D;
1169 return wkbGeometryCollectionM;
1171 return wkbGeometryCollectionZM;
1176 return wkbTriangleZ;
1178 return wkbTriangleM;
1180 return wkbTriangleZM;
1183 return wkbCircularString;
1185 return wkbCircularStringZ;
1187 return wkbCircularStringM;
1189 return wkbCircularStringZM;
1192 return approx ? wkbLineString : wkbUnknown;
1194 return approx ? wkbLineString25D : wkbUnknown;
1196 return approx ? wkbLineStringM : wkbUnknown;
1198 return approx ? wkbLineStringZM : wkbUnknown;
1201 return wkbCompoundCurve;
1203 return wkbCompoundCurveZ;
1205 return wkbCompoundCurveM;
1207 return wkbCompoundCurveZM;
1210 return wkbMultiCurve;
1212 return wkbMultiCurveZ;
1214 return wkbMultiCurveM;
1216 return wkbMultiCurveZM;
1219 return wkbCurvePolygon;
1221 return wkbCurvePolygonZ;
1223 return wkbCurvePolygonM;
1225 return wkbCurvePolygonZM;
1228 return wkbMultiSurface;
1230 return wkbMultiSurfaceZ;
1232 return wkbMultiSurfaceM;
1234 return wkbMultiSurfaceZM;
1237 return wkbPolyhedralSurface;
1239 return wkbPolyhedralSurfaceZ;
1241 return wkbPolyhedralSurfaceM;
1243 return wkbPolyhedralSurfaceZM;
1262 const auto ogrGeomType = OGR_G_GetGeometryType( geom );
1310 if ( wkbFlatten( wkbType ) == wkbGeometryCollection )
1313 if ( OGR_G_GetGeometryCount( geom ) >= 1 && wkbFlatten( OGR_G_GetGeometryType( OGR_G_GetGeometryRef( geom, 0 ) ) ) == wkbTIN )
1315 auto newGeom = OGR_G_ForceToMultiPolygon( OGR_G_Clone( geom ) );
1317 OGR_G_DestroyGeometry( newGeom );
1323 int memorySize = OGR_G_WkbSize( geom );
1324 unsigned char *wkb =
new unsigned char[memorySize];
1335 if (
string.isEmpty() )
1338 QString randomFileName = u
"/vsimem/%1"_s.arg( QUuid::createUuid().toString() );
1341 QByteArray ba =
string.toUtf8();
1342 VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(),
reinterpret_cast< GByte *
>( ba.data() ),
static_cast< vsi_l_offset
>( ba.size() ), FALSE ) );
1347 VSIUnlink( randomFileName.toUtf8().constData() );
1351 OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
1355 VSIUnlink( randomFileName.toUtf8().constData() );
1360 while ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
1368 VSIUnlink( randomFileName.toUtf8().constData() );
1376 if (
string.isEmpty() )
1379 QString randomFileName = u
"/vsimem/%1"_s.arg( QUuid::createUuid().toString() );
1382 QByteArray ba =
string.toUtf8();
1383 VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(),
reinterpret_cast< GByte *
>( ba.data() ),
static_cast< vsi_l_offset
>( ba.size() ), FALSE ) );
1388 VSIUnlink( randomFileName.toUtf8().constData() );
1392 OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
1396 VSIUnlink( randomFileName.toUtf8().constData() );
1402 if ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
1408 VSIUnlink( randomFileName.toUtf8().constData() );
1417 QStringList strings;
1419 for (
qgssize i = 0; stringList[i]; ++i )
1421 strings.append( QString::fromUtf8( stringList[i] ) );
1432 char *pszWkt =
nullptr;
1433 const QByteArray multiLineOption = u
"MULTILINE=NO"_s.toLocal8Bit();
1434 const QByteArray formatOption = u
"FORMAT=WKT2"_s.toLocal8Bit();
1435 const char *
const options[] = { multiLineOption.constData(), formatOption.constData(),
nullptr };
1436 OSRExportToWktEx( srs, &pszWkt, options );
1438 const QString res( pszWkt );
1446 if ( wkt.isEmpty() )
1449 const char *authorityName = OSRGetAuthorityName( srs,
nullptr );
1450 const char *authorityCode = OSRGetAuthorityCode( srs,
nullptr );
1452 if ( authorityName && authorityCode )
1454 QString authId = QString( authorityName ) +
':' + QString( authorityCode );
1455 OGRSpatialReferenceH ogrSrsTmp = OSRNewSpatialReference(
nullptr );
1457 if ( OSRSetFromUserInput( ogrSrsTmp, authId.toUtf8().constData() ) != OGRERR_NONE && OSRIsSame( srs, ogrSrsTmp ) )
1462 OSRDestroySpatialReference( ogrSrsTmp );
1467#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 4, 0 )
1468 const double coordinateEpoch = OSRGetCoordinateEpoch( srs );
1469 if ( coordinateEpoch > 0 )
1479 OGRSpatialReferenceH ogrSrs =
nullptr;
1485 const QString authId = crs.
authid();
1487 if ( !authId.isEmpty() )
1489 ogrSrs = OSRNewSpatialReference(
nullptr );
1490 if ( OSRSetFromUserInput( ogrSrs, authId.toUtf8().constData() ) == OGRERR_NONE )
1493 OGRSpatialReferenceH ogrSrsFromWkt = OSRNewSpatialReference( srsWkt.toUtf8().constData() );
1494 if ( ogrSrsFromWkt )
1496 if ( !OSRIsSame( ogrSrs, ogrSrsFromWkt ) )
1498 OSRDestroySpatialReference( ogrSrs );
1499 ogrSrs = ogrSrsFromWkt;
1503 OSRDestroySpatialReference( ogrSrsFromWkt );
1509 OSRDestroySpatialReference( ogrSrs );
1515 ogrSrs = OSRNewSpatialReference( srsWkt.toUtf8().constData() );
1519 OSRSetAxisMappingStrategy( ogrSrs, OAMS_TRADITIONAL_GIS_ORDER );
1520#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 4, 0 )
1536 if ( !cpgEncoding.isEmpty() )
1545 QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path,
false, QStringList(), 0, errCause,
false );
1546 return layer ? layer->GetMetadataItem( u
"ENCODING_FROM_CPG"_s, u
"SHAPEFILE"_s ) : QString();
1552 QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path,
false, QStringList(), 0, errCause,
false );
1553 return layer ? layer->GetMetadataItem( u
"ENCODING_FROM_LDID"_s, u
"SHAPEFILE"_s ) : QString();
1560 char **papszStyleString = CSLTokenizeString2(
string.toUtf8().constData(),
";", CSLT_HONOURSTRINGS | CSLT_PRESERVEQUOTES | CSLT_PRESERVEESCAPES );
1561 for (
int i = 0; papszStyleString[i] !=
nullptr; ++i )
1567 const thread_local QRegularExpression sToolPartRx( u
"^(.*?)\\((.*)\\)$"_s );
1568 const QString stylePart( papszStyleString[i] );
1569 const QRegularExpressionMatch match = sToolPartRx.match( stylePart );
1570 if ( !match.hasMatch() )
1573 const QString tool = match.captured( 1 );
1574 const QString params = match.captured( 2 );
1576 char **papszTokens = CSLTokenizeString2( params.toUtf8().constData(),
",", CSLT_HONOURSTRINGS | CSLT_PRESERVEESCAPES );
1578 QVariantMap toolParts;
1579 const thread_local QRegularExpression sToolParamRx( u
"^(.*?):(.*)$"_s );
1580 for (
int j = 0; papszTokens[j] !=
nullptr; ++j )
1582 const QString toolPart( papszTokens[j] );
1583 const QRegularExpressionMatch toolMatch = sToolParamRx.match( toolPart );
1584 if ( !match.hasMatch() )
1588 toolParts.insert( toolMatch.captured( 1 ).toLower(), toolMatch.captured( 2 ) );
1590 CSLDestroy( papszTokens );
1593 styles.insert( tool.toLower(), toolParts );
1595 CSLDestroy( papszStyleString );
1603 auto convertSize = [](
const QString &size,
double &value,
Qgis::RenderUnit &unit ) ->
bool {
1604 const thread_local QRegularExpression sUnitRx = QRegularExpression( u
"^([\\d\\.]+)(g|px|pt|mm|cm|in)$"_s );
1605 const QRegularExpressionMatch match = sUnitRx.match( size );
1606 if ( match.hasMatch() )
1608 value = match.captured( 1 ).toDouble();
1609 const QString unitString = match.captured( 2 );
1610 if ( unitString.compare(
"px"_L1, Qt::CaseInsensitive ) == 0 )
1614 static constexpr double PT_TO_INCHES_FACTOR = 1 / 72.0;
1615 static constexpr double PX_TO_PT_FACTOR = 1 / ( 96.0 * PT_TO_INCHES_FACTOR );
1617 value *= PX_TO_PT_FACTOR;
1620 else if ( unitString.compare(
"pt"_L1, Qt::CaseInsensitive ) == 0 )
1625 else if ( unitString.compare(
"mm"_L1, Qt::CaseInsensitive ) == 0 )
1630 else if ( unitString.compare(
"cm"_L1, Qt::CaseInsensitive ) == 0 )
1636 else if ( unitString.compare(
"in"_L1, Qt::CaseInsensitive ) == 0 )
1641 else if ( unitString.compare(
'g'_L1, Qt::CaseInsensitive ) == 0 )
1650 QgsDebugError( u
"Could not parse style size %1"_s.arg( size ) );
1655 auto convertColor = [](
const QString &string ) -> QColor {
1656 if (
string.isEmpty() )
1659 const thread_local QRegularExpression sColorWithAlphaRx = QRegularExpression( u
"^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})$"_s );
1660 const QRegularExpressionMatch match = sColorWithAlphaRx.match(
string );
1661 if ( match.hasMatch() )
1664 return QColor( u
"#%1%2"_s.arg( match.captured( 2 ), match.captured( 1 ) ) );
1668 return QColor(
string );
1672 auto convertPen = [&convertColor, &convertSize, string](
const QVariantMap &lineStyle ) -> std::unique_ptr< QgsSymbol > {
1673 QColor color = convertColor( lineStyle.value( u
"c"_s, u
"#000000"_s ).toString() );
1677 convertSize( lineStyle.value( u
"w"_s ).toString(), lineWidth, lineWidthUnit );
1680 const thread_local QRegularExpression sMapInfoId = QRegularExpression( u
"mapinfo-pen-(\\d+)"_s );
1681 const QRegularExpressionMatch match = sMapInfoId.match(
string );
1682 if ( match.hasMatch() )
1684 const int penId = match.captured( 1 ).toInt();
1691 auto simpleLine = std::make_unique< QgsSimpleLineSymbolLayer >( color, lineWidth );
1692 simpleLine->setWidthUnit( lineWidthUnit );
1695 const QString pattern = lineStyle.value( u
"p"_s ).toString();
1696 if ( !pattern.isEmpty() )
1698 const thread_local QRegularExpression sPatternUnitRx = QRegularExpression( u
"^([\\d\\.\\s]+)(g|px|pt|mm|cm|in)$"_s );
1699 const QRegularExpressionMatch match = sPatternUnitRx.match( pattern );
1700 if ( match.hasMatch() )
1702 const QStringList patternValues = match.captured( 1 ).split(
' ' );
1703 QVector< qreal > dashPattern;
1705 for (
const QString &val : patternValues )
1708 convertSize( val + match.captured( 2 ), length, patternUnits );
1709 dashPattern.push_back( length * lineWidth * 2 );
1712 simpleLine->setCustomDashVector( dashPattern );
1713 simpleLine->setCustomDashPatternUnit( patternUnits );
1714 simpleLine->setUseCustomDashPattern(
true );
1718 Qt::PenCapStyle capStyle = Qt::FlatCap;
1719 Qt::PenJoinStyle joinStyle = Qt::MiterJoin;
1721 const QString
id = lineStyle.value( u
"id"_s ).toString();
1722 if (
id.contains(
"mapinfo-pen"_L1, Qt::CaseInsensitive ) )
1727 capStyle = Qt::RoundCap;
1728 joinStyle = Qt::RoundJoin;
1732 const QString penCap = lineStyle.value( u
"cap"_s ).toString();
1733 if ( penCap.compare(
'b'_L1, Qt::CaseInsensitive ) == 0 )
1735 capStyle = Qt::FlatCap;
1737 else if ( penCap.compare(
'r'_L1, Qt::CaseInsensitive ) == 0 )
1739 capStyle = Qt::RoundCap;
1741 else if ( penCap.compare(
'p'_L1, Qt::CaseInsensitive ) == 0 )
1743 capStyle = Qt::SquareCap;
1745 simpleLine->setPenCapStyle( capStyle );
1748 const QString penJoin = lineStyle.value( u
"j"_s ).toString();
1749 if ( penJoin.compare(
'm'_L1, Qt::CaseInsensitive ) == 0 )
1751 joinStyle = Qt::MiterJoin;
1753 else if ( penJoin.compare(
'r'_L1, Qt::CaseInsensitive ) == 0 )
1755 joinStyle = Qt::RoundJoin;
1757 else if ( penJoin.compare(
'b'_L1, Qt::CaseInsensitive ) == 0 )
1759 joinStyle = Qt::BevelJoin;
1761 simpleLine->setPenJoinStyle( joinStyle );
1763 const QString priority = lineStyle.value( u
"l"_s ).toString();
1764 if ( !priority.isEmpty() )
1766 simpleLine->setRenderingPass( priority.toInt() );
1768 return std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << simpleLine.release() );
1771 auto convertBrush = [&convertColor](
const QVariantMap &brushStyle ) -> std::unique_ptr< QgsSymbol > {
1772 const QColor foreColor = convertColor( brushStyle.value( u
"fc"_s, u
"#000000"_s ).toString() );
1773 const QColor backColor = convertColor( brushStyle.value( u
"bc"_s, QString() ).toString() );
1775 const QString
id = brushStyle.value( u
"id"_s ).toString();
1778 const thread_local QRegularExpression sMapInfoId = QRegularExpression( u
"mapinfo-brush-(\\d+)"_s );
1779 const QRegularExpressionMatch match = sMapInfoId.match(
id );
1780 if ( match.hasMatch() )
1782 const int brushId = match.captured( 1 ).toInt();
1789 const thread_local QRegularExpression sOgrId = QRegularExpression( u
"ogr-brush-(\\d+)"_s );
1790 const QRegularExpressionMatch ogrMatch = sOgrId.match(
id );
1792 Qt::BrushStyle style = Qt::SolidPattern;
1793 if ( ogrMatch.hasMatch() )
1795 const int brushId = ogrMatch.captured( 1 ).toInt();
1799 style = Qt::SolidPattern;
1803 style = Qt::NoBrush;
1807 style = Qt::HorPattern;
1811 style = Qt::VerPattern;
1815 style = Qt::FDiagPattern;
1819 style = Qt::BDiagPattern;
1823 style = Qt::CrossPattern;
1827 style = Qt::DiagCrossPattern;
1833 if ( backColor.isValid() && style != Qt::SolidPattern && style != Qt::NoBrush )
1835 auto backgroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( backColor );
1836 backgroundFill->setLocked(
true );
1837 backgroundFill->setStrokeStyle( Qt::NoPen );
1838 layers << backgroundFill.release();
1841 auto foregroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( foreColor );
1842 foregroundFill->setBrushStyle( style );
1843 foregroundFill->setStrokeStyle( Qt::NoPen );
1845 const QString priority = brushStyle.value( u
"l"_s ).toString();
1846 if ( !priority.isEmpty() )
1848 foregroundFill->setRenderingPass( priority.toInt() );
1850 layers << foregroundFill.release();
1851 return std::make_unique< QgsFillSymbol >( layers );
1854 auto convertSymbol = [&convertColor, &convertSize, string](
const QVariantMap &symbolStyle ) -> std::unique_ptr< QgsSymbol > {
1855 const QColor color = convertColor( symbolStyle.value( u
"c"_s, u
"#000000"_s ).toString() );
1859 convertSize( symbolStyle.value( u
"s"_s ).toString(), symbolSize, symbolSizeUnit );
1861 const double angle = symbolStyle.value( u
"a"_s, u
"0"_s ).toDouble();
1863 const QString
id = symbolStyle.value( u
"id"_s ).toString();
1866 const thread_local QRegularExpression sMapInfoId = QRegularExpression( u
"mapinfo-sym-(\\d+)"_s );
1867 const QRegularExpressionMatch match = sMapInfoId.match(
id );
1868 if ( match.hasMatch() )
1870 const int symbolId = match.captured( 1 ).toInt();
1881 std::unique_ptr< QgsMarkerSymbolLayer > markerLayer;
1883 const thread_local QRegularExpression sFontId = QRegularExpression( u
"font-sym-(\\d+)"_s );
1884 const QRegularExpressionMatch fontMatch = sFontId.match(
id );
1885 if ( fontMatch.hasMatch() )
1887 const int symId = fontMatch.captured( 1 ).toInt();
1888 const QStringList families = symbolStyle.value( u
"f"_s, QString() ).toString().split(
',' );
1890 bool familyFound =
false;
1893 for (
const QString &family : std::as_const( families ) )
1900 fontFamily = processedFamily;
1907 auto fontMarker = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, QChar( symId ), symbolSize );
1908 fontMarker->setSizeUnit( symbolSizeUnit );
1909 fontMarker->setAngle( -angle );
1911 fontMarker->setColor( color );
1913 const QColor strokeColor = convertColor( symbolStyle.value( u
"o"_s, QString() ).toString() );
1914 if ( strokeColor.isValid() )
1916 fontMarker->setStrokeColor( strokeColor );
1917 fontMarker->setStrokeWidth( 1 );
1922 fontMarker->setStrokeWidth( 0 );
1925 markerLayer = std::move( fontMarker );
1927 else if ( !families.empty() )
1936 const thread_local QRegularExpression sOgrId = QRegularExpression( u
"ogr-sym-(\\d+)"_s );
1937 const QRegularExpressionMatch ogrMatch = sOgrId.match(
id );
1940 bool isFilled =
true;
1941 if ( ogrMatch.hasMatch() )
1943 const int symId = ogrMatch.captured( 1 ).toInt();
2006 auto simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, symbolSize, -angle );
2007 simpleMarker->setSizeUnit( symbolSizeUnit );
2008 simpleMarker->setStrokeWidth( 1.0 );
2013 simpleMarker->setColor( color );
2014 simpleMarker->setStrokeStyle( Qt::NoPen );
2018 simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
2019 simpleMarker->setStrokeColor( color );
2022 const QColor strokeColor = convertColor( symbolStyle.value( u
"o"_s, QString() ).toString() );
2023 if ( strokeColor.isValid() )
2025 simpleMarker->setStrokeColor( strokeColor );
2026 simpleMarker->setStrokeStyle( Qt::SolidLine );
2029 markerLayer = std::move( simpleMarker );
2032 return std::make_unique< QgsMarkerSymbol >(
QgsSymbolLayerList() << markerLayer.release() );
2038 if ( styles.contains( u
"symbol"_s ) )
2040 const QVariantMap symbolStyle = styles.value( u
"symbol"_s ).toMap();
2041 return convertSymbol( symbolStyle );
2049 if ( styles.contains( u
"pen"_s ) )
2052 const QVariantMap lineStyle = styles.value( u
"pen"_s ).toMap();
2053 return convertPen( lineStyle );
2062 std::unique_ptr< QgsSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
2063 if ( styles.contains( u
"brush"_s ) )
2065 const QVariantMap brushStyle = styles.value( u
"brush"_s ).toMap();
2066 fillSymbol = convertBrush( brushStyle );
2070 auto emptyFill = std::make_unique< QgsSimpleFillSymbolLayer >();
2071 emptyFill->setBrushStyle( Qt::NoBrush );
2072 fillSymbol = std::make_unique< QgsFillSymbol >(
QgsSymbolLayerList() << emptyFill.release() );
2075 std::unique_ptr< QgsSymbol > penSymbol;
2076 if ( styles.contains( u
"pen"_s ) )
2078 const QVariantMap lineStyle = styles.value( u
"pen"_s ).toMap();
2079 penSymbol = convertPen( lineStyle );
2084 const int count = penSymbol->symbolLayerCount();
2090 condenseFillAndOutline(
dynamic_cast< QgsFillSymbolLayer *
>( fillSymbol->symbolLayer( fillSymbol->symbolLayerCount() - 1 ) ),
dynamic_cast< QgsLineSymbolLayer *
>( penSymbol->symbolLayer( 0 ) ) ) )
2094 for (
int i = 0; i < count; ++i )
2096 std::unique_ptr< QgsSymbolLayer > layer( penSymbol->takeSymbolLayer( 0 ) );
2097 layer->setLocked(
true );
2098 fillSymbol->appendSymbolLayer( layer.release() );
2114 variantType = QMetaType::Type::UnknownType;
2115 variantSubType = QMetaType::Type::UnknownType;
2120 if ( ogrSubType == OFSTBoolean )
2122 variantType = QMetaType::Type::Bool;
2125 variantType = QMetaType::Type::Int;
2128 variantType = QMetaType::Type::LongLong;
2131 variantType = QMetaType::Type::Double;
2134 variantType = QMetaType::Type::QDate;
2137 variantType = QMetaType::Type::QTime;
2140 variantType = QMetaType::Type::QDateTime;
2144 variantType = QMetaType::Type::QByteArray;
2149 if ( ogrSubType == OFSTJSON )
2151 variantType = QMetaType::Type::QVariantMap;
2152 variantSubType = QMetaType::Type::QString;
2156 variantType = QMetaType::Type::QString;
2161 case OFTWideStringList:
2162 variantType = QMetaType::Type::QStringList;
2163 variantSubType = QMetaType::Type::QString;
2166 case OFTIntegerList:
2167 variantType = QMetaType::Type::QVariantList;
2168 variantSubType = QMetaType::Type::Int;
2172 variantType = QMetaType::Type::QVariantList;
2173 variantSubType = QMetaType::Type::Double;
2176 case OFTInteger64List:
2177 variantType = QMetaType::Type::QVariantList;
2178 variantSubType = QMetaType::Type::LongLong;
2185 ogrSubType = OFSTNone;
2186 switch ( variantType )
2188 case QMetaType::Type::Bool:
2189 ogrType = OFTInteger;
2190 ogrSubType = OFSTBoolean;
2193 case QMetaType::Type::Int:
2194 ogrType = OFTInteger;
2197 case QMetaType::Type::LongLong:
2198 ogrType = OFTInteger64;
2201 case QMetaType::Type::Double:
2205 case QMetaType::Type::QChar:
2206 case QMetaType::Type::QString:
2207 ogrType = OFTString;
2210 case QMetaType::Type::QStringList:
2211 ogrType = OFTStringList;
2214 case QMetaType::Type::QByteArray:
2215 ogrType = OFTBinary;
2218 case QMetaType::Type::QDate:
2222 case QMetaType::Type::QTime:
2225 case QMetaType::Type::QDateTime:
2226 ogrType = OFTDateTime;
2230 ogrType = OFTString;
2237 if (
string.isEmpty() )
2245 res =
string.toInt( &ok );
2249 res =
string.toLongLong( &ok );
2253 res =
string.toDouble( &ok );
2263 res = QDate::fromString(
string, Qt::ISODate );
2268 res = QTime::fromString(
string, Qt::ISODate );
2273 res = QDateTime::fromString(
string, Qt::ISODate );
2283 return ok ? res : QVariant();
2291 const QString driverName = QString::fromUtf8( GDALGetDriverShortName( driver ) );
2293 int nMaxIntLen = 11;
2294 int nMaxInt64Len = 21;
2295 int nMaxDoubleLen = 20;
2296 int nMaxDoublePrec = 15;
2298 if ( driverName ==
"GPKG"_L1 )
2308 QList<QgsVectorDataProvider::NativeType> nativeTypes;
2315 if ( driverName ==
"GPKG"_L1 )
2316 nativeTypes <<
QgsVectorDataProvider::NativeType( QObject::tr(
"JSON (string)" ), u
"JSON"_s, QMetaType::Type::QVariantMap, 0, 0, 0, 0, QMetaType::Type::QString );
2318 bool supportsDate =
true;
2319 bool supportsTime =
true;
2320 bool supportsDateTime =
true;
2321 bool supportsBinary =
false;
2322 bool supportIntegerList =
false;
2323 bool supportInteger64List =
false;
2324 bool supportRealList =
false;
2325 bool supportsStringList =
false;
2329 if (
const char *pszDataTypes = GDALGetMetadataItem( driver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr ) )
2331 char **papszTokens = CSLTokenizeString2( pszDataTypes,
" ", 0 );
2332 supportsDate = CSLFindString( papszTokens,
"Date" ) >= 0;
2333 supportsTime = CSLFindString( papszTokens,
"Time" ) >= 0;
2334 supportsDateTime = CSLFindString( papszTokens,
"DateTime" ) >= 0;
2335 supportsBinary = CSLFindString( papszTokens,
"Binary" ) >= 0;
2336 supportIntegerList = CSLFindString( papszTokens,
"IntegerList" ) >= 0;
2337 supportInteger64List = CSLFindString( papszTokens,
"Integer64List" ) >= 0;
2338 supportRealList = CSLFindString( papszTokens,
"RealList" ) >= 0;
2339 supportsStringList = CSLFindString( papszTokens,
"StringList" ) >= 0;
2340 CSLDestroy( papszTokens );
2345#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION( 3, 2, 0 )
2346 if ( driverName ==
"ESRI Shapefile"_L1 )
2348 supportsDateTime =
false;
2360 if ( supportsDateTime )
2364 if ( supportsBinary )
2368 if ( supportIntegerList )
2370 nativeTypes << QgsVectorDataProvider::
2371 NativeType(
QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::Int ), u
"integerlist"_s, QMetaType::Type::QVariantList, 0, 0, 0, 0, QMetaType::Type::Int );
2373 if ( supportInteger64List )
2375 nativeTypes << QgsVectorDataProvider::
2376 NativeType(
QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::LongLong ), u
"integer64list"_s, QMetaType::Type::QVariantList, 0, 0, 0, 0, QMetaType::Type::LongLong );
2378 if ( supportRealList )
2380 nativeTypes << QgsVectorDataProvider::
2381 NativeType(
QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::Double ), u
"doublelist"_s, QMetaType::Type::QVariantList, 0, 0, 0, 0, QMetaType::Type::Double );
2383 if ( supportsStringList )
2388 const char *pszDataSubTypes = GDALGetMetadataItem( driver, GDAL_DMD_CREATIONFIELDDATASUBTYPES,
nullptr );
2389 if ( pszDataSubTypes && strstr( pszDataSubTypes,
"Boolean" ) )
2399#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 3, 0 )
2405 const QString name { OGR_FldDomain_GetName( domain ) };
2406 const QString description { OGR_FldDomain_GetDescription( domain ) };
2408 QMetaType::Type fieldType = QMetaType::Type::UnknownType;
2409 QMetaType::Type fieldSubType = QMetaType::Type::UnknownType;
2410 const OGRFieldType domainFieldType = OGR_FldDomain_GetFieldType( domain );
2411 const OGRFieldSubType domainFieldSubType = OGR_FldDomain_GetFieldSubType( domain );
2414 std::unique_ptr< QgsFieldDomain > res;
2415 switch ( OGR_FldDomain_GetDomainType( domain ) )
2419 QList< QgsCodedValue > values;
2420 const OGRCodedValue *codedValue = OGR_CodedFldDomain_GetEnumeration( domain );
2421 while ( codedValue && codedValue->pszCode )
2423 const QString code( codedValue->pszCode );
2428 const QString value( codedValue->pszValue ? codedValue->pszValue : codedValue->pszCode );
2434 res = std::make_unique< QgsCodedFieldDomain >( name, description, fieldType, values );
2441 bool minIsInclusive =
false;
2442 if (
const OGRField *min = OGR_RangeFldDomain_GetMin( domain, &minIsInclusive ) )
2447 bool maxIsInclusive =
false;
2448 if (
const OGRField *max = OGR_RangeFldDomain_GetMax( domain, &maxIsInclusive ) )
2453 res = std::make_unique< QgsRangeFieldDomain >( name, description, fieldType, minValue, minIsInclusive, maxValue, maxIsInclusive );
2458 res = std::make_unique< QgsGlobFieldDomain >( name, description, fieldType, QString( OGR_GlobFldDomain_GetGlob( domain ) ) );
2462 switch ( OGR_FldDomain_GetMergePolicy( domain ) )
2464 case OFDMP_DEFAULT_VALUE:
2470 case OFDMP_GEOMETRY_WEIGHTED:
2475 switch ( OGR_FldDomain_GetSplitPolicy( domain ) )
2477 case OFDSP_DEFAULT_VALUE:
2480 case OFDSP_DUPLICATE:
2483 case OFDSP_GEOMETRY_RATIO:
2495 OGRFieldType domainFieldType = OFTInteger;
2496 OGRFieldSubType domainFieldSubType = OFSTNone;
2499 OGRFieldDomainH res =
nullptr;
2500 switch ( domain->
type() )
2504 std::vector< OGRCodedValue > enumeration;
2505 const QList< QgsCodedValue> values = qgis::down_cast< const QgsCodedFieldDomain * >( domain )->values();
2506 enumeration.reserve( values.size() );
2509 OGRCodedValue codedValue;
2510 codedValue.pszCode = CPLStrdup( value.code().toString().toUtf8().constData() );
2511 codedValue.pszValue = CPLStrdup( value.value().toUtf8().constData() );
2512 enumeration.push_back( codedValue );
2515 last.pszCode =
nullptr;
2516 last.pszValue =
nullptr;
2517 enumeration.push_back( last );
2518 res = OGR_CodedFldDomain_Create( domain->
name().toUtf8().constData(), domain->
description().toUtf8().constData(), domainFieldType, domainFieldSubType, enumeration.data() );
2520 for (
const OGRCodedValue &value : std::as_const( enumeration ) )
2522 CPLFree( value.pszCode );
2523 CPLFree( value.pszValue );
2530 std::unique_ptr< OGRField > min =
variantToOGRField( qgis::down_cast< const QgsRangeFieldDomain * >( domain )->minimum(), domainFieldType );
2531 std::unique_ptr< OGRField > max =
variantToOGRField( qgis::down_cast< const QgsRangeFieldDomain * >( domain )->maximum(), domainFieldType );
2534 res = OGR_RangeFldDomain_Create(
2535 domain->
name().toUtf8().constData(),
2540 qgis::down_cast< const QgsRangeFieldDomain * >( domain )->minimumIsInclusive(),
2542 qgis::down_cast< const QgsRangeFieldDomain * >( domain )->maximumIsInclusive()
2549 res = OGR_GlobFldDomain_Create(
2550 domain->
name().toUtf8().constData(),
2554 qgis::down_cast< const QgsGlobFieldDomain * >( domain )->glob().toUtf8().constData()
2563 OGR_FldDomain_SetMergePolicy( res, OFDMP_DEFAULT_VALUE );
2566 OGR_FldDomain_SetMergePolicy( res, OFDMP_GEOMETRY_WEIGHTED );
2569 OGR_FldDomain_SetMergePolicy( res, OFDMP_SUM );
2584 OGR_FldDomain_SetSplitPolicy( res, OFDSP_DEFAULT_VALUE );
2587 OGR_FldDomain_SetSplitPolicy( res, OFDSP_GEOMETRY_RATIO );
2590 OGR_FldDomain_SetSplitPolicy( res, OFDSP_DUPLICATE );
2603#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
2607 const QVariantMap datasetUriParts = ogrProviderMetadata->
decodeUri( datasetUri );
2609 const QString leftTableName( GDALRelationshipGetLeftTableName( relationship ) );
2611 QVariantMap leftTableUriParts = datasetUriParts;
2612 leftTableUriParts.insert( u
"layerName"_s, leftTableName );
2613 const QString leftTableSource = ogrProviderMetadata->
encodeUri( leftTableUriParts );
2615 const QString rightTableName( GDALRelationshipGetRightTableName( relationship ) );
2616 QVariantMap rightTableUriParts = datasetUriParts;
2617 rightTableUriParts.insert( u
"layerName"_s, rightTableName );
2618 const QString rightTableSource = ogrProviderMetadata->
encodeUri( rightTableUriParts );
2620 const QString mappingTableName( GDALRelationshipGetMappingTableName( relationship ) );
2621 QString mappingTableSource;
2622 if ( !mappingTableName.isEmpty() )
2624 QVariantMap mappingTableUriParts = datasetUriParts;
2625 mappingTableUriParts.insert( u
"layerName"_s, mappingTableName );
2626 mappingTableSource = ogrProviderMetadata->
encodeUri( mappingTableUriParts );
2629 const QString relationshipName( GDALRelationshipGetName( relationship ) );
2631 char **cslLeftTableFieldNames = GDALRelationshipGetLeftTableFields( relationship );
2633 CSLDestroy( cslLeftTableFieldNames );
2635 char **cslRightTableFieldNames = GDALRelationshipGetRightTableFields( relationship );
2637 CSLDestroy( cslRightTableFieldNames );
2639 char **cslLeftMappingTableFieldNames = GDALRelationshipGetLeftMappingTableFields( relationship );
2641 CSLDestroy( cslLeftMappingTableFieldNames );
2643 char **cslRightMappingTableFieldNames = GDALRelationshipGetRightMappingTableFields( relationship );
2645 CSLDestroy( cslRightMappingTableFieldNames );
2647 const QString forwardPathLabel( GDALRelationshipGetForwardPathLabel( relationship ) );
2648 const QString backwardPathLabel( GDALRelationshipGetBackwardPathLabel( relationship ) );
2649 const QString relatedTableType( GDALRelationshipGetRelatedTableType( relationship ) );
2651 const GDALRelationshipType relationshipType = GDALRelationshipGetType( relationship );
2653 switch ( relationshipType )
2659 case GRT_ASSOCIATION:
2663 case GRT_AGGREGATION:
2664 QgsLogger::warning(
"Aggregation relationships are not supported, treating as association instead" );
2668 const GDALRelationshipCardinality eCardinality = GDALRelationshipGetCardinality( relationship );
2670 switch ( eCardinality )
2672 case GRC_ONE_TO_ONE:
2675 case GRC_ONE_TO_MANY:
2678 case GRC_MANY_TO_ONE:
2681 case GRC_MANY_TO_MANY:
2686 switch ( cardinality )
2692 QgsWeakRelation rel( relationshipName, relationshipName, strength, QString(), QString(), rightTableSource, u
"ogr"_s, QString(), QString(), leftTableSource, u
"ogr"_s );
2704 QgsWeakRelation rel( relationshipName, relationshipName, strength, QString(), QString(), rightTableSource, u
"ogr"_s, QString(), QString(), leftTableSource, u
"ogr"_s );
2722 GDALRelationshipCardinality gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_MANY;
2726 gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_ONE;
2729 gCardinality = GDALRelationshipCardinality::GRC_ONE_TO_MANY;
2732 gCardinality = GDALRelationshipCardinality::GRC_MANY_TO_ONE;
2735 gCardinality = GDALRelationshipCardinality::GRC_MANY_TO_MANY;
2742 const QString leftTableName = leftParts.value( u
"layerName"_s ).toString();
2743 if ( leftTableName.isEmpty() )
2745 error = QObject::tr(
"Parent table name was not set" );
2750 const QString rightTableName = rightParts.value( u
"layerName"_s ).toString();
2751 if ( rightTableName.isEmpty() )
2753 error = QObject::tr(
"Child table name was not set" );
2757 if ( leftParts.value( u
"path"_s ).toString() != rightParts.value( u
"path"_s ).toString() )
2759 error = QObject::tr(
"Parent and child table must be from the same dataset" );
2763 QString mappingTableName;
2767 mappingTableName = mappingParts.value( u
"layerName"_s ).toString();
2768 if ( leftParts.value( u
"path"_s ).toString() != mappingParts.value( u
"path"_s ).toString() )
2770 error = QObject::tr(
"Parent and mapping table must be from the same dataset" );
2776 GDALRelationshipCreate( relationship.
name().toLocal8Bit().constData(), leftTableName.toLocal8Bit().constData(), rightTableName.toLocal8Bit().constData(), gCardinality )
2781 int count = leftFieldNames.count();
2782 char **lst =
nullptr;
2785 for (
const QString &
string : leftFieldNames )
2787 lst = CSLAddString( lst,
string.toLocal8Bit().constData() );
2790 GDALRelationshipSetLeftTableFields( relationH.get(), lst );
2795 count = rightFieldNames.count();
2799 for (
const QString &
string : rightFieldNames )
2801 lst = CSLAddString( lst,
string.toLocal8Bit().constData() );
2804 GDALRelationshipSetRightTableFields( relationH.get(), lst );
2807 if ( !mappingTableName.isEmpty() )
2809 GDALRelationshipSetMappingTableName( relationH.get(), mappingTableName.toLocal8Bit().constData() );
2813 int count = leftFieldNames.count();
2817 for (
const QString &
string : leftFieldNames )
2819 lst = CSLAddString( lst,
string.toLocal8Bit().constData() );
2822 GDALRelationshipSetLeftMappingTableFields( relationH.get(), lst );
2827 count = rightFieldNames.count();
2831 for (
const QString &
string : rightFieldNames )
2833 lst = CSLAddString( lst,
string.toLocal8Bit().constData() );
2836 GDALRelationshipSetRightMappingTableFields( relationH.get(), lst );
2844 GDALRelationshipSetType( relationH.get(), GDALRelationshipType::GRT_ASSOCIATION );
2848 GDALRelationshipSetType( relationH.get(), GDALRelationshipType::GRT_COMPOSITE );
2854 GDALRelationshipSetForwardPathLabel( relationH.get(), relationship.
forwardPathLabel().toLocal8Bit().constData() );
2856 GDALRelationshipSetBackwardPathLabel( relationH.get(), relationship.
backwardPathLabel().toLocal8Bit().constData() );
2860 GDALRelationshipSetRelatedTableType( relationH.get(), relationship.
relatedTableType().toLocal8Bit().constData() );
2868 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
2872 errCause = QObject::tr(
"No styles available on DB" );
2876 if ( OGR_L_GetFeatureCount( hLayer, TRUE ) == 0 )
2879 errCause = QObject::tr(
"No styles available on DB" );
2883 OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
2885 OGR_L_ResetReading( hLayer );
2887 QList<qlonglong> listTimestamp;
2888 QMap<int, QString> mapIdToStyleName;
2889 QMap<int, QString> mapIdToDescription;
2890 QMap<qlonglong, QList<int> > mapTimestampToId;
2891 int numberOfRelatedStyles = 0;
2899 QString tableName( QString::fromUtf8( OGR_F_GetFieldAsString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_table_name" ) ) ) );
2900 QString geometryColumn( QString::fromUtf8( OGR_F_GetFieldAsString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_geometry_column" ) ) ) );
2901 QString styleName( QString::fromUtf8( OGR_F_GetFieldAsString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleName" ) ) ) );
2902 QString description( QString::fromUtf8( OGR_F_GetFieldAsString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"description" ) ) ) );
2903 int fid =
static_cast<int>( OGR_F_GetFID( hFeature.get() ) );
2904 if ( tableName == layerName && geometryColumn == geomColumn )
2907 QString id( QString::number( fid ) );
2909 names.append( styleName );
2910 descriptions.append( description );
2911 ++numberOfRelatedStyles;
2915 int year, month, day, hour, minute, second, TZ;
2916 OGR_F_GetFieldAsDateTime( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"update_time" ), &year, &month, &day, &hour, &minute, &second, &TZ );
2917 const qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
static_cast<qlonglong
>( month ) * 31 * 24 * 3600 +
static_cast<qlonglong
>( year ) * 12 * 31 * 24 * 3600;
2919 listTimestamp.append( ts );
2920 mapIdToStyleName[fid] = styleName;
2921 mapIdToDescription[fid] = description;
2922 mapTimestampToId[ts].append( fid );
2926 std::sort( listTimestamp.begin(), listTimestamp.end() );
2928 for (
int i = listTimestamp.size() - 1; i >= 0; i-- )
2930 const QList<int> &listId = mapTimestampToId[listTimestamp[i]];
2931 for (
int j = 0; j < listId.size(); j++ )
2933 int fid = listId[j];
2934 QString id( QString::number( fid ) );
2936 names.append( mapIdToStyleName[fid] );
2937 descriptions.append( mapIdToDescription[fid] );
2941 return numberOfRelatedStyles;
2949 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
2953 const QString realStyleId = styleId.isEmpty() ? layerName : styleId;
2955 const QString checkQuery = QStringLiteral(
2957 " AND f_table_name=%1"
2958 " AND f_geometry_column=%2"
2961 .arg( QgsOgrProviderUtils::quotedValue( layerName ), QgsOgrProviderUtils::quotedValue( geomColumn ), QgsOgrProviderUtils::quotedValue( realStyleId ) );
2962 OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
2963 OGR_L_ResetReading( hLayer );
2965 OGR_L_ResetReading( hLayer );
2975 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
2979 errCause = QObject::tr(
"No styles available on DB" );
2984 int id = styleId.toInt( &ok );
2987 errCause = QObject::tr(
"Invalid style identifier" );
2994 errCause = QObject::tr(
"No style corresponding to style identifier" );
2998 OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
2999 QString styleQML( QString::fromUtf8( OGR_F_GetFieldAsString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleQML" ) ) ) );
3000 OGR_L_ResetReading( hLayer );
3009 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
3014 errCause = QObject::tr(
"Connection to database failed" );
3019 if ( OGR_L_DeleteFeature( hLayer, styleId.toInt() ) != OGRERR_NONE )
3021 errCause = QObject::tr(
"Error executing the delete query." );
3034 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
3038 errCause = QObject::tr(
"No styles available on DB" );
3042 QString selectQmlQuery = QStringLiteral(
3044 " AND f_table_name=%1"
3045 " AND f_geometry_column=%2"
3046 " ORDER BY CASE WHEN useAsDefault THEN 1 ELSE 2 END"
3049 .arg( QgsOgrProviderUtils::quotedValue( layerName ), QgsOgrProviderUtils::quotedValue( geomColumn ) );
3050 OGR_L_SetAttributeFilter( hLayer, selectQmlQuery.toUtf8().constData() );
3051 OGR_L_ResetReading( hLayer );
3052 OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
3054 qlonglong moreRecentTimestamp = 0;
3060 if ( OGR_F_GetFieldAsInteger( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"useAsDefault" ) ) )
3062 styleQML = QString::fromUtf8( OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleQML" ) ) );
3063 styleName = QString::fromUtf8( OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleName" ) ) );
3067 int year, month, day, hour, minute, second, TZ;
3068 OGR_F_GetFieldAsDateTime( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"update_time" ), &year, &month, &day, &hour, &minute, &second, &TZ );
3069 qlonglong ts = second + minute * 60 + hour * 3600 + day * 24 * 3600 +
static_cast<qlonglong
>( month ) * 31 * 24 * 3600 +
static_cast<qlonglong
>( year ) * 12 * 31 * 24 * 3600;
3070 if ( ts > moreRecentTimestamp )
3072 moreRecentTimestamp = ts;
3073 styleQML = QString::fromUtf8( OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleQML" ) ) );
3074 styleName = QString::fromUtf8( OGR_F_GetFieldAsString( hFeat.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleName" ) ) );
3077 OGR_L_ResetReading( hLayer );
3084 const QString &layerName,
3085 const QString &geomColumn,
3086 const QString &qmlStyle,
3087 const QString &sldStyle,
3088 const QString &styleName,
3089 const QString &styleDescription,
3090 const QString &uiFileContent,
3096 OGRLayerH hLayer = GDALDatasetGetLayerByName( hDS,
"layer_styles" );
3103 char **options =
nullptr;
3105 options = CSLSetNameValue( options,
"FID",
"id" );
3106 hLayer = GDALDatasetCreateLayer( hDS,
"layer_styles",
nullptr, wkbNone, options );
3107 QgsOgrProviderUtils::invalidateCachedDatasets( QString::fromUtf8( GDALGetDescription( hDS ) ) );
3108 CSLDestroy( options );
3111 errCause = QObject::tr(
"Unable to save layer style. It's not possible to create the destination table on the database." );
3117 OGR_Fld_SetWidth( fld.get(), 256 );
3118 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3122 OGR_Fld_SetWidth( fld.get(), 256 );
3123 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3127 OGR_Fld_SetWidth( fld.get(), 256 );
3128 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3132 OGR_Fld_SetWidth( fld.get(), 256 );
3133 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3137 OGR_Fld_SetWidth( fld.get(), 30 );
3138 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3142 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3146 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3150 OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
3151 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3155 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3159 OGR_Fld_SetWidth( fld.get(), 30 );
3160 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3164 OGR_Fld_SetWidth( fld.get(), 30 );
3165 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3169 OGR_Fld_SetDefault( fld.get(),
"CURRENT_TIMESTAMP" );
3170 ok &= OGR_L_CreateField( hLayer, fld.get(),
true ) == OGRERR_NONE;
3174 errCause = QObject::tr(
"Unable to save layer style. It's not possible to create the destination table on the database." );
3179 QString realStyleName = styleName.isEmpty() ? layerName : styleName;
3181 OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn( hLayer );
3185 QString oldDefaultQuery = QStringLiteral(
3186 "useAsDefault = 1 AND f_table_schema=''"
3187 " AND f_table_name=%1"
3188 " AND f_geometry_column=%2"
3190 .arg( QgsOgrProviderUtils::quotedValue( layerName ) )
3191 .arg( QgsOgrProviderUtils::quotedValue( geomColumn ) );
3192 OGR_L_SetAttributeFilter( hLayer, oldDefaultQuery.toUtf8().constData() );
3196 OGR_F_SetFieldInteger( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"useAsDefault" ), 0 );
3197 bool ok = OGR_L_SetFeature( hLayer, hFeature.get() ) == 0;
3200 QgsDebugError( u
"Could not unset previous useAsDefault style"_s );
3205 QString checkQuery = QStringLiteral(
3207 " AND f_table_name=%1"
3208 " AND f_geometry_column=%2"
3211 .arg( QgsOgrProviderUtils::quotedValue( layerName ) )
3212 .arg( QgsOgrProviderUtils::quotedValue( geomColumn ) )
3213 .arg( QgsOgrProviderUtils::quotedValue( realStyleName ) );
3214 OGR_L_SetAttributeFilter( hLayer, checkQuery.toUtf8().constData() );
3215 OGR_L_ResetReading( hLayer );
3217 OGR_L_ResetReading( hLayer );
3226 hFeature.reset( OGR_F_Create( hLayerDefn ) );
3227 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_table_catalog" ),
"" );
3228 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_table_schema" ),
"" );
3229 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_table_name" ), layerName.toUtf8().constData() );
3230 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"f_geometry_column" ), geomColumn.toUtf8().constData() );
3231 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleName" ), realStyleName.toUtf8().constData() );
3232 if ( !uiFileContent.isEmpty() )
3234 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"ui" ), uiFileContent.toUtf8().constData() );
3237 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleQML" ), qmlStyle.toUtf8().constData() );
3238 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"styleSLD" ), sldStyle.toUtf8().constData() );
3239 OGR_F_SetFieldInteger( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"useAsDefault" ), useAsDefault ? 1 : 0 );
3240 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"description" ), ( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ).toUtf8().constData() );
3241 OGR_F_SetFieldString( hFeature.get(), OGR_FD_GetFieldIndex( hLayerDefn,
"owner" ),
"" );
3245 bFeatureOK = OGR_L_CreateFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
3247 bFeatureOK = OGR_L_SetFeature( hLayer, hFeature.get() ) == OGRERR_NONE;
3252 errCause = QObject::tr(
"Error looking for style. The query was logged" );
RelationshipStrength
Relationship strength.
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
@ SetToNull
Use a null value.
@ GeometryWeighted
New values are computed as the weighted average of the source values.
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
@ LargestGeometry
Use value from the feature with the largest geometry.
@ DefaultValue
Use default field value.
@ MaximumValue
Use the maximum value from the features-to-be-merged.
@ MinimumValue
Use the minimum value from the features-to-be-merged.
@ GeometryRatio
New values are computed by the ratio of their area/length compared to the area/length of the original...
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
@ DefaultValue
Use default field value.
@ Duplicate
Duplicate original value.
MarkerShape
Marker shapes.
@ Cross2
Rotated cross (lines only), 'x' shape.
@ Cross
Cross (lines only).
RenderUnit
Rendering size units.
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes).
@ Coded
Coded field domain.
@ Range
Numeric range field domain (min/max).
@ Glob
Glob string pattern field domain.
RelationshipCardinality
Relationship cardinality.
@ ManyToMany
Many to many relationship.
@ ManyToOne
Many to one relationship.
@ OneToOne
One to one relationship.
@ OneToMany
One to many relationship.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ MultiSurfaceM
MultiSurfaceM.
@ PolyhedralSurfaceM
PolyhedralSurfaceM.
@ MultiLineStringZM
MultiLineStringZM.
@ MultiPointZM
MultiPointZM.
@ MultiPointZ
MultiPointZ.
@ CompoundCurve
CompoundCurve.
@ MultiPolygonZM
MultiPolygonZM.
@ LineStringM
LineStringM.
@ MultiLineStringM
MultiLineStringM.
@ NurbsCurveM
NurbsCurveM.
@ MultiPolygon25D
MultiPolygon25D.
@ MultiPointM
MultiPointM.
@ LineStringZM
LineStringZM.
@ GeometryCollectionZM
GeometryCollectionZM.
@ CompoundCurveZM
CompoundCurveZM.
@ CompoundCurveM
CompoundCurveM.
@ MultiLineString25D
MultiLineString25D.
@ MultiPolygon
MultiPolygon.
@ GeometryCollectionZ
GeometryCollectionZ.
@ GeometryCollectionM
GeometryCollectionM.
@ CircularStringZM
CircularStringZM.
@ MultiSurfaceZ
MultiSurfaceZ.
@ CurvePolygonZM
CurvePolygonZM.
@ MultiLineString
MultiLineString.
@ MultiPolygonM
MultiPolygonM.
@ MultiCurveZM
MultiCurveZM.
@ MultiSurfaceZM
MultiSurfaceZM.
@ MultiPoint25D
MultiPoint25D.
@ NurbsCurveZ
NurbsCurveZ.
@ CurvePolygonM
CurvePolygonM.
@ NurbsCurveZM
NurbsCurveZM.
@ CircularString
CircularString.
@ MultiLineStringZ
MultiLineStringZ.
@ GeometryCollection
GeometryCollection.
@ PolyhedralSurfaceZM
PolyhedralSurfaceM.
@ MultiPolygonZ
MultiPolygonZ.
@ CurvePolygonZ
CurvePolygonZ.
@ CompoundCurveZ
CompoundCurveZ.
@ MultiCurveZ
MultiCurveZ.
@ MultiCurveM
MultiCurveM.
@ PolyhedralSurfaceZ
PolyhedralSurfaceZ.
@ CircularStringM
CircularStringM.
@ CurvePolygon
CurvePolygon.
@ CircularStringZ
CircularStringZ.
@ LineStringZ
LineStringZ.
@ PolyhedralSurface
PolyhedralSurface.
@ MultiSurface
MultiSurface.
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
static endian_t endian()
Returns whether this machine uses big or little endian.
Associates a code and a value.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
void setCoordinateEpoch(double epoch)
Sets the coordinate epoch, as a decimal year.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
double coordinateEpoch() const
Returns the coordinate epoch, as a decimal year.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setId(QgsFeatureId id)
Sets the feature id for this feature.
void clearGeometry()
Removes any geometry associated with the feature.
void setValid(bool validity)
Sets the validity of the feature.
bool isValid() const
Returns the validity of this feature.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for field domains.
Qgis::FieldDomainMergePolicy mergePolicy() const
Returns the merge policy.
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the split policy.
QMetaType::Type fieldType() const
Returns the associated field type.
virtual Qgis::FieldDomainType type() const =0
Returns the type of field domain.
QString name() const
Returns the name of the field domain.
QString description() const
Returns the description of the field domain.
Encapsulate a field in an attribute table or data source.
QString typeName() const
Gets the field type.
QMetaType::Type subType() const
If the field is a collection, gets its element's type.
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Abstract base class for fill symbol layers.
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
A geometry is the spatial representation of a feature.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
static QVariant jsonToVariant(const json &value)
Converts a JSON value to a QVariant, in case of parsing error an invalid QVariant is returned.
Abstract base class for line symbol layers.
static void warning(const QString &msg)
Goes to qWarning.
Context for a MapInfo symbol conversion operation.
static QgsFillSymbol * convertFillSymbol(int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &foreColor, const QColor &backColor=QColor())
Converts the MapInfo fill symbol with the specified identifier to a QgsFillSymbol.
static QgsMarkerSymbol * convertMarkerSymbol(int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &color, double size, Qgis::RenderUnit sizeUnit)
Converts the MapInfo marker symbol with the specified identifier to a QgsMarkerSymbol.
static QgsLineSymbol * convertLineSymbol(int identifier, QgsMapInfoSymbolConversionContext &context, const QColor &foreColor, double size, Qgis::RenderUnit sizeUnit, bool interleaved=false)
Converts the MapInfo line symbol with the specified identifier to a QgsLineSymbol.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static QString readShapefileEncoding(const QString &path)
Reads the encoding of the shapefile at the specified path (where path is the location of the "....
static QgsWeakRelation convertRelationship(GDALRelationshipH relationship, const QString &datasetUri)
Converts an GDAL relationship definition to a QgsWeakRelation equivalent.
static QVariant stringToVariant(OGRFieldType type, OGRFieldSubType subType, const QString &string)
Converts a string to a variant, using the provider OGR field type and subType to determine the most a...
static bool readOgrFeatureAttributes(OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding)
Reads all attributes from an OGR feature into a QgsFeature.
static QString loadStoredStyle(GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, QString &styleName, QString &errCause)
Helper function for loading a stored styles in ogr/gdal database datasources.
static QString getStyleById(GDALDatasetH hDS, const QString &styleId, QString &errCause)
Helper function for getting a style by ID from ogr/gdal database datasources.
static Qgis::WkbType ogrGeometryTypeToQgsWkbType(OGRwkbGeometryType ogrGeomType)
Converts a OGRwkbGeometryType to QgsWkbTypes::Type.
static int listStyles(GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Helper function for listing styles in ogr/gdal database datasources.
static QgsGeometry ogrGeometryToQgsGeometry(OGRGeometryH geom)
Converts an OGR geometry representation to a QgsGeometry object.
static QString OGRSpatialReferenceToWkt(OGRSpatialReferenceH srs)
Returns a WKT string corresponding to the specified OGR srs object.
static OGRSpatialReferenceH crsToOGRSpatialReference(const QgsCoordinateReferenceSystem &crs)
Returns a OGRSpatialReferenceH corresponding to the specified crs object.
static bool saveStyle(GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, const QString &qmlStyle, const QString &sldStyle, const QString &styleName, const QString &styleDescription, const QString &uiFileContent, bool useAsDefault, QString &errCause)
Helper function for saving a style to ogr/gdal database datasources.
static bool styleExists(GDALDatasetH hDS, const QString &layerName, const QString &geomColumn, const QString &styleId, QString &errorCause)
Helper function for checking whether a style exists in ogr/gdal database datasources.
static QVariant OGRFieldtoVariant(const OGRField *value, OGRFieldType type)
Converts an OGRField value of the specified type into a QVariant.
static QStringList cStringListToQStringList(const char *const *stringList)
Converts a c string list to a QStringList.
static QgsFeature readOgrFeature(OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding)
Reads an OGR feature and converts it to a QgsFeature.
static void ogrFieldTypeToQVariantType(OGRFieldType ogrType, OGRFieldSubType ogrSubType, QMetaType::Type &variantType, QMetaType::Type &variantSubType)
Converts an OGR field type and sub type to the best matching QVariant::Type equivalent.
static QgsFields readOgrFields(OGRFeatureH ogrFet, QTextCodec *encoding)
Reads an OGR feature and returns a corresponding fields collection.
static QList< QgsVectorDataProvider::NativeType > nativeFieldTypesForDriver(GDALDriverH driver)
Returns the list of native field types supported for a driver.
static std::unique_ptr< QgsFieldDomain > convertFieldDomain(OGRFieldDomainH domain)
Converts an OGR field domain definition to a QgsFieldDomain equivalent.
static QgsCoordinateReferenceSystem OGRSpatialReferenceToCrs(OGRSpatialReferenceH srs)
Returns a QgsCoordinateReferenceSystem corresponding to the specified OGR srs object,...
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
static OGRwkbGeometryType qgsWkbTypeToOgrGeometryType(Qgis::WkbType wkbType, bool approx=false)
Converts a QgsWkbTypes::Type to a OGRwkbGeometryType.
static QString readShapefileEncodingFromCpg(const QString &path)
Reads the encoding of the shapefile at the specified path (where path is the location of the "....
static bool readOgrFeatureGeometry(OGRFeatureH ogrFet, QgsFeature &feature)
Reads the geometry from an OGR feature into a QgsFeature.
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR.
static QString readShapefileEncodingFromLdid(const QString &path)
Reads the encoding of the shapefile at the specified path (where path is the location of the "....
static std::unique_ptr< QgsSymbol > symbolFromStyleString(const QString &string, Qgis::SymbolType type)
Creates a new QgsSymbol matching an OGR style string.
static std::unique_ptr< OGRField > variantToOGRField(const QVariant &value, OGRFieldType type)
Converts a QVariant to an OGRField value of specified type.
static bool deleteStyleById(GDALDatasetH hDS, const QString &styleId, QString &errCause)
Helper function for deleting a style by id from ogr/gdal database datasources.
static void variantTypeToOgrFieldType(QMetaType::Type variantType, OGRFieldType &ogrType, OGRFieldSubType &ogrSubType)
Converts an QVariant type to the best matching OGR field type and sub type.
static QVariantMap parseStyleString(const QString &string)
Parses an OGR style string to a variant map containing the style string components.
static int OGRTZFlagFromQt(const QDateTime &datetime)
Gets the value of OGRField::Date::TZFlag from the timezone of a QDateTime.
static QVariant getOgrFeatureAttribute(OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok=nullptr)
Retrieves an attribute value from an OGR feature.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
static bool shapeIsFilled(Qgis::MarkerShape shape)
Returns true if a symbol shape has a fill.
Contains utility functions for working with symbols and symbol layers.
static QString typeToDisplayString(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
Represent a QgsRelation with possibly unresolved layers or unmatched fields.
void setMappingTable(const QgsVectorLayerRef &table)
Sets a weak reference to the mapping table, which forms the middle table in many-to-many relationship...
QStringList mappingReferencingLayerFields() const
Returns the list of fields from the mappingTable() involved in the relationship.
void setForwardPathLabel(const QString &label)
Sets the label of the forward path for the relationship.
QString mappingTableSource() const
Returns the source URI for the mapping table, which forms the middle table in many-to-many relationsh...
void setMappingReferencingLayerFields(const QStringList &fields)
Sets the list of fields from the mappingTable() involved in the relationship.
void setBackwardPathLabel(const QString &label)
Sets the label of the backward path for the relationship.
QString relatedTableType() const
Returns the type string of the related table.
void setReferencingLayerFields(const QStringList &fields)
Sets the list of fields from the referencingLayer() involved in the relationship.
QString name() const
Returns the relationship's name.
QString backwardPathLabel() const
Returns the label of the backward path for the relationship.
void setMappingReferencedLayerFields(const QStringList &fields)
Sets the list of fields from the mappingTable() involved in the relationship.
QString referencedLayerSource() const
Returns the source URI for the referenced (or "parent" / "left") layer.
QString referencingLayerSource() const
Returns the source URI for the referencing (or "child" / "right") layer.
QString forwardPathLabel() const
Returns the label of the forward path for the relationship.
Qgis::RelationshipCardinality cardinality() const
Returns the relationship's cardinality.
void setCardinality(Qgis::RelationshipCardinality cardinality)
Sets the relationship's cardinality.
QStringList referencedLayerFields() const
Returns the list of fields from the referencedLayer() involved in the relationship.
QStringList mappingReferencedLayerFields() const
Returns the list of fields from the mappingTable() involved in the relationship.
void setRelatedTableType(const QString &type)
Sets the type string of the related table.
QStringList referencingLayerFields() const
Returns the list of fields from the referencingLayer() involved in the relationship.
void setReferencedLayerFields(const QStringList &fields)
Sets the list of fields from the referencedLayer() involved in the relationship.
Qgis::RelationshipStrength strength() const
Returns the strength of the relation.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
void CORE_EXPORT fast_delete_and_close(dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path)
Performs a fast close of an unwanted GDAL dataset handle by deleting the underlying data store.
std::unique_ptr< std::remove_pointer< OGRFeatureH >::type, OGRFeatureDeleter > ogr_feature_unique_ptr
Scoped OGR feature.
std::unique_ptr< std::remove_pointer< GDALRelationshipH >::type, GDALRelationshipDeleter > relationship_unique_ptr
Scoped GDAL relationship.
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.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
QList< QgsFeature > QgsFeatureList
#define DEFAULT_SIMPLELINE_WIDTH
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define DEFAULT_SIMPLEMARKER_SIZE
std::unique_ptr< QgsLineString > ogrGeometryToQgsLineString(OGRGeometryH geom)
std::unique_ptr< QgsMultiLineString > ogrGeometryToQgsMultiLineString(OGRGeometryH geom)
std::unique_ptr< QgsPolyhedralSurface > ogrGeometryToQgsPolyhedralSurface(OGRGeometryH geom)
std::unique_ptr< QgsMultiPoint > ogrGeometryToQgsMultiPoint(OGRGeometryH geom)
std::unique_ptr< QgsPolygon > ogrGeometryToQgsPolygon(OGRGeometryH geom)
std::unique_ptr< QgsPoint > ogrGeometryToQgsPoint(OGRGeometryH geom)
std::unique_ptr< QgsMultiPolygon > ogrGeometryToQgsMultiPolygon(OGRGeometryH geom)
QList< QgsSymbolLayer * > QgsSymbolLayerList
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
void CORE_EXPORT operator()(GDALDatasetH datasource) const
Destroys an gdal dataset, using the correct gdal calls.
void CORE_EXPORT operator()(GDALRelationshipH relationship) const
Destroys GDAL relationship, using the correct gdal calls.
void CORE_EXPORT operator()(GDALWarpOptions *options) const
Destroys GDAL warp options, using the correct gdal calls.
void CORE_EXPORT operator()(OGRDataSourceH source) const
Destroys an OGR data source, using the correct gdal calls.
void CORE_EXPORT operator()(OGRFeatureH feature) const
Destroys an OGR feature, using the correct gdal calls.
void CORE_EXPORT operator()(OGRFieldDefnH definition) const
Destroys an OGR field definition, using the correct gdal calls.
void CORE_EXPORT operator()(OGRGeometryH geometry) const
Destroys an OGR geometry, using the correct gdal calls.