[OAPIF provider] Integrate provider within WFS provider GUI

Funded by Planet
This commit is contained in:
Even Rouault 2019-10-13 12:52:39 +02:00 committed by Nyall Dawson
parent 4a6b49fe8f
commit 681229a48a
13 changed files with 431 additions and 83 deletions

View File

@ -78,6 +78,15 @@ Returns the current connection url.
protected:
enum WfsVersionIndex
{
WFS_VERSION_MAX,
WFS_VERSION_1_0,
WFS_VERSION_1_1,
WFS_VERSION_2_0,
WFS_VERSION_API_FEATURES,
};
virtual bool validate();
%Docstring
Returns ``True`` if dialog settings are valid, or ``False`` if current

View File

@ -73,6 +73,7 @@ QgsNewHttpConnection::QgsNewHttpConnection( QWidget *parent, ConnectionTypes typ
cmbVersion->addItem( tr( "1.0" ) );
cmbVersion->addItem( tr( "1.1" ) );
cmbVersion->addItem( tr( "2.0" ) );
cmbVersion->addItem( tr( "OGC API - Features" ) );
connect( cmbVersion,
static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
this, &QgsNewHttpConnection::wfsVersionCurrentIndexChanged );
@ -166,10 +167,11 @@ QgsNewHttpConnection::QgsNewHttpConnection( QWidget *parent, ConnectionTypes typ
void QgsNewHttpConnection::wfsVersionCurrentIndexChanged( int index )
{
// For now 2019-06-06, leave paging checkable for some WFS version 1.1 servers with support
cbxWfsFeaturePaging->setEnabled( index == 0 || index >= 2 );
lblPageSize->setEnabled( cbxWfsFeaturePaging->isChecked() && ( index == 0 || index >= 2 ) );
txtPageSize->setEnabled( cbxWfsFeaturePaging->isChecked() && ( index == 0 || index >= 2 ) );
cbxWfsIgnoreAxisOrientation->setEnabled( index != 1 );
cbxWfsFeaturePaging->setEnabled( index == WFS_VERSION_MAX || index >= WFS_VERSION_2_0 );
lblPageSize->setEnabled( cbxWfsFeaturePaging->isChecked() && ( index == WFS_VERSION_MAX || index >= WFS_VERSION_1_1 ) );
txtPageSize->setEnabled( cbxWfsFeaturePaging->isChecked() && ( index == WFS_VERSION_MAX || index >= WFS_VERSION_1_1 ) );
cbxWfsIgnoreAxisOrientation->setEnabled( index != WFS_VERSION_1_0 && index != WFS_VERSION_API_FEATURES );
cbxWfsInvertAxisOrientation->setEnabled( index != WFS_VERSION_API_FEATURES );
}
void QgsNewHttpConnection::wfsFeaturePagingStateChanged( int state )
@ -312,29 +314,27 @@ void QgsNewHttpConnection::updateServiceSpecificSettings()
cmbDpiMode->setCurrentIndex( dpiIdx );
QString version = settings.value( wfsKey + "/version" ).toString();
int versionIdx = 0; // AUTO
int versionIdx = WFS_VERSION_MAX; // AUTO
if ( version == QLatin1String( "1.0.0" ) )
versionIdx = 1;
versionIdx = WFS_VERSION_1_0;
else if ( version == QLatin1String( "1.1.0" ) )
versionIdx = 2;
versionIdx = WFS_VERSION_1_1;
else if ( version == QLatin1String( "2.0.0" ) )
versionIdx = 3;
versionIdx = WFS_VERSION_2_0;
else if ( version == QLatin1String( "OGC_API_FEATURES" ) )
versionIdx = WFS_VERSION_API_FEATURES;
cmbVersion->setCurrentIndex( versionIdx );
// Enable/disable these items per WFS versions
wfsVersionCurrentIndexChanged( versionIdx );
txtReferer->setText( settings.value( wmsKey + "/referer" ).toString() );
txtMaxNumFeatures->setText( settings.value( wfsKey + "/maxnumfeatures" ).toString() );
// Only default to paging enabled if WFS 2.0.0 or higher
bool pagingEnabled = settings.value( wfsKey + "/pagingenabled", ( versionIdx == 0 || versionIdx >= 3 ) ).toBool();
bool pagingEnabled = settings.value( wfsKey + "/pagingenabled", ( versionIdx == WFS_VERSION_MAX || versionIdx >= WFS_VERSION_2_0 ) ).toBool();
txtPageSize->setText( settings.value( wfsKey + "/pagesize" ).toString() );
cbxWfsFeaturePaging->setChecked( pagingEnabled );
// Enable/disable these items per WFS versions
// For now 2019-06-06, leave paging checkable for some WFS version 1.1 servers with support
txtPageSize->setEnabled( pagingEnabled && ( versionIdx == 0 || versionIdx >= 2 ) );
lblPageSize->setEnabled( pagingEnabled && ( versionIdx == 0 || versionIdx >= 2 ) );
cbxWfsFeaturePaging->setEnabled( versionIdx == 0 || versionIdx >= 2 );
cbxWfsIgnoreAxisOrientation->setEnabled( versionIdx != 1 );
}
QUrl QgsNewHttpConnection::urlTrimmed() const
@ -434,18 +434,21 @@ void QgsNewHttpConnection::accept()
QString version = QStringLiteral( "auto" );
switch ( cmbVersion->currentIndex() )
{
case 0:
case WFS_VERSION_MAX:
version = QStringLiteral( "auto" );
break;
case 1:
case WFS_VERSION_1_0:
version = QStringLiteral( "1.0.0" );
break;
case 2:
case WFS_VERSION_1_1:
version = QStringLiteral( "1.1.0" );
break;
case 3:
case WFS_VERSION_2_0:
version = QStringLiteral( "2.0.0" );
break;
case WFS_VERSION_API_FEATURES:
version = QStringLiteral( "OGC_API_FEATURES" );
break;
}
settings.setValue( wfsKey + "/version", version );

View File

@ -103,6 +103,16 @@ class GUI_EXPORT QgsNewHttpConnection : public QDialog, private Ui::QgsNewHttpCo
protected:
//! Index of wfsVersionComboBox
enum WfsVersionIndex
{
WFS_VERSION_MAX = 0,
WFS_VERSION_1_0 = 1,
WFS_VERSION_1_1 = 2,
WFS_VERSION_2_0 = 3,
WFS_VERSION_API_FEATURES = 4,
};
/**
* Returns TRUE if dialog settings are valid, or FALSE if current
* settings are not valid and the dialog should not be acceptable.

View File

@ -145,6 +145,11 @@ class CPLXMLTreeUniquePointer
void QgsWfsCapabilities::capabilitiesReplyFinished()
{
if ( mErrorCode != QgsBaseNetworkRequest::NoError )
{
emit gotCapabilities();
return;
}
const QByteArray &buffer = mResponse;
QgsDebugMsgLevel( QStringLiteral( "parsing capabilities: " ) + buffer, 4 );

View File

@ -19,11 +19,15 @@
#include "qgsdataitemprovider.h"
#include "qgsdataprovider.h"
#include "qgslogger.h"
#include "qgsoapiflandingpagerequest.h"
#include "qgsoapifcollection.h"
#include "qgsoapifprovider.h"
#include "qgswfsconstants.h"
#include "qgswfsconnection.h"
#include "qgswfscapabilities.h"
#include "qgswfsdataitems.h"
#include "qgswfsdatasourceuri.h"
#include "qgswfsprovider.h"
#include "qgssettings.h"
#include "qgsgeonodeconnection.h"
#include "qgsgeonoderequest.h"
@ -40,8 +44,8 @@
// QgsWfsLayerItem
//
QgsWfsLayerItem::QgsWfsLayerItem( QgsDataItem *parent, QString name, const QgsDataSourceUri &uri, QString featureType, QString title, QString crsString )
: QgsLayerItem( parent, title, parent->path() + '/' + name, QString(), QgsLayerItem::Vector, QStringLiteral( "WFS" ) )
QgsWfsLayerItem::QgsWfsLayerItem( QgsDataItem *parent, QString name, const QgsDataSourceUri &uri, QString featureType, QString title, QString crsString, const QString &providerKey )
: QgsLayerItem( parent, title.isEmpty() ? featureType : title, parent->path() + '/' + name, QString(), QgsLayerItem::Vector, providerKey )
{
QgsSettings settings;
bool useCurrentViewExtent = settings.value( QStringLiteral( "Windows/WFSSourceSelect/FeatureCurrentViewExtent" ), true ).toBool();
@ -140,34 +144,82 @@ QgsWfsConnectionItem::QgsWfsConnectionItem( QgsDataItem *parent, QString name, Q
mCapabilities |= Collapse;
}
QVector<QgsDataItem *> QgsWfsConnectionItem::createChildrenOapif()
{
QVector<QgsDataItem *> layers;
QgsDataSourceUri uri( mUri );
const bool synchronous = true;
const bool forceRefresh = false;
QgsOapifLandingPageRequest landingPageRequest( uri );
if ( landingPageRequest.request( synchronous, forceRefresh ) &&
landingPageRequest.errorCode() == QgsBaseNetworkRequest::NoError )
{
QString url = landingPageRequest.collectionsUrl();
while ( !url.isEmpty() )
{
QgsOapifCollectionsRequest collectionsRequest( uri, url );
url.clear();
if ( collectionsRequest.request( synchronous, forceRefresh ) &&
collectionsRequest.errorCode() == QgsBaseNetworkRequest::NoError )
{
for ( const auto &collection : collectionsRequest.collections() )
{
QgsWfsLayerItem *layer = new QgsWfsLayerItem(
this, mName, uri, collection.mId, collection.mTitle,
QString(), QgsOapifProvider::OAPIF_PROVIDER_KEY );
layers.append( layer );
}
url = collectionsRequest.nextUrl();
}
}
}
return layers;
}
QVector<QgsDataItem *> QgsWfsConnectionItem::createChildren()
{
QgsDataSourceUri uri( mUri );
QgsDebugMsg( "mUri = " + mUri );
QgsWfsCapabilities capabilities( mUri );
const bool synchronous = true;
const bool forceRefresh = false;
capabilities.requestCapabilities( synchronous, forceRefresh );
QVector<QgsDataItem *> layers;
if ( capabilities.errorCode() == QgsWfsCapabilities::NoError )
auto version = QgsWFSDataSourceURI( mUri ).version();
if ( version == QLatin1String( "OGC_API_FEATURES" ) )
{
const auto featureTypes = capabilities.capabilities().featureTypes;
for ( const QgsWfsCapabilities::FeatureType &featureType : featureTypes )
{
QgsWfsLayerItem *layer = new QgsWfsLayerItem( this, mName, uri, featureType.name, featureType.title, !featureType.crslist.isEmpty() ? featureType.crslist.first() : QString() );
layers.append( layer );
}
return createChildrenOapif();
}
else
{
//layers.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) );
// TODO: show the error without adding child
}
QgsWfsCapabilities capabilities( mUri );
if ( version == QgsWFSConstants::VERSION_AUTO )
{
capabilities.setLogErrors( false ); // as this might be a OAPIF server
}
capabilities.requestCapabilities( synchronous, forceRefresh );
return layers;
QVector<QgsDataItem *> layers;
if ( capabilities.errorCode() == QgsWfsCapabilities::NoError )
{
const auto featureTypes = capabilities.capabilities().featureTypes;
for ( const QgsWfsCapabilities::FeatureType &featureType : featureTypes )
{
QgsWfsLayerItem *layer = new QgsWfsLayerItem(
this, mName, uri, featureType.name, featureType.title,
!featureType.crslist.isEmpty() ? featureType.crslist.first() : QString(),
QgsWFSProvider::WFS_PROVIDER_KEY );
layers.append( layer );
}
}
else if ( version == QgsWFSConstants::VERSION_AUTO )
{
return createChildrenOapif();
}
return layers;
}
}
@ -233,7 +285,7 @@ QgsDataItem *QgsWfsDataItemProvider::createDataItem( const QString &path, QgsDat
QgsDebugMsgLevel( "WFS path = " + path, 4 );
if ( path.isEmpty() )
{
return new QgsWfsRootItem( parentItem, QStringLiteral( "WFS" ), QStringLiteral( "wfs:" ) );
return new QgsWfsRootItem( parentItem, QStringLiteral( "WFS / OGC API - Features" ), QStringLiteral( "wfs:" ) );
}
// path schema: wfs:/connection name (used by OWS)

View File

@ -55,7 +55,7 @@ class QgsWfsConnectionItem : public QgsDataCollectionItem
private:
QString mUri;
QgsWfsCapabilities *mWfsCapabilities = nullptr;
QVector<QgsDataItem *> createChildrenOapif();
};
@ -64,7 +64,7 @@ class QgsWfsLayerItem : public QgsLayerItem
Q_OBJECT
public:
QgsWfsLayerItem( QgsDataItem *parent, QString name, const QgsDataSourceUri &uri, QString featureType, QString title, QString crsString );
QgsWfsLayerItem( QgsDataItem *parent, QString name, const QgsDataSourceUri &uri, QString featureType, QString title, QString crsString, const QString &providerKey );
QList<QMenu *> menus( QWidget *parent ) override;

View File

@ -372,6 +372,10 @@ QString QgsWFSDataSourceURI::build( const QString &baseUri,
uri.setSql( sql );
if ( restrictToCurrentViewExtent )
uri.mURI.setParam( QgsWFSConstants::URI_PARAM_RESTRICT_TO_REQUEST_BBOX, QStringLiteral( "1" ) );
if ( uri.version() == QStringLiteral( "OGC_API_FEATURES" ) )
{
uri.setVersion( QString() );
}
return uri.uri();
}

View File

@ -13,11 +13,15 @@
* *
***************************************************************************/
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgswfsnewconnection.h"
#include "qgswfsguiutils.h"
#include <QMessageBox>
#include <algorithm>
QgsWFSNewConnection::QgsWFSNewConnection( QWidget *parent, const QString &connName ):
QgsNewHttpConnection( parent, QgsNewHttpConnection::ConnectionWfs, QgsWFSConstants::CONNECTIONS_WFS, connName )
{
@ -26,28 +30,30 @@ QgsWFSNewConnection::QgsWFSNewConnection( QWidget *parent, const QString &connNa
QgsWFSNewConnection::~QgsWFSNewConnection()
{
if ( mCapabilities )
if ( mCapabilities || mOAPIFLandingPage || mOAPIFApi )
{
QApplication::restoreOverrideCursor();
delete mCapabilities;
}
}
void QgsWFSNewConnection::versionDetectButton()
QgsDataSourceUri QgsWFSNewConnection::createUri()
{
delete mCapabilities;
// Honor any defined authentication settings
QgsDataSourceUri uri = QgsDataSourceUri();
QgsDataSourceUri uri;
uri.setParam( QStringLiteral( "url" ), urlTrimmed().toString() );
uri.setUsername( authSettingsWidget()->username() );
uri.setPassword( authSettingsWidget()->password() );
uri.setAuthConfigId( authSettingsWidget()->configId() );
return uri;
}
mCapabilities = new QgsWfsCapabilities( uri.uri( false ) );
connect( mCapabilities, &QgsWfsCapabilities::gotCapabilities, this, &QgsWFSNewConnection::capabilitiesReplyFinished );
void QgsWFSNewConnection::versionDetectButton()
{
mCapabilities.reset( new QgsWfsCapabilities( createUri().uri( false ) ) );
connect( mCapabilities.get(), &QgsWfsCapabilities::gotCapabilities, this, &QgsWFSNewConnection::capabilitiesReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
mCapabilities->setLogErrors( false ); // as this might be a OAPIF server
if ( mCapabilities->requestCapabilities( synchronous, forceRefresh ) )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
@ -59,8 +65,7 @@ void QgsWFSNewConnection::versionDetectButton()
box->setModal( true );
box->open();
delete mCapabilities;
mCapabilities = nullptr;
mCapabilities.reset();
}
}
@ -74,32 +79,136 @@ void QgsWFSNewConnection::capabilitiesReplyFinished()
auto err = mCapabilities->errorCode();
if ( err != QgsBaseNetworkRequest::NoError )
{
QgsWfsGuiUtils::displayErrorMessageOnFailedCapabilities( mCapabilities, this );
delete mCapabilities;
mCapabilities = nullptr;
startOapifLandingPageRequest();
return;
}
const auto &caps = mCapabilities->capabilities();
int versionIdx = 0;
int versionIdx = WFS_VERSION_MAX;
wfsPageSizeLineEdit()->clear();
if ( caps.version.startsWith( QLatin1String( "1.0" ) ) )
{
versionIdx = 1;
versionIdx = WFS_VERSION_1_0;
}
else if ( caps.version.startsWith( QLatin1String( "1.1" ) ) )
{
versionIdx = 2;
versionIdx = WFS_VERSION_1_1;
}
else if ( caps.version.startsWith( QLatin1String( "2.0" ) ) )
{
versionIdx = 3;
versionIdx = WFS_VERSION_2_0;
wfsPageSizeLineEdit()->setText( QString::number( caps.maxFeatures ) );
}
wfsVersionComboBox()->setCurrentIndex( versionIdx );
wfsPagingEnabledCheckBox()->setChecked( caps.supportsPaging );
delete mCapabilities;
mCapabilities = nullptr;
mCapabilities.reset();
}
void QgsWFSNewConnection::startOapifLandingPageRequest()
{
mOAPIFLandingPage.reset( new QgsOapifLandingPageRequest( createUri() ) );
connect( mOAPIFLandingPage.get(), &QgsOapifLandingPageRequest::gotResponse, this, &QgsWFSNewConnection::oapifLandingPageReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
if ( mOAPIFLandingPage->request( synchronous, forceRefresh ) )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
}
else
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, tr( "Error" ), tr( "Could not get landing page" ), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
mOAPIFLandingPage.reset();
}
}
void QgsWFSNewConnection::oapifLandingPageReplyFinished()
{
if ( !mOAPIFLandingPage )
return;
QApplication::restoreOverrideCursor();
if ( mOAPIFLandingPage->errorCode() != QgsBaseNetworkRequest::NoError )
{
if ( mOAPIFLandingPage->errorCode() == QgsBaseNetworkRequest::ApplicationLevelError )
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, QObject::tr( "Invalid response" ), mOAPIFLandingPage->errorMessage(), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
}
else if ( mCapabilities )
{
QgsMessageLog::logMessage( mCapabilities->errorMessage(), tr( "WFS" ) );
QgsWfsGuiUtils::displayErrorMessageOnFailedCapabilities( mCapabilities.get(), this );
}
mCapabilities.reset();
mOAPIFLandingPage.reset();
return;
}
wfsVersionComboBox()->setCurrentIndex( WFS_VERSION_API_FEATURES );
wfsPagingEnabledCheckBox()->setChecked( true );
mCapabilities.reset();
startOapifApiRequest();
}
void QgsWFSNewConnection::startOapifApiRequest()
{
Q_ASSERT( mOAPIFLandingPage );
mOAPIFApi.reset( new QgsOapifApiRequest( createUri(), mOAPIFLandingPage->apiUrl() ) );
mOAPIFLandingPage.reset();
connect( mOAPIFApi.get(), &QgsOapifApiRequest::gotResponse, this, &QgsWFSNewConnection::oapifApiReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
if ( mOAPIFApi->request( synchronous, forceRefresh ) )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
}
else
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, tr( "Error" ), tr( "Could not get API" ), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
mOAPIFApi.reset();
}
}
void QgsWFSNewConnection::oapifApiReplyFinished()
{
if ( !mOAPIFApi )
return;
QApplication::restoreOverrideCursor();
if ( mOAPIFApi->errorCode() != QgsBaseNetworkRequest::NoError )
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, QObject::tr( "Invalid response" ), mOAPIFApi->errorMessage(), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
mOAPIFApi.reset();
return;
}
wfsPageSizeLineEdit()->clear();
if ( mOAPIFApi->defaultLimit() > 0 && mOAPIFApi->maxLimit() > 0 )
wfsPageSizeLineEdit()->setText( QString::number( std::min( std::max( 1000, mOAPIFApi->defaultLimit() ), mOAPIFApi->maxLimit() ) ) );
else if ( mOAPIFApi->defaultLimit() > 0 )
wfsPageSizeLineEdit()->setText( QString::number( mOAPIFApi->defaultLimit() ) );
else if ( mOAPIFApi->maxLimit() > 0 )
wfsPageSizeLineEdit()->setText( QString::number( mOAPIFApi->maxLimit() ) );
mOAPIFApi.reset();
}

View File

@ -19,6 +19,8 @@
#include "qgsnewhttpconnection.h"
#include "qgswfsconstants.h"
#include "qgswfscapabilities.h"
#include "qgsoapiflandingpagerequest.h"
#include "qgsoapifapirequest.h"
class QgsWFSNewConnection : public QgsNewHttpConnection
{
@ -32,10 +34,17 @@ class QgsWFSNewConnection : public QgsNewHttpConnection
private slots:
void versionDetectButton();
void capabilitiesReplyFinished();
void oapifLandingPageReplyFinished();
void oapifApiReplyFinished();
private:
QgsWfsCapabilities *mCapabilities = nullptr;
QgsDataSourceUri createUri();
void startOapifLandingPageRequest();
void startOapifApiRequest();
std::unique_ptr<QgsWfsCapabilities> mCapabilities;
std::unique_ptr<QgsOapifLandingPageRequest> mOAPIFLandingPage;
std::unique_ptr<QgsOapifApiRequest> mOAPIFApi;
};
#endif //QGSWFSNEWCONNECTION_H

View File

@ -25,8 +25,8 @@ class QgsWfsSourceSelectProvider : public QgsSourceSelectProvider
{
public:
QString providerKey() const override { return QStringLiteral( "WFS" ); }
QString text() const override { return QObject::tr( "WFS" ); }
QString providerKey() const override { return QgsWFSProvider::WFS_PROVIDER_KEY; }
QString text() const override { return QObject::tr( "WFS / OGC API - Features" ); }
int ordering() const override { return QgsSourceSelectProvider::OrderRemoteProvider + 40; }
QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddWfsLayer.svg" ) ); }
QgsAbstractDataSourceWidget *createDataSourceWidget( QWidget *parent = nullptr, Qt::WindowFlags fl = Qt::Widget, QgsProviderRegistry::WidgetMode widgetMode = QgsProviderRegistry::WidgetMode::Embedded ) const override

View File

@ -29,6 +29,7 @@
#include "qgscoordinatetransform.h"
#include "qgslogger.h"
#include "qgsmanageconnectionsdialog.h"
#include "qgsoapifprovider.h"
#include "qgssqlstatement.h"
#include "qgssettings.h"
#include "qgsgui.h"
@ -121,7 +122,6 @@ QgsWFSSourceSelect::~QgsWFSSourceSelect()
delete mItemDelegate;
delete mProjectionSelector;
delete mCapabilities;
delete mModel;
delete mModelProxy;
delete mBuildQueryButton;
@ -169,10 +169,7 @@ void QgsWFSSourceSelect::populateConnectionList()
cmbConnections->setCurrentIndex( index );
}
QgsWfsConnection connection( cmbConnections->currentText() );
delete mCapabilities;
mCapabilities = new QgsWfsCapabilities( connection.uri().uri() );
connect( mCapabilities, &QgsWfsCapabilities::gotCapabilities, this, &QgsWFSSourceSelect::capabilitiesReplyFinished );
changeConnection();
}
QString QgsWFSSourceSelect::getPreferredCrs( const QSet<QString> &crsSet ) const
@ -222,9 +219,16 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
auto err = mCapabilities->errorCode();
if ( err != QgsBaseNetworkRequest::NoError )
{
QgsWfsGuiUtils::displayErrorMessageOnFailedCapabilities( mCapabilities, this );
emit enableButtons( false );
if ( mVersion == QgsWFSConstants::VERSION_AUTO )
{
startOapifLandingPageRequest();
}
else
{
QgsWfsGuiUtils::displayErrorMessageOnFailedCapabilities( mCapabilities.get(), this );
mCapabilities.reset();
emit enableButtons( false );
}
return;
}
@ -248,7 +252,13 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
mAvailableCRS.insert( featureType.name, featureType.crslist );
}
if ( !mCaps.featureTypes.isEmpty() )
resizeTreeViewAfterModelFill();
}
void QgsWFSSourceSelect::resizeTreeViewAfterModelFill()
{
if ( mModel->rowCount() > 0 )
{
treeView->resizeColumnToContents( MODEL_IDX_TITLE );
treeView->resizeColumnToContents( MODEL_IDX_NAME );
@ -276,6 +286,113 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished()
}
}
void QgsWFSSourceSelect::startOapifLandingPageRequest()
{
QgsWfsConnection connection( cmbConnections->currentText() );
mOAPIFLandingPage.reset( new QgsOapifLandingPageRequest( connection.uri() ) );
connect( mOAPIFLandingPage.get(), &QgsOapifLandingPageRequest::gotResponse, this, &QgsWFSSourceSelect::oapifLandingPageReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
mOAPIFLandingPage->request( synchronous, forceRefresh );
QApplication::setOverrideCursor( Qt::WaitCursor );
btnConnect->setEnabled( false );
}
void QgsWFSSourceSelect::oapifLandingPageReplyFinished()
{
QApplication::restoreOverrideCursor();
btnConnect->setEnabled( true );
if ( !mOAPIFLandingPage )
return;
auto err = mOAPIFLandingPage->errorCode();
if ( err != QgsBaseNetworkRequest::NoError )
{
if ( mVersion == QgsWFSConstants::VERSION_AUTO && mCapabilities )
{
QgsWfsGuiUtils::displayErrorMessageOnFailedCapabilities( mCapabilities.get(), this );
mCapabilities.reset();
}
else
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, tr( "Error" ), mOAPIFLandingPage->errorMessage(), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
}
mOAPIFLandingPage.reset();
emit enableButtons( false );
return;
}
mCapabilities.reset();
mAvailableCRS.clear();
QString url( mOAPIFLandingPage->collectionsUrl() );
mOAPIFLandingPage.reset();
startOapifCollectionsRequest( url );
}
void QgsWFSSourceSelect::startOapifCollectionsRequest( const QString &url )
{
QgsWfsConnection connection( cmbConnections->currentText() );
mOAPIFCollections.reset( new QgsOapifCollectionsRequest( connection.uri(), url ) );
connect( mOAPIFCollections.get(), &QgsOapifCollectionsRequest::gotResponse, this, &QgsWFSSourceSelect::oapifCollectionsReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
mOAPIFCollections->request( synchronous, forceRefresh );
QApplication::setOverrideCursor( Qt::WaitCursor );
btnConnect->setEnabled( false );
}
void QgsWFSSourceSelect::oapifCollectionsReplyFinished()
{
QApplication::restoreOverrideCursor();
btnConnect->setEnabled( true );
if ( !mOAPIFCollections )
return;
auto err = mOAPIFCollections->errorCode();
if ( err != QgsBaseNetworkRequest::NoError )
{
QMessageBox *box = new QMessageBox( QMessageBox::Critical, tr( "Error" ), mOAPIFCollections->errorMessage(), QMessageBox::Ok, this );
box->setAttribute( Qt::WA_DeleteOnClose );
box->setModal( true );
box->open();
mOAPIFCollections.reset();
emit enableButtons( false );
return;
}
for ( const auto &collection : mOAPIFCollections->collections() )
{
// insert the typenames, titles and abstracts into the tree view
QStandardItem *titleItem = new QStandardItem( collection.mTitle );
QStandardItem *nameItem = new QStandardItem( collection.mId );
QStandardItem *abstractItem = new QStandardItem( collection.mDescription );
abstractItem->setToolTip( "<font color=black>" + collection.mDescription + "</font>" );
abstractItem->setTextAlignment( Qt::AlignLeft | Qt::AlignTop );
QStandardItem *filterItem = new QStandardItem();
typedef QList< QStandardItem * > StandardItemList;
mModel->appendRow( StandardItemList() << titleItem << nameItem << abstractItem << filterItem );
}
if ( !mOAPIFCollections->nextUrl().isEmpty() )
{
QString url( mOAPIFCollections->nextUrl() );
mOAPIFCollections.reset();
startOapifCollectionsRequest( url );
return;
}
mVersion = QStringLiteral( "OGC_API_FEATURES" );
resizeTreeViewAfterModelFill();
}
void QgsWFSSourceSelect::addEntryToServerList()
{
auto nc = new QgsWFSNewConnection( this );
@ -339,10 +456,24 @@ void QgsWFSSourceSelect::connectToServer()
{
mModel->removeRows( 0, mModel->rowCount() );
}
if ( mCapabilities )
QgsWfsConnection connection( cmbConnections->currentText() );
mVersion = QgsWFSDataSourceURI( connection.uri().uri() ).version();
if ( mVersion == QLatin1String( "OGC_API_FEATURES" ) )
{
startOapifLandingPageRequest();
}
else
{
mCapabilities.reset( new QgsWfsCapabilities( connection.uri().uri() ) );
connect( mCapabilities.get(), &QgsWfsCapabilities::gotCapabilities, this, &QgsWFSSourceSelect::capabilitiesReplyFinished );
const bool synchronous = false;
const bool forceRefresh = true;
if ( mVersion == QgsWFSConstants::VERSION_AUTO )
{
mCapabilities->setLogErrors( false ); // as this might be a OAPIF server
}
mCapabilities->requestCapabilities( synchronous, forceRefresh );
QApplication::setOverrideCursor( Qt::WaitCursor );
}
@ -386,7 +517,7 @@ void QgsWFSSourceSelect::addButtonClicked()
mUri = QgsWFSDataSourceURI::build( connection.uri().uri( false ), typeName, pCrsString,
sql, cbxFeatureCurrentViewExtent->isChecked() );
emit addVectorLayer( mUri, layerName );
emit addVectorLayer( mUri, layerName, isOapif() ? QgsOapifProvider::OAPIF_PROVIDER_KEY : QgsWFSProvider::WFS_PROVIDER_KEY );
}
if ( ! mHoldDialogOpen->isChecked() && widgetMode() == QgsProviderRegistry::WidgetMode::None )
@ -689,12 +820,13 @@ void QgsWFSSourceSelect::cmbConnections_activated( int index )
{
Q_UNUSED( index )
QgsWfsConnection::setSelectedConnection( cmbConnections->currentText() );
changeConnection();
}
QgsWfsConnection connection( cmbConnections->currentText() );
delete mCapabilities;
mCapabilities = new QgsWfsCapabilities( connection.uri().uri() );
connect( mCapabilities, &QgsWfsCapabilities::gotCapabilities, this, &QgsWFSSourceSelect::capabilitiesReplyFinished );
void QgsWFSSourceSelect::changeConnection()
{
mCapabilities.reset();
mOAPIFLandingPage.reset();
}
void QgsWFSSourceSelect::btnSave_clicked()
@ -720,6 +852,8 @@ void QgsWFSSourceSelect::btnLoad_clicked()
void QgsWFSSourceSelect::treeWidgetItemDoubleClicked( const QModelIndex &index )
{
if ( isOapif() )
return;
QgsDebugMsg( QStringLiteral( "double-click called" ) );
buildQuery( index );
}
@ -729,7 +863,7 @@ void QgsWFSSourceSelect::treeWidgetCurrentRowChanged( const QModelIndex &current
Q_UNUSED( previous )
QgsDebugMsg( QStringLiteral( "treeWidget_currentRowChanged called" ) );
changeCRSFilter();
mBuildQueryButton->setEnabled( current.isValid() );
mBuildQueryButton->setEnabled( !isOapif() && current.isValid() );
emit enableButtons( current.isValid() );
}

View File

@ -21,6 +21,8 @@
#include "ui_qgswfssourceselectbase.h"
#include "qgshelp.h"
#include "qgswfscapabilities.h"
#include "qgsoapiflandingpagerequest.h"
#include "qgsoapifcollection.h"
#include "qgsproviderregistry.h"
#include "qgsabstractdatasourcewidget.h"
#include "qgssqlcomposerdialog.h"
@ -78,7 +80,9 @@ class QgsWFSSourceSelect: public QgsAbstractDataSourceWidget, private Ui::QgsWFS
The first string is the typename, the corresponding list
stores the CRS for the typename in the form 'EPSG:XXXX'*/
QMap<QString, QStringList > mAvailableCRS;
QgsWfsCapabilities *mCapabilities = nullptr;
std::unique_ptr<QgsWfsCapabilities> mCapabilities;
std::unique_ptr<QgsOapifLandingPageRequest> mOAPIFLandingPage;
std::unique_ptr<QgsOapifCollectionsRequest> mOAPIFCollections;
QString mUri; // data source URI
QgsWFSItemDelegate *mItemDelegate = nullptr;
QStandardItemModel *mModel = nullptr;
@ -87,6 +91,7 @@ class QgsWFSSourceSelect: public QgsAbstractDataSourceWidget, private Ui::QgsWFS
QgsWfsCapabilities::Capabilities mCaps;
QModelIndex mSQLIndex;
QgsSQLComposerDialog *mSQLComposerDialog = nullptr;
QString mVersion;
/**
* Returns the best suited CRS from a set of authority ids
@ -114,6 +119,8 @@ class QgsWFSSourceSelect: public QgsAbstractDataSourceWidget, private Ui::QgsWFS
void changeCRSFilter();
void cmbConnections_activated( int index );
void capabilitiesReplyFinished();
void oapifLandingPageReplyFinished();
void oapifCollectionsReplyFinished();
void btnSave_clicked();
void btnLoad_clicked();
void treeWidgetItemDoubleClicked( const QModelIndex &index );
@ -123,7 +130,11 @@ class QgsWFSSourceSelect: public QgsAbstractDataSourceWidget, private Ui::QgsWFS
void updateSql();
void populateConnectionList();
void changeConnection();
void startOapifLandingPageRequest();
void startOapifCollectionsRequest( const QString &url );
void resizeTreeViewAfterModelFill();
bool isOapif() const { return mVersion == QLatin1String( "OGC_API_FEATURES" ); }
};

View File

@ -117,6 +117,8 @@ class TestPyQgsWFSProviderGUI(unittest.TestCase):
QTest.mouseClick(btnConnect, Qt.LeftButton)
# Depends on asynchronous signal
QApplication.processEvents()
# Second attempt for OAPIF request
QApplication.processEvents()
error_box = find_window('WFSCapabilitiesErrorBox')
self.assertIsNotNone(error_box)
# Close error box