Skip to content
Permalink
Browse files

Refine QgsProviderRegistry::preferredProvidersForUri API so that

it returns a list of preferred providers along with the valid
layer types which those providers report for the URI

This ultimately gives us a framework we can use to pick the best
guess for how to open any particular URI, given no advance knowledge
of the provider or corresponding layer type.
  • Loading branch information
nyalldawson committed Nov 6, 2020
1 parent 51762dd commit bf32b713e12d4399cddfdd592e3b30b441483efc
@@ -763,31 +763,44 @@ QgsProviderMetadata *QgsProviderRegistry::providerMetadata( const QString &provi
return findMetadata_( mProviders, providerKey );
}

QList< QgsProviderMetadata * > QgsProviderRegistry::preferredProvidersForUri( const QString &uri ) const
QList<QgsProviderRegistry::ProviderCandidateDetails> QgsProviderRegistry::preferredProvidersForUri( const QString &uri ) const
{
QList< QgsProviderMetadata * > res;
QList< QgsProviderRegistry::ProviderCandidateDetails > res;
int maxPriority = 0;
for ( auto it = mProviders.begin(); it != mProviders.end(); ++it )
{
if ( !( it->second->capabilities() & QgsProviderMetadata::PriorityForUri ) )
continue;

const int thisProviderPriority = it->second->priorityForUri( uri );
if ( thisProviderPriority == 0 )
continue;

if ( thisProviderPriority > maxPriority )
{
res.clear();
maxPriority = thisProviderPriority;
}
if ( thisProviderPriority == maxPriority )
res.append( it->second );
{
res.append( ProviderCandidateDetails( it->second, it->second->validLayerTypesForUri( uri ) ) );
}
}
return res;
}

bool QgsProviderRegistry::shouldDeferUriForOtherProviders( const QString &uri, const QString &providerKey ) const
{
const QList< QgsProviderMetadata * > providers = preferredProvidersForUri( uri );
const QList< ProviderCandidateDetails > providers = preferredProvidersForUri( uri );
if ( providers.empty() )
return false;

return !providers.contains( QgsProviderRegistry::instance()->providerMetadata( providerKey ) );
for ( const ProviderCandidateDetails &provider : providers )
{
if ( provider.metadata()->key() == providerKey )
return false;
}
return true;
}

bool QgsProviderRegistry::uriIsBlocklisted( const QString &uri ) const
@@ -283,7 +283,45 @@ class CORE_EXPORT QgsProviderRegistry
QgsProviderMetadata *providerMetadata( const QString &providerKey ) const;

/**
* Returns the metadata for the preferred provider(s) for opening the specified \a uri.
* \ingroup core
*
* Contains information pertaining to a candidate provider.
*
* \since QGIS 3.18
*/
class CORE_EXPORT ProviderCandidateDetails
{

public:

/**
* Constructor for ProviderCandidateDetails, with the specified provider \a metadata and valid candidate \a layerTypes.
*/
ProviderCandidateDetails( QgsProviderMetadata *metadata, const QList< QgsMapLayerType > &layerTypes )
: mMetadata( metadata )
, mLayerTypes( layerTypes )
{}

/**
* Returns the candidate provider metadata.
*/
QgsProviderMetadata *metadata() const { return mMetadata; }

/**
* Returns a list of map layer types which are valid options for opening the
* target using this candidate provider.
*/
QList<QgsMapLayerType> layerTypes() const { return mLayerTypes; }

private:
QgsProviderMetadata *mMetadata = nullptr;

QList< QgsMapLayerType > mLayerTypes;

};

/**
* Returns the details for the preferred provider(s) for opening the specified \a uri.
*
* The preferred provider is determined by comparing the priority returned by
* QgsProviderMetadata::priorityForUri() for all registered providers, and selecting
@@ -298,7 +336,7 @@ class CORE_EXPORT QgsProviderRegistry
* \see shouldDeferUriForOtherProviders()
* \since QGIS 3.18
*/
QList< QgsProviderMetadata *> preferredProvidersForUri( const QString &uri ) const;
QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProvidersForUri( const QString &uri ) const;

/**
* Returns TRUE if the provider with matching \a providerKey should defer handling of
@@ -51,11 +51,11 @@ void QgsPointCloudSourceSelect::addButtonClicked()
{
// auto determine preferred provider for each path

const QList< QgsProviderMetadata * > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( mPath );
const QList< QgsProviderRegistry::ProviderCandidateDetails > preferredProviders = QgsProviderRegistry::instance()->preferredProvidersForUri( mPath );
// maybe we should raise an assert if preferredProviders size is 0 or >1? Play it safe for now...
if ( preferredProviders.empty() )
continue;

emit addPointCloudLayer( path, QFileInfo( path ).baseName(), preferredProviders.at( 0 )->key() ) ;
emit addPointCloudLayer( path, QFileInfo( path ).baseName(), preferredProviders.at( 0 ).metadata()->key() ) ;
}
}
@@ -47,6 +47,7 @@ class TestQgsEptProvider : public QObject
void encodeUri();
void decodeUri();
void preferredUri();
void layerTypesForUri();
void uriIsBlocklisted();

private:
@@ -112,14 +113,33 @@ void TestQgsEptProvider::decodeUri()

void TestQgsEptProvider::preferredUri()
{
QgsProviderMetadata *eptMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ept" ) );
QVERIFY( eptMetadata->capabilities() & QgsProviderMetadata::PriorityForUri );

// test that EPT is the preferred provider for ept.json uris
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/ept.json" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ept" ) ) );
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/EPT.JSON" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ept" ) ) );
QList<QgsProviderRegistry::ProviderCandidateDetails> candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/ept.json" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "ept" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/EPT.JSON" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "ept" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

QVERIFY( !QgsProviderRegistry::instance()->shouldDeferUriForOtherProviders( QStringLiteral( "/home/test/ept.json" ), QStringLiteral( "ept" ) ) );
QVERIFY( QgsProviderRegistry::instance()->shouldDeferUriForOtherProviders( QStringLiteral( "/home/test/ept.json" ), QStringLiteral( "ogr" ) ) );
}

void TestQgsEptProvider::layerTypesForUri()
{
QgsProviderMetadata *eptMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ept" ) );
QVERIFY( eptMetadata->capabilities() & QgsProviderMetadata::LayerTypesForUri );

QCOMPARE( eptMetadata->validLayerTypesForUri( QStringLiteral( "/home/test/ept.json" ) ), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );
QCOMPARE( eptMetadata->validLayerTypesForUri( QStringLiteral( "/home/test/cloud.las" ) ), QList< QgsMapLayerType >() );
}

void TestQgsEptProvider::uriIsBlocklisted()
{
QVERIFY( !QgsProviderRegistry::instance()->uriIsBlocklisted( QStringLiteral( "/home/nyall/ept.json" ) ) );
@@ -28,6 +28,7 @@
#include "qgsapplication.h"
#include "qgsproviderregistry.h"
#include "qgseptprovider.h"
#include "qgsmaplayer.h"

/**
* \ingroup UnitTests
@@ -46,6 +47,7 @@ class TestQgsPdalProvider : public QObject
void filters();
void encodeUri();
void decodeUri();
void layerTypesForUri();
void preferredUri();

private:
@@ -109,13 +111,40 @@ void TestQgsPdalProvider::decodeUri()
QCOMPARE( parts.value( QStringLiteral( "path" ) ).toString(), QStringLiteral( "/home/point_clouds/cloud.las" ) );
}

void TestQgsPdalProvider::layerTypesForUri()
{
QgsProviderMetadata *pdalMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) );
QVERIFY( pdalMetadata->capabilities() & QgsProviderMetadata::LayerTypesForUri );

QCOMPARE( pdalMetadata->validLayerTypesForUri( QStringLiteral( "/home/test/cloud.las" ) ), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );
QCOMPARE( pdalMetadata->validLayerTypesForUri( QStringLiteral( "/home/test/cloud.shp" ) ), QList< QgsMapLayerType >() );
}

void TestQgsPdalProvider::preferredUri()
{
QgsProviderMetadata *pdalMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) );
QVERIFY( pdalMetadata->capabilities() & QgsProviderMetadata::PriorityForUri );

// test that EPT is the preferred provider for las/laz uris
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/cloud.las" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) ) );
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/CLOUD.LAS" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) ) );
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/cloud.laz" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) ) );
QCOMPARE( QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/CLOUD.LAZ" ) ), QList< QgsProviderMetadata * >() << QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "pdal" ) ) );
QList<QgsProviderRegistry::ProviderCandidateDetails> candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/cloud.las" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "pdal" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/CLOUD.LAS" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "pdal" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/cloud.laz" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "pdal" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

candidates = QgsProviderRegistry::instance()->preferredProvidersForUri( QStringLiteral( "/home/test/CLOUD.LAZ" ) );
QCOMPARE( candidates.size(), 1 );
QCOMPARE( candidates.at( 0 ).metadata()->key(), QStringLiteral( "pdal" ) );
QCOMPARE( candidates.at( 0 ).layerTypes(), QList< QgsMapLayerType >() << QgsMapLayerType::PointCloudLayer );

QVERIFY( !QgsProviderRegistry::instance()->shouldDeferUriForOtherProviders( QStringLiteral( "/home/test/cloud.las" ), QStringLiteral( "pdal" ) ) );
QVERIFY( QgsProviderRegistry::instance()->shouldDeferUriForOtherProviders( QStringLiteral( "/home/test/cloud.las" ), QStringLiteral( "ept" ) ) );

0 comments on commit bf32b71

Please sign in to comment.
You can’t perform that action at this time.