Skip to content
Permalink
Browse files
Only try to query sublayers for providers which support them
Fixes loading other layer types from browser
  • Loading branch information
nyalldawson committed Jul 15, 2021
1 parent d9b6eda commit bb354708da53ccb27ca264a67c0b631e9b9d7961
@@ -138,6 +138,7 @@ library object.
{
PriorityForUri,
LayerTypesForUri,
QuerySublayers,
};
typedef QFlags<QgsProviderMetadata::ProviderMetadataCapability> ProviderMetadataCapabilities;

@@ -101,6 +101,7 @@
#include "qgsprovidersublayerdetails.h"
#include "qgsproviderutils.h"
#include "qgsprovidersublayersdialog.h"
#include "qgsmaplayerfactory.h"

#include "qgsanalysis.h"
#include "qgsgeometrycheckregistry.h"
@@ -5438,6 +5439,8 @@ bool QgisApp::addVectorLayers( const QStringList &layerQStringList, const QStrin

bool QgisApp::addVectorLayersPrivate( const QStringList &layers, const QString &enc, const QString &dataSourceType, const bool guiWarning )
{
//note: this method ONLY supports vector layers from the OGR provider!

QgsCanvasRefreshBlocker refreshBlocker;

QList<QgsMapLayer *> layersToAdd;
@@ -13119,60 +13122,81 @@ T *QgisApp::addLayerPrivate( QgsMapLayerType type, const QString &uri, const QSt
// Not all providers implement decodeUri(), so use original uri if uriElements is empty
const QString updatedUri = uriElements.isEmpty() ? uri : QgsProviderRegistry::instance()->encodeUri( providerKey, uriElements );

// query sublayers
QList< QgsProviderSublayerDetails > sublayers = QgsProviderRegistry::instance()->providerMetadata( providerKey ) ?
QgsProviderRegistry::instance()->providerMetadata( providerKey )->querySublayers( updatedUri )
: QgsProviderRegistry::instance()->querySublayers( updatedUri );

// filter out non-matching sublayers
sublayers.erase( std::remove_if( sublayers.begin(), sublayers.end(), [type]( const QgsProviderSublayerDetails & sublayer )
{
return sublayer.type() != type;
} ), sublayers.end() );
const bool canQuerySublayers = QgsProviderRegistry::instance()->providerMetadata( providerKey ) &&
( QgsProviderRegistry::instance()->providerMetadata( providerKey )->capabilities() & QgsProviderMetadata::QuerySublayers );

T *result = nullptr;
if ( sublayers.empty() )
if ( canQuerySublayers )
{
if ( guiWarnings )
// query sublayers
QList< QgsProviderSublayerDetails > sublayers = QgsProviderRegistry::instance()->providerMetadata( providerKey ) ?
QgsProviderRegistry::instance()->providerMetadata( providerKey )->querySublayers( updatedUri )
: QgsProviderRegistry::instance()->querySublayers( updatedUri );

// filter out non-matching sublayers
sublayers.erase( std::remove_if( sublayers.begin(), sublayers.end(), [type]( const QgsProviderSublayerDetails & sublayer )
{
QString msg = tr( "%1 is not a valid or recognized data source." ).arg( uri );
visibleMessageBar()->pushMessage( tr( "Invalid Data Source" ), msg, Qgis::MessageLevel::Critical );
}
return sublayer.type() != type;
} ), sublayers.end() );

// since the layer is bad, stomp on it
return nullptr;
}
else if ( sublayers.size() > 1 )
{
// ask user for sublayers (unless user settings dictate otherwise!)
switch ( shouldAskUserForSublayers( sublayers ) )
if ( sublayers.empty() )
{
case SublayerHandling::AskUser:
if ( guiWarnings )
{
QgsProviderSublayersDialog dlg( updatedUri, path, sublayers, {type}, this );
if ( dlg.exec() )
QString msg = tr( "%1 is not a valid or recognized data source." ).arg( uri );
visibleMessageBar()->pushMessage( tr( "Invalid Data Source" ), msg, Qgis::MessageLevel::Critical );
}

// since the layer is bad, stomp on it
return nullptr;
}
else if ( sublayers.size() > 1 )
{
// ask user for sublayers (unless user settings dictate otherwise!)
switch ( shouldAskUserForSublayers( sublayers ) )
{
case SublayerHandling::AskUser:
{
const QList< QgsProviderSublayerDetails > selectedLayers = dlg.selectedLayers();
if ( !selectedLayers.isEmpty() )
QgsProviderSublayersDialog dlg( updatedUri, path, sublayers, {type}, this );
if ( dlg.exec() )
{
result = qobject_cast< T * >( addSublayers( selectedLayers, baseName, dlg.groupName() ).value( 0 ) );
const QList< QgsProviderSublayerDetails > selectedLayers = dlg.selectedLayers();
if ( !selectedLayers.isEmpty() )
{
result = qobject_cast< T * >( addSublayers( selectedLayers, baseName, dlg.groupName() ).value( 0 ) );
}
}
break;
}
break;
}
case SublayerHandling::LoadAll:
case SublayerHandling::LoadAll:
{
result = qobject_cast< T * >( addSublayers( sublayers, baseName, QString() ).value( 0 ) );
break;
}
case SublayerHandling::AbortLoading:
break;
};
}
else
{
result = qobject_cast< T * >( addSublayers( sublayers, name, QString() ).value( 0 ) );

if ( result )
{
result = qobject_cast< T * >( addSublayers( sublayers, baseName, QString() ).value( 0 ) );
break;
QString base( baseName );
if ( settings.value( QStringLiteral( "qgis/formatLayerName" ), false ).toBool() )
{
base = QgsMapLayer::formatLayerName( base );
}
result->setName( base );
}
case SublayerHandling::AbortLoading:
break;
};
}
}
else
{
result = qobject_cast< T * >( addSublayers( sublayers, name, QString() ).value( 0 ) );

QgsMapLayerFactory::LayerOptions options( QgsProject::instance()->transformContext() );
options.loadDefaultStyle = false;
result = qobject_cast< T * >( QgsMapLayerFactory::createLayer( uri, name, type, options, providerKey ) );
if ( result )
{
QString base( baseName );
@@ -13181,6 +13205,10 @@ T *QgisApp::addLayerPrivate( QgsMapLayerType type, const QString &uri, const QSt
base = QgsMapLayer::formatLayerName( base );
}
result->setName( base );
QgsProject::instance()->addMapLayer( result );

askUserForDatumTransform( result->crs(), QgsProject::instance()->crs(), result );
postProcessAddedLayer( result );
}
}

@@ -3528,6 +3528,11 @@ QList<QPair<QString, QString> > QgsGdalProviderMetadata::pyramidResamplingMethod
return methods;
}

QgsProviderMetadata::ProviderMetadataCapabilities QgsGdalProviderMetadata::capabilities() const
{
return QuerySublayers;
}

QgsProviderMetadata::ProviderCapabilities QgsGdalProviderMetadata::providerCapabilities() const
{
return FileBasedUris;
@@ -383,6 +383,7 @@ class QgsGdalProviderMetadata final: public QgsProviderMetadata
QString filters( FilterType type ) override;
QList< QgsDataItemProvider * > dataItemProviders() const override;
QList<QPair<QString, QString> > pyramidResamplingMethods() override;
QgsProviderMetadata::ProviderMetadataCapabilities capabilities() const override;
ProviderCapabilities providerCapabilities() const override;
QList< QgsProviderSublayerDetails > querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags = Qgis::SublayerQueryFlags(), QgsFeedback *feedback = nullptr ) const override;
};
@@ -1012,6 +1012,11 @@ QString QgsOgrProviderMetadata::filters( FilterType type )
return QString();
}

QgsProviderMetadata::ProviderMetadataCapabilities QgsOgrProviderMetadata::capabilities() const
{
return QuerySublayers;
}

bool QgsOgrProviderMetadata::uriIsBlocklisted( const QString &uri ) const
{
const QVariantMap parts = decodeUri( uri );
@@ -39,6 +39,7 @@ class QgsOgrProviderMetadata final: public QgsProviderMetadata
QVariantMap decodeUri( const QString &uri ) const override;
QString encodeUri( const QVariantMap &parts ) const override;
QString filters( FilterType type ) override;
QgsProviderMetadata::ProviderMetadataCapabilities capabilities() const override;
ProviderCapabilities providerCapabilities() const override;
bool uriIsBlocklisted( const QString &uri ) const override;
QList< QgsProviderSublayerDetails > querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags = Qgis::SublayerQueryFlags(), QgsFeedback *feedback = nullptr ) const override;
@@ -179,6 +179,7 @@ class CORE_EXPORT QgsProviderMetadata : public QObject
{
PriorityForUri = 1 << 0, //!< Indicates that the metadata can calculate a priority for a URI
LayerTypesForUri = 1 << 1, //!< Indicates that the metadata can determine valid layer types for a URI
QuerySublayers = 1 << 2, //!< Indicates that the metadata can query sublayers for a URI (since QGIS 3.22)
};
Q_DECLARE_FLAGS( ProviderMetadataCapabilities, ProviderMetadataCapability )

@@ -1055,6 +1055,11 @@ QgsProviderMetadata::ProviderCapabilities QgsMdalProviderMetadata::providerCapab
return FileBasedUris;
}

QgsProviderMetadata::ProviderMetadataCapabilities QgsMdalProviderMetadata::capabilities() const
{
return QuerySublayers;
}

QList<QgsProviderSublayerDetails> QgsMdalProviderMetadata::querySublayers( const QString &uri, Qgis::SublayerQueryFlags, QgsFeedback * ) const
{
if ( uri.isEmpty() )
@@ -154,6 +154,7 @@ class QgsMdalProviderMetadata: public QgsProviderMetadata
QVariantMap decodeUri( const QString &uri ) const override;
QString encodeUri( const QVariantMap &parts ) const override;
ProviderCapabilities providerCapabilities() const override;
QgsProviderMetadata::ProviderMetadataCapabilities capabilities() const override;
QList< QgsProviderSublayerDetails > querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags = Qgis::SublayerQueryFlags(), QgsFeedback *feedback = nullptr ) const override;
};

0 comments on commit bb35470

Please sign in to comment.