Skip to content

Commit

Permalink
Implement a QgsProviderRegistry decodeUri function + test
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Aug 16, 2018
1 parent 4ab4b42 commit f4a0e74
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 7 deletions.
22 changes: 19 additions & 3 deletions python/core/auto_generated/qgsproviderregistry.sip.in
Expand Up @@ -78,7 +78,7 @@ Sets library directory where to search for plugins
%Docstring
Creates a new instance of a provider.

:param providerKey: identificator of the provider
:param providerKey: identifier of the provider
:param dataSource: string containing data source for the provider
:param options: provider options

Expand All @@ -89,9 +89,25 @@ Creates a new instance of a provider.
%Docstring
Returns the provider capabilities

:param providerKey: identificator of the provider
:param providerKey: identifier of the provider

.. versionadded:: 2.6
%End

QVariantMap decodeUri( const QString &providerKey, const QString &uri );
%Docstring
Returns the components (e.g. file path, layer name) of a provider uri

:param providerKey: identifier of the provider
:param uri: uri string

:return: map containing components

.. note::

this function may not be supported by all providers, an empty map will be returned in such case

.. versionadded:: 3.4
%End

QWidget *createSelectionWidget( const QString &providerKey,
Expand All @@ -109,7 +125,7 @@ responsible for deleting the returned widget.
%Docstring
Gets pointer to provider function

:param providerKey: identificator of the provider
:param providerKey: identifier of the provider
:param functionName: name of function

:return: pointer to function or NULL on error. If the provider uses direct provider
Expand Down
18 changes: 18 additions & 0 deletions src/core/qgsproviderregistry.cpp
Expand Up @@ -43,6 +43,8 @@ typedef QString databaseDrivers_t();
typedef QString directoryDrivers_t();
typedef QString protocolDrivers_t();
typedef void initProviderFunction_t();
typedef QVariantMap decodeUri_t( const QString &uri );

//typedef int dataCapabilities_t();
//typedef QgsDataItem * dataItem_t(QString);

Expand Down Expand Up @@ -438,6 +440,22 @@ QgsDataProvider *QgsProviderRegistry::createProvider( QString const &providerKey
return dataProvider;
} // QgsProviderRegistry::setDataProvider

QVariantMap QgsProviderRegistry::decodeUri( const QString &providerKey, const QString &uri )
{
std::unique_ptr< QLibrary > library( createProviderLibrary( providerKey ) );
if ( !library )
{
return QVariantMap();
}

decodeUri_t *decodeUri = reinterpret_cast< decodeUri_t *>( cast_to_fptr( library->resolve( "decodeUri" ) ) );
if ( !decodeUri )
{
return QVariantMap();
}
return decodeUri( uri );
}

int QgsProviderRegistry::providerCapabilities( const QString &providerKey ) const
{
std::unique_ptr< QLibrary > library( createProviderLibrary( providerKey ) );
Expand Down
16 changes: 13 additions & 3 deletions src/core/qgsproviderregistry.h
Expand Up @@ -91,7 +91,7 @@ class CORE_EXPORT QgsProviderRegistry

/**
* Creates a new instance of a provider.
* \param providerKey identificator of the provider
* \param providerKey identifier of the provider
* \param dataSource string containing data source for the provider
* \param options provider options
* \returns new instance of provider or NULL on error
Expand All @@ -102,11 +102,21 @@ class CORE_EXPORT QgsProviderRegistry

/**
* Returns the provider capabilities
\param providerKey identificator of the provider
\param providerKey identifier of the provider
\since QGIS 2.6
*/
int providerCapabilities( const QString &providerKey ) const;

/**
* Returns the components (e.g. file path, layer name) of a provider uri
\param providerKey identifier of the provider
\param uri uri string
\returns map containing components
\note this function may not be supported by all providers, an empty map will be returned in such case
\since QGIS 3.4
*/
QVariantMap decodeUri( const QString &providerKey, const QString &uri );

/**
* Returns a new widget for selecting layers from a provider.
* Either the \a parent widget must be set or the caller becomes
Expand All @@ -119,7 +129,7 @@ class CORE_EXPORT QgsProviderRegistry

/**
* Gets pointer to provider function
* \param providerKey identificator of the provider
* \param providerKey identifier of the provider
* \param functionName name of function
* \returns pointer to function or NULL on error. If the provider uses direct provider
* function pointers instead of a library nullptr will be returned.
Expand Down
24 changes: 24 additions & 0 deletions src/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -1974,6 +1974,30 @@ QStringList QgsGdalProvider::subLayers() const
return mSubLayers;
}


QGISEXTERN QVariantMap decodeUri( const QString &uri )
{
QString path = uri;
QString layerName;

QString vsiPrefix = qgsVsiPrefix( path );
if ( !path.isEmpty() )
path = path.mid( vsiPrefix.count() );

if ( path.indexOf( ':' ) != -1 )
{
QStringList parts = path.split( ':' );
path = parts[1];
if ( parts.count() > 2 )
layerName = parts[2];
}

QVariantMap uriComponents;
uriComponents.insert( QStringLiteral( "path" ), path );
uriComponents.insert( QStringLiteral( "layerName" ), layerName );
return uriComponents;
}

/**
* Class factory to return a pointer to a newly created
* QgsGdalProvider object
Expand Down
33 changes: 33 additions & 0 deletions src/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -3021,6 +3021,39 @@ QString createFilters( const QString &type )
}
}

QGISEXTERN QVariantMap decodeUri( const QString &uri )
{
QString path = uri;
QString layerName;
int layerId = -1;

int pipeIndex = path.indexOf( '|' );
if ( pipeIndex != -1 )
{
if ( path.indexOf( QLatin1String( "|layername=" ) ) != -1 )
{
QRegularExpression regex( QStringLiteral( "\\|layername=([^|]*)" ) );
layerName = regex.match( path ).captured( 1 );
}
else if ( path.indexOf( QLatin1String( "|layerid=" ) ) )
{
QRegularExpression regex( QStringLiteral( "\\|layerid=([^|]*)" ) );
layerId = regex.match( path ).captured( 1 ).toInt();
}

path = path.left( pipeIndex );
}

QString vsiPrefix = qgsVsiPrefix( path );
if ( !vsiPrefix.isEmpty() )
path = path.mid( vsiPrefix.count() );

QVariantMap uriComponents;
uriComponents.insert( QStringLiteral( "path" ), path );
uriComponents.insert( QStringLiteral( "layerName" ), layerName );
uriComponents.insert( QStringLiteral( "layerId" ), layerId > -1 ? layerId : QVariant() ) ;
return uriComponents;
}

QGISEXTERN QString fileVectorFilters()
{
Expand Down
1 change: 0 additions & 1 deletion src/providers/ogr/qgsogrprovider.h
Expand Up @@ -96,7 +96,6 @@ class QgsOgrProvider : public QgsVectorDataProvider
*/
QString dataSourceUri( bool expandAuthConfig = false ) const override;


QgsAbstractFeatureSource *featureSource() const override;

QgsCoordinateReferenceSystem crs() const override;
Expand Down
15 changes: 15 additions & 0 deletions tests/src/providers/testqgsgdalprovider.cpp
Expand Up @@ -44,6 +44,7 @@ class TestQgsGdalProvider : public QObject
void init() {}// will be called before each testfunction is executed.
void cleanup() {}// will be called after every testfunction.

void decodeUri(); // test decode URI implementation
void scaleDataType(); //test resultant data types for int raster with float scale (#11573)
void warpedVrt(); //test loading raster which requires a warped vrt
void noData();
Expand Down Expand Up @@ -82,6 +83,20 @@ void TestQgsGdalProvider::cleanupTestCase()
}
}

void TestQgsGdalProvider::decodeUri()
{
QString uri = QStringLiteral( "/home/to/path/raster.tif" );
QVariantMap components;

components = QgsProviderRegistry::instance()->decodeUri( QStringLiteral( "gdal" ), uri );
QCOMPARE( components[QStringLiteral( "path" )].toString(), uri );

uri = QStringLiteral( "gpkg:/home/to/path/my_file.gpkg:layer_name" );
components = QgsProviderRegistry::instance()->decodeUri( QStringLiteral( "gdal" ), uri );
QCOMPARE( components[QStringLiteral( "path" )].toString(), QStringLiteral( "/home/to/path/my_file.gpkg" ) );
QCOMPARE( components[QStringLiteral( "layerName" )].toString(), QStringLiteral( "layer_name" ) );
}

void TestQgsGdalProvider::scaleDataType()
{
QString rasterWithOffset = QStringLiteral( TEST_DATA_DIR ) + "/int_raster_with_scale.tif";
Expand Down
20 changes: 20 additions & 0 deletions tests/src/python/test_provider_ogr_gpkg.py
Expand Up @@ -28,6 +28,7 @@
QgsField,
QgsFieldConstraints,
QgsGeometry,
QgsProviderRegistry,
QgsRectangle,
QgsSettings,
QgsVectorLayer,
Expand Down Expand Up @@ -95,6 +96,25 @@ def tearDownClass(cls):

QgsSettings().clear()

def testDecodeUri(self):

filename = '/home/to/path/my_file.gpkg'

registry = QgsProviderRegistry.instance()
uri = filename
components = registry.decodeUri('ogr', uri)
self.assertEqual(components["path"], filename)

uri = '{}|layername=test'.format(filename)
components = registry.decodeUri('ogr', uri)
self.assertEqual(components["path"], filename)
self.assertEqual(components["layerName"], 'test')

uri = '{}|layerid=0'.format(filename)
components = registry.decodeUri('ogr', uri)
self.assertEqual(components["path"], filename)
self.assertEqual(components["layerId"], 0)

def testSingleToMultiPolygonPromotion(self):

tmpfile = os.path.join(self.basetestpath, 'testSingleToMultiPolygonPromotion.gpkg')
Expand Down

0 comments on commit f4a0e74

Please sign in to comment.