Skip to content

Commit

Permalink
Only try to query sublayers for providers which support them
Browse files Browse the repository at this point in the history
Fixes loading other layer types from browser
  • Loading branch information
nyalldawson committed Jul 15, 2021
1 parent d9b6eda commit bb35470
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 38 deletions.
Expand Up @@ -138,6 +138,7 @@ library object.
{
PriorityForUri,
LayerTypesForUri,
QuerySublayers,
};
typedef QFlags<QgsProviderMetadata::ProviderMetadataCapability> ProviderMetadataCapabilities;

Expand Down
104 changes: 66 additions & 38 deletions src/app/qgisapp.cpp
Expand Up @@ -101,6 +101,7 @@
#include "qgsprovidersublayerdetails.h"
#include "qgsproviderutils.h"
#include "qgsprovidersublayersdialog.h"
#include "qgsmaplayerfactory.h"

#include "qgsanalysis.h"
#include "qgsgeometrycheckregistry.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
Expand All @@ -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 );
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/core/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/core/providers/gdal/qgsgdalprovider.h
Expand Up @@ -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;
};
Expand Down
5 changes: 5 additions & 0 deletions src/core/providers/ogr/qgsogrprovidermetadata.cpp
Expand Up @@ -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 );
Expand Down
1 change: 1 addition & 0 deletions src/core/providers/ogr/qgsogrprovidermetadata.h
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/core/providers/qgsprovidermetadata.h
Expand Up @@ -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 )

Expand Down
5 changes: 5 additions & 0 deletions src/providers/mdal/qgsmdalprovider.cpp
Expand Up @@ -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() )
Expand Down
1 change: 1 addition & 0 deletions src/providers/mdal/qgsmdalprovider.h
Expand Up @@ -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;
};

Expand Down

0 comments on commit bb35470

Please sign in to comment.