508 if ( !ogrFet || attIndex < 0 )
515 OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
522 QgsDebugMsg( QStringLiteral(
"ogrFet->GetFieldDefnRef(attindex) returns NULL" ) );
531 if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
535 case QVariant::String:
538 value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
540 value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
545 if ( value.isNull() )
546 value = QVariant( QStringLiteral(
"" ) );
552 value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
555 value = QVariant(
bool( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ) );
557 case QVariant::LongLong:
558 value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
560 case QVariant::Double:
561 value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
564 case QVariant::DateTime:
567 int year, month, day, hour, minute, tzf;
569 float secondsPart = 0;
571 OGR_F_GetFieldAsDateTimeEx( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
572 float millisecondPart = std::modf( second, &secondsPart );
575 value = QDate( year, month, day );
576 else if (
field.
type() == QVariant::Time )
577 value = QTime( hour, minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) );
580 QDateTime dt = QDateTime( QDate( year, month, day ),
581 QTime( hour, minute,
static_cast< int >( secondsPart ),
static_cast< int >( std::round( 1000 * millisecondPart ) ) ) );
582 setQTTimeZoneFromOGRTZFlag( dt, tzf );
588 case QVariant::ByteArray:
591 const GByte *b = OGR_F_GetFieldAsBinary( ogrFet, attIndex, &size );
595 QByteArray ba = QByteArray::fromRawData(
reinterpret_cast<const char *
>( b ), size );
602 case QVariant::StringList:
605 char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
606 const int count = CSLCount( lst );
609 list.reserve( count );
610 for (
int i = 0; i < count; i++ )
613 list << encoding->toUnicode( lst[i] );
615 list << QString::fromUtf8( lst[i] );
626 case QVariant::String:
629 char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
630 const int count = CSLCount( lst );
633 list.reserve( count );
634 for (
int i = 0; i < count; i++ )
637 list << encoding->toUnicode( lst[i] );
639 list << QString::fromUtf8( lst[i] );
650 const int *lst = OGR_F_GetFieldAsIntegerList( ogrFet, attIndex, &count );
653 list.reserve( count );
654 for (
int i = 0; i < count; i++ )
663 case QVariant::Double:
667 const double *lst = OGR_F_GetFieldAsDoubleList( ogrFet, attIndex, &count );
670 list.reserve( count );
671 for (
int i = 0; i < count; i++ )
680 case QVariant::LongLong:
684 const long long *lst = OGR_F_GetFieldAsInteger64List( ogrFet, attIndex, &count );
687 list.reserve( count );
688 for (
int i = 0; i < count; i++ )
699 Q_ASSERT_X(
false,
"QgsOgrUtils::getOgrFeatureAttribute",
"unsupported field type" );
713 value = QJsonDocument::fromJson( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
715 value = QJsonDocument::fromJson( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
719 Q_ASSERT_X(
false,
"QgsOgrUtils::getOgrFeatureAttribute",
"unsupported field type" );
1353 const QVariantMap styles = parseStyleString(
string );
1357 const thread_local QRegularExpression sUnitRx = QRegularExpression( QStringLiteral(
"^([\\d\\.]+)(g|px|pt|mm|cm|in)$" ) );
1358 const QRegularExpressionMatch match = sUnitRx.match( size );
1359 if ( match.hasMatch() )
1361 value = match.captured( 1 ).toDouble();
1362 const QString unitString = match.captured( 2 );
1363 if ( unitString.compare( QLatin1String(
"px" ), Qt::CaseInsensitive ) == 0 )
1367 static constexpr double PT_TO_INCHES_FACTOR = 1 / 72.0;
1368 static constexpr double PX_TO_PT_FACTOR = 1 / ( 96.0 * PT_TO_INCHES_FACTOR );
1370 value *= PX_TO_PT_FACTOR;
1373 else if ( unitString.compare( QLatin1String(
"pt" ), Qt::CaseInsensitive ) == 0 )
1378 else if ( unitString.compare( QLatin1String(
"mm" ), Qt::CaseInsensitive ) == 0 )
1383 else if ( unitString.compare( QLatin1String(
"cm" ), Qt::CaseInsensitive ) == 0 )
1389 else if ( unitString.compare( QLatin1String(
"in" ), Qt::CaseInsensitive ) == 0 )
1394 else if ( unitString.compare( QLatin1String(
"g" ), Qt::CaseInsensitive ) == 0 )
1399 QgsDebugMsg( QStringLiteral(
"Unknown unit %1" ).arg( unitString ) );
1403 QgsDebugMsg( QStringLiteral(
"Could not parse style size %1" ).arg( size ) );
1408 auto convertColor = [](
const QString & string ) -> QColor
1410 if (
string.isEmpty() )
1413 const thread_local QRegularExpression sColorWithAlphaRx = QRegularExpression( QStringLiteral(
"^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})$" ) );
1414 const QRegularExpressionMatch match = sColorWithAlphaRx.match(
string );
1415 if ( match.hasMatch() )
1418 return QColor( QStringLiteral(
"#%1%2" ).arg( match.captured( 2 ), match.captured( 1 ) ) );
1422 return QColor(
string );
1426 auto convertPen = [&convertColor, &convertSize, string](
const QVariantMap & lineStyle ) -> std::unique_ptr< QgsSymbol >
1428 QColor color = convertColor( lineStyle.value( QStringLiteral(
"c" ), QStringLiteral(
"#000000" ) ).toString() );
1432 convertSize( lineStyle.value( QStringLiteral(
"w" ) ).toString(), lineWidth, lineWidthUnit );
1435 const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral(
"mapinfo-pen-(\\d+)" ) );
1436 const QRegularExpressionMatch match = sMapInfoId.match(
string );
1437 if ( match.hasMatch() )
1439 const int penId = match.captured( 1 ).toInt();
1446 std::unique_ptr< QgsSimpleLineSymbolLayer > simpleLine = std::make_unique< QgsSimpleLineSymbolLayer >( color, lineWidth );
1447 simpleLine->setWidthUnit( lineWidthUnit );
1450 const QString pattern = lineStyle.value( QStringLiteral(
"p" ) ).toString();
1451 if ( !pattern.isEmpty() )
1453 const thread_local QRegularExpression sPatternUnitRx = QRegularExpression( QStringLiteral(
"^([\\d\\.\\s]+)(g|px|pt|mm|cm|in)$" ) );
1454 const QRegularExpressionMatch match = sPatternUnitRx.match( pattern );
1455 if ( match.hasMatch() )
1457 const QStringList patternValues = match.captured( 1 ).split(
' ' );
1458 QVector< qreal > dashPattern;
1460 for (
const QString &val : patternValues )
1463 convertSize( val + match.captured( 2 ), length, patternUnits );
1464 dashPattern.push_back( length * lineWidth * 2 );
1467 simpleLine->setCustomDashVector( dashPattern );
1468 simpleLine->setCustomDashPatternUnit( patternUnits );
1469 simpleLine->setUseCustomDashPattern(
true );
1473 Qt::PenCapStyle capStyle = Qt::FlatCap;
1474 Qt::PenJoinStyle joinStyle = Qt::MiterJoin;
1476 const QString
id = lineStyle.value( QStringLiteral(
"id" ) ).toString();
1477 if (
id.contains( QLatin1String(
"mapinfo-pen" ), Qt::CaseInsensitive ) )
1482 capStyle = Qt::RoundCap;
1483 joinStyle = Qt::RoundJoin;
1487 const QString penCap = lineStyle.value( QStringLiteral(
"cap" ) ).toString();
1488 if ( penCap.compare( QLatin1String(
"b" ), Qt::CaseInsensitive ) == 0 )
1490 capStyle = Qt::FlatCap;
1492 else if ( penCap.compare( QLatin1String(
"r" ), Qt::CaseInsensitive ) == 0 )
1494 capStyle = Qt::RoundCap;
1496 else if ( penCap.compare( QLatin1String(
"p" ), Qt::CaseInsensitive ) == 0 )
1498 capStyle = Qt::SquareCap;
1500 simpleLine->setPenCapStyle( capStyle );
1503 const QString penJoin = lineStyle.value( QStringLiteral(
"j" ) ).toString();
1504 if ( penJoin.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0 )
1506 joinStyle = Qt::MiterJoin;
1508 else if ( penJoin.compare( QLatin1String(
"r" ), Qt::CaseInsensitive ) == 0 )
1510 joinStyle = Qt::RoundJoin;
1512 else if ( penJoin.compare( QLatin1String(
"b" ), Qt::CaseInsensitive ) == 0 )
1514 joinStyle = Qt::BevelJoin;
1516 simpleLine->setPenJoinStyle( joinStyle );
1518 const QString priority = lineStyle.value( QStringLiteral(
"l" ) ).toString();
1519 if ( !priority.isEmpty() )
1521 simpleLine->setRenderingPass( priority.toInt() );
1523 return std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << simpleLine.release() );
1526 auto convertBrush = [&convertColor](
const QVariantMap & brushStyle ) -> std::unique_ptr< QgsSymbol >
1528 const QColor foreColor = convertColor( brushStyle.value( QStringLiteral(
"fc" ), QStringLiteral(
"#000000" ) ).toString() );
1529 const QColor backColor = convertColor( brushStyle.value( QStringLiteral(
"bc" ), QString() ).toString() );
1531 const QString
id = brushStyle.value( QStringLiteral(
"id" ) ).toString();
1534 const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral(
"mapinfo-brush-(\\d+)" ) );
1535 const QRegularExpressionMatch match = sMapInfoId.match(
id );
1536 if ( match.hasMatch() )
1538 const int brushId = match.captured( 1 ).toInt();
1545 const thread_local QRegularExpression sOgrId = QRegularExpression( QStringLiteral(
"ogr-brush-(\\d+)" ) );
1546 const QRegularExpressionMatch ogrMatch = sOgrId.match(
id );
1548 Qt::BrushStyle style = Qt::SolidPattern;
1549 if ( ogrMatch.hasMatch() )
1551 const int brushId = ogrMatch.captured( 1 ).toInt();
1555 style = Qt::SolidPattern;
1559 style = Qt::NoBrush;
1563 style = Qt::HorPattern;
1567 style = Qt::VerPattern;
1571 style = Qt::FDiagPattern;
1575 style = Qt::BDiagPattern;
1579 style = Qt::CrossPattern;
1583 style = Qt::DiagCrossPattern;
1589 if ( backColor.isValid() && style != Qt::SolidPattern && style != Qt::NoBrush )
1591 std::unique_ptr< QgsSimpleFillSymbolLayer > backgroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( backColor );
1592 backgroundFill->setLocked(
true );
1593 backgroundFill->setStrokeStyle( Qt::NoPen );
1594 layers << backgroundFill.release();
1597 std::unique_ptr< QgsSimpleFillSymbolLayer > foregroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( foreColor );
1598 foregroundFill->setBrushStyle( style );
1599 foregroundFill->setStrokeStyle( Qt::NoPen );
1601 const QString priority = brushStyle.value( QStringLiteral(
"l" ) ).toString();
1602 if ( !priority.isEmpty() )
1604 foregroundFill->setRenderingPass( priority.toInt() );
1606 layers << foregroundFill.release();
1607 return std::make_unique< QgsFillSymbol >( layers );
1610 auto convertSymbol = [&convertColor, &convertSize, string](
const QVariantMap & symbolStyle ) -> std::unique_ptr< QgsSymbol >
1612 const QColor color = convertColor( symbolStyle.value( QStringLiteral(
"c" ), QStringLiteral(
"#000000" ) ).toString() );
1616 convertSize( symbolStyle.value( QStringLiteral(
"s" ) ).toString(), symbolSize, symbolSizeUnit );
1618 const double angle = symbolStyle.value( QStringLiteral(
"a" ), QStringLiteral(
"0" ) ).toDouble();
1620 const QString
id = symbolStyle.value( QStringLiteral(
"id" ) ).toString();
1623 const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral(
"mapinfo-sym-(\\d+)" ) );
1624 const QRegularExpressionMatch match = sMapInfoId.match(
id );
1625 if ( match.hasMatch() )
1627 const int symbolId = match.captured( 1 ).toInt();
1638 std::unique_ptr< QgsMarkerSymbolLayer > markerLayer;
1640 const thread_local QRegularExpression sFontId = QRegularExpression( QStringLiteral(
"font-sym-(\\d+)" ) );
1641 const QRegularExpressionMatch fontMatch = sFontId.match(
id );
1642 if ( fontMatch.hasMatch() )
1644 const int symId = fontMatch.captured( 1 ).toInt();
1645 const QStringList families = symbolStyle.value( QStringLiteral(
"f" ), QString() ).toString().split(
',' );
1647 bool familyFound =
false;
1650 for (
const QString &family : std::as_const( families ) )
1658 fontFamily = processedFamily;
1665 std::unique_ptr< QgsFontMarkerSymbolLayer > fontMarker = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, QChar( symId ), symbolSize );
1666 fontMarker->setSizeUnit( symbolSizeUnit );
1667 fontMarker->setAngle( -angle );
1669 fontMarker->setColor( color );
1671 const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral(
"o" ), QString() ).toString() );
1672 if ( strokeColor.isValid() )
1674 fontMarker->setStrokeColor( strokeColor );
1675 fontMarker->setStrokeWidth( 1 );
1680 fontMarker->setStrokeWidth( 0 );
1683 markerLayer = std::move( fontMarker );
1685 else if ( !families.empty() )
1694 const thread_local QRegularExpression sOgrId = QRegularExpression( QStringLiteral(
"ogr-sym-(\\d+)" ) );
1695 const QRegularExpressionMatch ogrMatch = sOgrId.match(
id );
1698 bool isFilled =
true;
1699 if ( ogrMatch.hasMatch() )
1701 const int symId = ogrMatch.captured( 1 ).toInt();
1764 std::unique_ptr< QgsSimpleMarkerSymbolLayer > simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, symbolSize, -angle );
1765 simpleMarker->setSizeUnit( symbolSizeUnit );
1769 simpleMarker->setColor( color );
1770 simpleMarker->setStrokeStyle( Qt::NoPen );
1774 simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
1775 simpleMarker->setStrokeColor( color );
1778 const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral(
"o" ), QString() ).toString() );
1779 if ( strokeColor.isValid() )
1781 simpleMarker->setStrokeColor( strokeColor );
1782 simpleMarker->setStrokeStyle( Qt::SolidLine );
1785 markerLayer = std::move( simpleMarker );
1788 return std::make_unique< QgsMarkerSymbol >(
QgsSymbolLayerList() << markerLayer.release() );
1794 if ( styles.contains( QStringLiteral(
"symbol" ) ) )
1796 const QVariantMap symbolStyle = styles.value( QStringLiteral(
"symbol" ) ).toMap();
1797 return convertSymbol( symbolStyle );
1805 if ( styles.contains( QStringLiteral(
"pen" ) ) )
1808 const QVariantMap lineStyle = styles.value( QStringLiteral(
"pen" ) ).toMap();
1809 return convertPen( lineStyle );
1818 std::unique_ptr< QgsSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
1819 if ( styles.contains( QStringLiteral(
"brush" ) ) )
1821 const QVariantMap brushStyle = styles.value( QStringLiteral(
"brush" ) ).toMap();
1822 fillSymbol = convertBrush( brushStyle );
1826 std::unique_ptr< QgsSimpleFillSymbolLayer > emptyFill = std::make_unique< QgsSimpleFillSymbolLayer >();
1827 emptyFill->setBrushStyle( Qt::NoBrush );
1828 fillSymbol = std::make_unique< QgsFillSymbol >(
QgsSymbolLayerList() << emptyFill.release() );
1831 std::unique_ptr< QgsSymbol > penSymbol;
1832 if ( styles.contains( QStringLiteral(
"pen" ) ) )
1834 const QVariantMap lineStyle = styles.value( QStringLiteral(
"pen" ) ).toMap();
1835 penSymbol = convertPen( lineStyle );
1840 const int count = penSymbol->symbolLayerCount();
1850 for (
int i = 0; i < count; ++i )
1852 std::unique_ptr< QgsSymbolLayer > layer( penSymbol->takeSymbolLayer( 0 ) );
1853 layer->setLocked(
true );
1854 fillSymbol->appendSymbolLayer( layer.release() );
2052 const QString driverName = QString::fromUtf8( GDALGetDriverShortName( driver ) );
2054 int nMaxIntLen = 11;
2055 int nMaxInt64Len = 21;
2056 int nMaxDoubleLen = 20;
2057 int nMaxDoublePrec = 15;
2059 if ( driverName == QLatin1String(
"GPKG" ) )
2069 QList<QgsVectorDataProvider::NativeType> nativeTypes;
2073 <<
QgsVectorDataProvider::NativeType( QObject::tr(
"Decimal number (real)" ), QStringLiteral(
"double" ), QVariant::Double, 0, nMaxDoubleLen, 0, nMaxDoublePrec )
2076 if ( driverName == QLatin1String(
"GPKG" ) )
2079 bool supportsDate =
true;
2080 bool supportsTime =
true;
2081 bool supportsDateTime =
true;
2082 bool supportsBinary =
false;
2083 bool supportIntegerList =
false;
2084 bool supportInteger64List =
false;
2085 bool supportRealList =
false;
2086 bool supportsStringList =
false;
2090 if (
const char *pszDataTypes = GDALGetMetadataItem( driver, GDAL_DMD_CREATIONFIELDDATATYPES,
nullptr ) )
2092 char **papszTokens = CSLTokenizeString2( pszDataTypes,
" ", 0 );
2093 supportsDate = CSLFindString( papszTokens,
"Date" ) >= 0;
2094 supportsTime = CSLFindString( papszTokens,
"Time" ) >= 0;
2095 supportsDateTime = CSLFindString( papszTokens,
"DateTime" ) >= 0;
2096 supportsBinary = CSLFindString( papszTokens,
"Binary" ) >= 0;
2097 supportIntegerList = CSLFindString( papszTokens,
"IntegerList" ) >= 0;
2098 supportInteger64List = CSLFindString( papszTokens,
"Integer64List" ) >= 0;
2099 supportRealList = CSLFindString( papszTokens,
"RealList" ) >= 0;
2100 supportsStringList = CSLFindString( papszTokens,
"StringList" ) >= 0;
2101 CSLDestroy( papszTokens );
2106#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
2107 if ( driverName == QLatin1String(
"ESRI Shapefile" ) )
2109 supportsDateTime =
false;
2123 if ( supportsDateTime )
2128 if ( supportsBinary )
2133 if ( supportIntegerList )
2138 if ( supportInteger64List )
2143 if ( supportRealList )
2148 if ( supportsStringList )
2154 const char *pszDataSubTypes = GDALGetMetadataItem( driver, GDAL_DMD_CREATIONFIELDDATASUBTYPES,
nullptr );
2155 if ( pszDataSubTypes && strstr( pszDataSubTypes,
"Boolean" ) )
2172 const QString name{ OGR_FldDomain_GetName( domain ) };
2173 const QString description{ OGR_FldDomain_GetDescription( domain ) };
2175 QVariant::Type fieldType = QVariant::Type::Invalid;
2176 QVariant::Type fieldSubType = QVariant::Type::Invalid;
2177 const OGRFieldType domainFieldType = OGR_FldDomain_GetFieldType( domain );
2178 const OGRFieldSubType domainFieldSubType = OGR_FldDomain_GetFieldSubType( domain );
2179 ogrFieldTypeToQVariantType( domainFieldType, domainFieldSubType, fieldType, fieldSubType );
2181 std::unique_ptr< QgsFieldDomain > res;
2182 switch ( OGR_FldDomain_GetDomainType( domain ) )
2186 QList< QgsCodedValue > values;
2187 const OGRCodedValue *codedValue = OGR_CodedFldDomain_GetEnumeration( domain );
2188 while ( codedValue && codedValue->pszCode )
2190 const QString code( codedValue->pszCode );
2195 const QString value( codedValue->pszValue ? codedValue->pszValue : codedValue->pszCode );
2196 values.append(
QgsCodedValue( stringToVariant( domainFieldType, domainFieldSubType, code ), value ) );
2201 res = std::make_unique< QgsCodedFieldDomain >( name, description, fieldType, values );
2208 bool minIsInclusive =
false;
2209 if (
const OGRField *min = OGR_RangeFldDomain_GetMin( domain, &minIsInclusive ) )
2214 bool maxIsInclusive =
false;
2215 if (
const OGRField *max = OGR_RangeFldDomain_GetMax( domain, &maxIsInclusive ) )
2220 res = std::make_unique< QgsRangeFieldDomain >( name, description, fieldType,
2221 minValue, minIsInclusive,
2222 maxValue, maxIsInclusive );
2227 res = std::make_unique< QgsGlobFieldDomain >( name, description, fieldType,
2228 QString( OGR_GlobFldDomain_GetGlob( domain ) ) );
2232 switch ( OGR_FldDomain_GetMergePolicy( domain ) )
2234 case OFDMP_DEFAULT_VALUE:
2240 case OFDMP_GEOMETRY_WEIGHTED:
2245 switch ( OGR_FldDomain_GetSplitPolicy( domain ) )
2247 case OFDSP_DEFAULT_VALUE:
2250 case OFDSP_DUPLICATE:
2253 case OFDSP_GEOMETRY_RATIO: