From 8866b0cdad5b2bff3ee714bdb2bc5d306eb12cce Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 11 Dec 2022 13:40:55 +0100 Subject: [PATCH] QgsProviderSublayerTask: make it possible to restrict it to a particular provider Avoids the 'ERROR: Status 2: File pagingEnabled='false' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:25832' typename='dvg:nw_dvg1_bld' url='https://www.wfs.nrw.de/geobasis/wfs_nw_dvg' version='auto' could not be found' type of message in the scenario described by https://github.com/qgis/QGIS/pull/51144#issuecomment-1345507627 --- .../providers/qgsprovidermetadata.sip.in | 2 +- .../providers/qgsprovidersublayertask.sip.in | 8 ++++++++ src/app/layers/qgsapplayerhandling.cpp | 8 ++++---- src/core/providers/qgsprovidermetadata.h | 2 +- .../providers/qgsprovidersublayertask.cpp | 19 ++++++++++++++++++- src/core/providers/qgsprovidersublayertask.h | 10 ++++++++++ src/gui/qgsprovidersublayersdialog.cpp | 4 ++-- src/gui/qgsprovidersublayersdialog.h | 1 + 8 files changed, 45 insertions(+), 9 deletions(-) diff --git a/python/core/auto_generated/providers/qgsprovidermetadata.sip.in b/python/core/auto_generated/providers/qgsprovidermetadata.sip.in index fc8d226e927..4bb06f75127 100644 --- a/python/core/auto_generated/providers/qgsprovidermetadata.sip.in +++ b/python/core/auto_generated/providers/qgsprovidermetadata.sip.in @@ -398,7 +398,7 @@ The optional ``feedback`` argument can be used to provide cancellation support f virtual QString suggestGroupNameForUri( const QString &uri ) const; %Docstring -Returns a name that can be used as a group name for sublayers got from +Returns a name that can be used as a group name for sublayers retrieved from the specified ``uri``. The default implementation returns an empty string. diff --git a/python/core/auto_generated/providers/qgsprovidersublayertask.sip.in b/python/core/auto_generated/providers/qgsprovidersublayertask.sip.in index 18e00f0dd0e..6a7482a09e5 100644 --- a/python/core/auto_generated/providers/qgsprovidersublayertask.sip.in +++ b/python/core/auto_generated/providers/qgsprovidersublayertask.sip.in @@ -39,6 +39,14 @@ possible, regardless of how expensive this may be. %Docstring Constructor for QgsProviderSublayerTask, which retrieves sublayer details for the specified ``uri``. +%End + + QgsProviderSublayerTask( const QString &uri, const QString &providerKey, bool includeSystemTables = false ); +%Docstring +Constructor for QgsProviderSublayerTask, which retrieves sublayer details for the +specified ``uri``, restricted to a particular provider. + +.. versionadded:: 3.30 %End ~QgsProviderSublayerTask(); diff --git a/src/app/layers/qgsapplayerhandling.cpp b/src/app/layers/qgsapplayerhandling.cpp index b0d1f640327..53c86860bef 100644 --- a/src/app/layers/qgsapplayerhandling.cpp +++ b/src/app/layers/qgsapplayerhandling.cpp @@ -324,7 +324,7 @@ QList< QgsMapLayer * > QgsAppLayerHandling::addOgrVectorLayers( const QStringLis case SublayerHandling::AskUser: { // prompt user for sublayers - QgsProviderSublayersDialog dlg( uri, path, sublayers, {QgsMapLayerType::VectorLayer}, QgisApp::instance() ); + QgsProviderSublayersDialog dlg( uri, QString(), path, sublayers, {QgsMapLayerType::VectorLayer}, QgisApp::instance() ); if ( dlg.exec() ) sublayers = dlg.selectedLayers(); @@ -534,7 +534,7 @@ bool QgsAppLayerHandling::askUserForZipItemLayers( const QString &path, const QL case SublayerHandling::AskUser: { // prompt user for sublayers - QgsProviderSublayersDialog dlg( path, path, sublayers, acceptableTypes, QgisApp::instance() ); + QgsProviderSublayersDialog dlg( path, QString(), path, sublayers, acceptableTypes, QgisApp::instance() ); if ( dlg.exec() ) sublayers = dlg.selectedLayers(); @@ -936,7 +936,7 @@ QList< QgsMapLayer * > QgsAppLayerHandling::openLayer( const QString &fileName, case SublayerHandling::AskUser: { // prompt user for sublayers - QgsProviderSublayersDialog dlg( fileName, fileName, sublayers, {}, QgisApp::instance() ); + QgsProviderSublayersDialog dlg( fileName, QString(), fileName, sublayers, {}, QgisApp::instance() ); dlg.setNonLayerItems( nonLayerItems ); if ( dlg.exec() ) @@ -1373,7 +1373,7 @@ T *QgsAppLayerHandling::addLayerPrivate( QgsMapLayerType type, const QString &ur { case SublayerHandling::AskUser: { - QgsProviderSublayersDialog dlg( updatedUri, path, sublayers, {type}, QgisApp::instance() ); + QgsProviderSublayersDialog dlg( updatedUri, providerKey, path, sublayers, {type}, QgisApp::instance() ); QString groupName = providerMetadata->suggestGroupNameForUri( uri ); if ( !groupName.isEmpty() ) dlg.setGroupName( groupName ); diff --git a/src/core/providers/qgsprovidermetadata.h b/src/core/providers/qgsprovidermetadata.h index 1d5287d0d11..62d66376d92 100644 --- a/src/core/providers/qgsprovidermetadata.h +++ b/src/core/providers/qgsprovidermetadata.h @@ -458,7 +458,7 @@ class CORE_EXPORT QgsProviderMetadata : public QObject virtual QList< QgsProviderSublayerDetails > querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags = Qgis::SublayerQueryFlags(), QgsFeedback *feedback = nullptr ) const; /** - * Returns a name that can be used as a group name for sublayers got from + * Returns a name that can be used as a group name for sublayers retrieved from * the specified \a uri. * * The default implementation returns an empty string. diff --git a/src/core/providers/qgsprovidersublayertask.cpp b/src/core/providers/qgsprovidersublayertask.cpp index cc7064a99ad..af84500892b 100644 --- a/src/core/providers/qgsprovidersublayertask.cpp +++ b/src/core/providers/qgsprovidersublayertask.cpp @@ -17,6 +17,7 @@ #include "qgsprovidersublayertask.h" #include "qgsfeedback.h" +#include "qgsprovidermetadata.h" #include "qgsproviderregistry.h" #include "qgsprovidersublayerdetails.h" #include "qgsreadwritelocker.h" @@ -28,6 +29,14 @@ QgsProviderSublayerTask::QgsProviderSublayerTask( const QString &uri, bool inclu { } +QgsProviderSublayerTask::QgsProviderSublayerTask( const QString &uri, const QString &providerKey, bool includeSystemTables ) + : QgsTask( tr( "Retrieving layers" ), QgsTask::CanCancel | QgsTask::CancelWithoutPrompt | QgsTask::Silent ) + , mUri( uri ) + , mProviderKey( providerKey ) + , mIncludeSystemTables( includeSystemTables ) +{ +} + QList QgsProviderSublayerTask::results() const { const QgsReadWriteLocker locker( mLock, QgsReadWriteLocker::Read ); @@ -44,7 +53,15 @@ bool QgsProviderSublayerTask::run() if ( mIncludeSystemTables ) flags |= Qgis::SublayerQueryFlag::IncludeSystemTables; - const QList res = QgsProviderRegistry::instance()->querySublayers( mUri, flags, mFeedback.get() ); + QList res; + if ( mProviderKey.isEmpty() ) + res = QgsProviderRegistry::instance()->querySublayers( mUri, flags, mFeedback.get() ); + else + { + QgsProviderMetadata *provider = QgsProviderRegistry::instance()->providerMetadata( mProviderKey ); + if ( provider ) + res = provider->querySublayers( mUri, flags, mFeedback.get() ); + } const QgsReadWriteLocker locker( mLock, QgsReadWriteLocker::Write ); mResults = res; diff --git a/src/core/providers/qgsprovidersublayertask.h b/src/core/providers/qgsprovidersublayertask.h index fe020adc1ae..d04df862c1f 100644 --- a/src/core/providers/qgsprovidersublayertask.h +++ b/src/core/providers/qgsprovidersublayertask.h @@ -55,6 +55,14 @@ class CORE_EXPORT QgsProviderSublayerTask : public QgsTask */ QgsProviderSublayerTask( const QString &uri, bool includeSystemTables = false ); + /** + * Constructor for QgsProviderSublayerTask, which retrieves sublayer details for the + * specified \a uri, restricted to a particular provider. + * + * \since QGIS 3.30 + */ + QgsProviderSublayerTask( const QString &uri, const QString &providerKey, bool includeSystemTables = false ); + ~QgsProviderSublayerTask() override; /** @@ -72,6 +80,8 @@ class CORE_EXPORT QgsProviderSublayerTask : public QgsTask QString mUri; + QString mProviderKey; + bool mIncludeSystemTables = false; std::unique_ptr< QgsFeedback > mFeedback; diff --git a/src/gui/qgsprovidersublayersdialog.cpp b/src/gui/qgsprovidersublayersdialog.cpp index dd0047abc54..c67b5ec9f47 100644 --- a/src/gui/qgsprovidersublayersdialog.cpp +++ b/src/gui/qgsprovidersublayersdialog.cpp @@ -111,7 +111,7 @@ void QgsProviderSublayerDialogModel::setGeometryTypesResolved( bool resolved ) emit dataChanged( index( 0, 0 ), index( rowCount( QModelIndex() ), columnCount() ) ); } -QgsProviderSublayersDialog::QgsProviderSublayersDialog( const QString &uri, const QString &filePathIn, const QList initialDetails, const QList &acceptableTypes, QWidget *parent, Qt::WindowFlags fl ) +QgsProviderSublayersDialog::QgsProviderSublayersDialog( const QString &uri, const QString &providerKey, const QString &filePathIn, const QList initialDetails, const QList &acceptableTypes, QWidget *parent, Qt::WindowFlags fl ) : QDialog( parent, fl ) { setupUi( this ); @@ -177,7 +177,7 @@ QgsProviderSublayersDialog::QgsProviderSublayersDialog( const QString &uri, cons if ( QgsProviderUtils::sublayerDetailsAreIncomplete( initialDetails ) ) { // initial details are incomplete, so fire up a task in the background to fully populate the model... - mTask = new QgsProviderSublayerTask( uri, true ); + mTask = new QgsProviderSublayerTask( uri, providerKey, true ); connect( mTask.data(), &QgsProviderSublayerTask::taskCompleted, this, [ = ] { QList< QgsProviderSublayerDetails > res = mTask->results(); diff --git a/src/gui/qgsprovidersublayersdialog.h b/src/gui/qgsprovidersublayersdialog.h index 185b4c51945..33572f7d055 100644 --- a/src/gui/qgsprovidersublayersdialog.h +++ b/src/gui/qgsprovidersublayersdialog.h @@ -78,6 +78,7 @@ class GUI_EXPORT QgsProviderSublayersDialog : public QDialog, private Ui::QgsPro * Constructor. */ QgsProviderSublayersDialog( const QString &uri, + const QString &providerKey, const QString &filePath, const QList< QgsProviderSublayerDetails> initialDetails = QList< QgsProviderSublayerDetails>(), const QList< QgsMapLayerType > &acceptableTypes = QList< QgsMapLayerType >(),