From 2eb82430bbdb02b0789b3ffe80d5b6fd747fa8cc Mon Sep 17 00:00:00 2001 From: "Juergen E. Fischer" Date: Fri, 4 Mar 2016 23:51:04 +0100 Subject: [PATCH] use individual network managers for threads (fixes #13721, fixes #14401, implements #14192) --- python/core/qgsnetworkaccessmanager.sip | 19 ---- src/app/qgisapp.cpp | 69 ++++++++------ src/core/CMakeLists.txt | 2 + src/core/qgsnetworkaccessmanager.cpp | 72 +++++++------- src/core/qgsnetworkaccessmanager.h | 22 +---- src/core/qgsnetworkdiskcache.cpp | 115 +++++++++++++++++++++++ src/core/qgsnetworkdiskcache.h | 100 ++++++++++++++++++++ src/gui/qgscredentialdialog.cpp | 1 + src/providers/wcs/qgswcscapabilities.cpp | 37 +++----- src/providers/wcs/qgswcscapabilities.h | 3 +- src/providers/wcs/qgswcsprovider.cpp | 30 +----- src/providers/wcs/qgswcsprovider.h | 3 - src/providers/wfs/qgswfsdataitems.cpp | 17 +--- src/providers/wfs/qgswfsdataitems.h | 3 - src/providers/wms/qgswmscapabilities.cpp | 55 ++--------- src/providers/wms/qgswmscapabilities.h | 18 +--- src/providers/wms/qgswmsprovider.cpp | 44 ++------- src/providers/wms/qgswmsprovider.h | 2 - 18 files changed, 341 insertions(+), 271 deletions(-) create mode 100644 src/core/qgsnetworkdiskcache.cpp create mode 100644 src/core/qgsnetworkdiskcache.h diff --git a/python/core/qgsnetworkaccessmanager.sip b/python/core/qgsnetworkaccessmanager.sip index 744486bf542..b4e1e831978 100644 --- a/python/core/qgsnetworkaccessmanager.sip +++ b/python/core/qgsnetworkaccessmanager.sip @@ -62,29 +62,10 @@ class QgsNetworkAccessManager : QNetworkAccessManager bool useSystemProxy(); - public slots: - /** Send GET request, calls get(). - * Emits requestSent(). - * @param request request to be sent - */ - void sendGet( const QNetworkRequest & request ); - /** Abort and delete reply. This slot may be used to abort reply created by instance of this class - * (and which was not moved to another thread) from a different thread. Such reply cannot - * be aborted directly from a different thread. The reply must be also deleted - * in this slot, otherwise it could happen that abort signal comes after the reply was deleted. - * @param reply reply to be aborted. - */ - void deleteReply( QNetworkReply * reply ); - signals: void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * ); void requestCreated( QNetworkReply * ); void requestTimedOut( QNetworkReply * ); - /** Emitted when request was sent by request() - * @param reply request reply - * @param sender the object which called request() slot. - */ - void requestSent( QNetworkReply * reply, QObject *sender ); protected: virtual QNetworkReply *createRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0 ); diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 821f5de54da..698eea14267 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -79,7 +79,6 @@ #include #include #include -#include // // Mac OS X Includes @@ -398,7 +397,7 @@ static void setTitleBarText_( QWidget & qgisApp ) */ static QgsMessageOutput *messageOutputViewer_() { - if ( QThread::currentThread() == QApplication::instance()->thread() ) + if ( QThread::currentThread() == qApp->thread() ) return new QgsMessageViewer( QgisApp::instance() ); else return new QgsMessageOutputConsole(); @@ -10864,6 +10863,8 @@ void QgisApp::namSetup() void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *auth ) { + Q_ASSERT( qApp->thread() == QThread::currentThread() ); + QString username = auth->user(); QString password = auth->password(); @@ -10882,31 +10883,38 @@ void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *a } } + for ( ;; ) { - QMutexLocker lock( QgsCredentials::instance()->mutex() ); + bool ok; - for ( ;; ) { - bool ok = QgsCredentials::instance()->get( - QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ), - username, password, - tr( "Authentication required" ) ); - if ( !ok ) - return; + QMutexLocker lock( QgsCredentials::instance()->mutex() ); + ok = QgsCredentials::instance()->get( + QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ), + username, password, + tr( "Authentication required" ) ); + } + if ( !ok ) + return; - if ( reply->isFinished() ) - return; + if ( reply->isFinished() ) + return; - if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) ) - break; + if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) ) + break; - // credentials didn't change - stored ones probably wrong? clear password and retry + // credentials didn't change - stored ones probably wrong? clear password and retry + { + QMutexLocker lock( QgsCredentials::instance()->mutex() ); QgsCredentials::instance()->put( QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ), username, QString::null ); } + } - // save credentials + // save credentials + { + QMutexLocker lock( QgsCredentials::instance()->mutex() ); QgsCredentials::instance()->put( QString( "%1 at %2" ).arg( auth->realm(), reply->url().host() ), username, password @@ -10930,27 +10938,34 @@ void QgisApp::namProxyAuthenticationRequired( const QNetworkProxy &proxy, QAuthe QString username = auth->user(); QString password = auth->password(); + for ( ;; ) { - QMutexLocker lock( QgsCredentials::instance()->mutex() ); + bool ok; - for ( ;; ) { - bool ok = QgsCredentials::instance()->get( - QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), - username, password, - tr( "Proxy authentication required" ) ); - if ( !ok ) - return; + QMutexLocker lock( QgsCredentials::instance()->mutex() ); + ok = QgsCredentials::instance()->get( + QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), + username, password, + tr( "Proxy authentication required" ) ); + } + if ( !ok ) + return; - if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) ) - break; + if ( auth->user() != username || ( password != auth->password() && !password.isNull() ) ) + break; - // credentials didn't change - stored ones probably wrong? clear password and retry + // credentials didn't change - stored ones probably wrong? clear password and retry + { + QMutexLocker lock( QgsCredentials::instance()->mutex() ); QgsCredentials::instance()->put( QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), username, QString::null ); } + } + { + QMutexLocker lock( QgsCredentials::instance()->mutex() ); QgsCredentials::instance()->put( QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), username, password diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 95227e6d853..f6a686913dd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -149,6 +149,7 @@ SET(QGIS_CORE_SRCS qgsmimedatautils.cpp qgsmultirenderchecker.cpp qgsnetworkaccessmanager.cpp + qgsnetworkdiskcache.cpp qgsnetworkcontentfetcher.cpp qgsnetworkreplyparser.cpp qgsobjectcustomproperties.cpp @@ -452,6 +453,7 @@ SET(QGIS_CORE_MOC_HDRS qgsmessagelog.h qgsmessageoutput.h qgsnetworkaccessmanager.h + qgsnetworkdiskcache.h qgsnetworkcontentfetcher.h qgsnetworkreplyparser.h qgsofflineediting.h diff --git a/src/core/qgsnetworkaccessmanager.cpp b/src/core/qgsnetworkaccessmanager.cpp index 1acb55326dd..29fd7485146 100644 --- a/src/core/qgsnetworkaccessmanager.cpp +++ b/src/core/qgsnetworkaccessmanager.cpp @@ -30,14 +30,17 @@ #include #include #include -#include +#include #ifndef QT_NO_OPENSSL #include #endif +#include "qgsnetworkdiskcache.h" #include "qgsauthmanager.h" +QgsNetworkAccessManager *QgsNetworkAccessManager::smMainNAM = 0; + /// @cond PRIVATE class QgsNetworkProxyFactory : public QNetworkProxyFactory { @@ -99,13 +102,22 @@ class QgsNetworkProxyFactory : public QNetworkProxyFactory // QgsNetworkAccessManager* QgsNetworkAccessManager::instance() { - static QgsNetworkAccessManager* sInstance( new QgsNetworkAccessManager( QApplication::instance() ) ); - return sInstance; + static QThreadStorage sInstances; + QgsNetworkAccessManager *nam = &sInstances.localData(); + + if ( nam->thread() == qApp->thread() ) + smMainNAM = nam; + + if ( !nam->mInitialized ) + nam->setupDefaultProxyAndCache(); + + return nam; } QgsNetworkAccessManager::QgsNetworkAccessManager( QObject *parent ) : QNetworkAccessManager( parent ) , mUseSystemProxy( false ) + , mInitialized( false ) { setProxyFactory( new QgsNetworkProxyFactory() ); } @@ -221,6 +233,8 @@ void QgsNetworkAccessManager::abortRequest() QNetworkReply *reply = qobject_cast( timer->parent() ); Q_ASSERT( reply ); + QgsDebugMsg( QString( "Abort [reply:%1]" ).arg(( qint64 ) reply, 0, 16 ) ); + QgsMessageLog::logMessage( tr( "Network request %1 timed out" ).arg( reply->url().toString() ), tr( "Network" ) ); if ( reply->isRunning() ) @@ -270,36 +284,36 @@ QNetworkRequest::CacheLoadControl QgsNetworkAccessManager::cacheLoadControlFromN void QgsNetworkAccessManager::setupDefaultProxyAndCache() { - QNetworkProxy proxy; - QStringList excludes; - - QSettings settings; - + mInitialized = true; mUseSystemProxy = false; - if ( this != instance() ) - { - Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection; + Q_ASSERT( smMainNAM ); + if ( smMainNAM != this ) + { connect( this, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ), - instance(), SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ), - connectionType ); + smMainNAM, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ), + Qt::BlockingQueuedConnection ); connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), - instance(), SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), - connectionType ); + smMainNAM, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), + Qt::BlockingQueuedConnection ); connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ), - instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) ); + smMainNAM, SIGNAL( requestTimedOut( QNetworkReply* ) ) ); #ifndef QT_NO_OPENSSL connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), - instance(), SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), - connectionType ); + smMainNAM, SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), + Qt::BlockingQueuedConnection ); #endif } // check if proxy is enabled + QSettings settings; + QNetworkProxy proxy; + QStringList excludes; + bool proxyEnabled = settings.value( "proxy/proxyEnabled", false ).toBool(); if ( proxyEnabled ) { @@ -354,9 +368,9 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache() setFallbackProxyAndExcludes( proxy, excludes ); - QNetworkDiskCache *newcache = qobject_cast( cache() ); + QgsNetworkDiskCache *newcache = qobject_cast( cache() ); if ( !newcache ) - newcache = new QNetworkDiskCache( this ); + newcache = new QgsNetworkDiskCache( this ); QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString(); qint64 cacheSize = settings.value( "cache/size", 50 * 1024 * 1024 ).toULongLong(); @@ -370,21 +384,3 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache() if ( cache() != newcache ) setCache( newcache ); } - -void QgsNetworkAccessManager::sendGet( const QNetworkRequest & request ) -{ - QgsDebugMsg( "Entered" ); - QNetworkReply * reply = get( request ); - emit requestSent( reply, QObject::sender() ); -} - -void QgsNetworkAccessManager::deleteReply( QNetworkReply * reply ) -{ - QgsDebugMsg( "Entered" ); - if ( !reply ) - { - return; - } - reply->abort(); - reply->deleteLater(); -} diff --git a/src/core/qgsnetworkaccessmanager.h b/src/core/qgsnetworkaccessmanager.h index 262b2644eba..10bb7fbcce0 100644 --- a/src/core/qgsnetworkaccessmanager.h +++ b/src/core/qgsnetworkaccessmanager.h @@ -82,31 +82,13 @@ class CORE_EXPORT QgsNetworkAccessManager : public QNetworkAccessManager //! Setup the NAM according to the user's settings void setupDefaultProxyAndCache(); + //! return whether the system proxy should be used bool useSystemProxy() { return mUseSystemProxy; } - public slots: - /** Send GET request, calls get(). - * Emits requestSent(). - * @param request request to be sent - */ - void sendGet( const QNetworkRequest & request ); - /** Abort and delete reply. This slot may be used to abort reply created by instance of this class - * (and which was not moved to another thread) from a different thread. Such reply cannot - * be aborted directly from a different thread. The reply must be also deleted - * in this slot, otherwise it could happen that abort signal comes after the reply was deleted. - * @param reply reply to be aborted. - */ - void deleteReply( QNetworkReply * reply ); - signals: void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * ); void requestCreated( QNetworkReply * ); void requestTimedOut( QNetworkReply * ); - /** Emitted when request was sent by request() - * @param reply request reply - * @param sender the object which called request() slot. - */ - void requestSent( QNetworkReply * reply, QObject *sender ); private slots: void abortRequest(); @@ -119,6 +101,8 @@ class CORE_EXPORT QgsNetworkAccessManager : public QNetworkAccessManager QNetworkProxy mFallbackProxy; QStringList mExcludedURLs; bool mUseSystemProxy; + bool mInitialized; + static QgsNetworkAccessManager *smMainNAM; }; #endif // QGSNETWORKACCESSMANAGER_H diff --git a/src/core/qgsnetworkdiskcache.cpp b/src/core/qgsnetworkdiskcache.cpp new file mode 100644 index 00000000000..2a1a821297f --- /dev/null +++ b/src/core/qgsnetworkdiskcache.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + qgsnetworkdiskcache.cpp - Thread-safe interface for QNetworkDiskCache + ------------------- + begin : 2016-03-05 + copyright : (C) 2016 by Juergen E. Fischer + email : jef at norbit dot de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include "qgsnetworkdiskcache.h" + +QgsNetworkDiskCache::ExpirableNetworkDiskCache QgsNetworkDiskCache::smDiskCache; +QMutex QgsNetworkDiskCache::smDiskCacheMutex; + +QgsNetworkDiskCache::QgsNetworkDiskCache( QObject *parent ) + : QNetworkDiskCache( parent ) +{ +} + +QgsNetworkDiskCache::~QgsNetworkDiskCache() +{ +} + +QString QgsNetworkDiskCache::cacheDirectory() const +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.cacheDirectory(); +} + +void QgsNetworkDiskCache::setCacheDirectory( const QString &cacheDir ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + smDiskCache.setCacheDirectory( cacheDir ); +} + +qint64 QgsNetworkDiskCache::maximumCacheSize() const +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.maximumCacheSize(); +} + +void QgsNetworkDiskCache::setMaximumCacheSize( qint64 size ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + smDiskCache.setMaximumCacheSize( size ); +} + +qint64 QgsNetworkDiskCache::cacheSize() const +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.cacheSize(); +} + +QNetworkCacheMetaData QgsNetworkDiskCache::metaData( const QUrl &url ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.metaData( url ); +} + +void QgsNetworkDiskCache::updateMetaData( const QNetworkCacheMetaData &metaData ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + smDiskCache.updateMetaData( metaData ); +} + +QIODevice *QgsNetworkDiskCache::data( const QUrl &url ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.data( url ); +} + +bool QgsNetworkDiskCache::remove( const QUrl &url ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.remove( url ); +} + +QIODevice *QgsNetworkDiskCache::prepare( const QNetworkCacheMetaData &metaData ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.prepare( metaData ); +} + +void QgsNetworkDiskCache::insert( QIODevice *device ) +{ + QMutexLocker lock( &smDiskCacheMutex ); + smDiskCache.insert( device ); +} + +QNetworkCacheMetaData QgsNetworkDiskCache::fileMetaData( const QString &fileName ) const +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.fileMetaData( fileName ); +} + +qint64 QgsNetworkDiskCache::expire() +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.runExpire(); +} + +void QgsNetworkDiskCache::clear() +{ + QMutexLocker lock( &smDiskCacheMutex ); + return smDiskCache.clear(); +} diff --git a/src/core/qgsnetworkdiskcache.h b/src/core/qgsnetworkdiskcache.h new file mode 100644 index 00000000000..a385f817ffc --- /dev/null +++ b/src/core/qgsnetworkdiskcache.h @@ -0,0 +1,100 @@ +/*************************************************************************** + qgsnetworkdiskcache.h - Thread-safe interface for QNetworkDiskCache + ------------------- + begin : 2016-03-05 + copyright : (C) 2016 by Juergen E. Fischer + email : jef at norbit dot de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSNETWORKDISKCACHE_H +#define QGSNETWORKDISKCACHE_H + +#include +#include + +class QNetworkDiskCache; + +/** + * Wrapper implementation of QNetworkDiskCache with all methods guarded by a + * mutex soly for internal use of QgsNetworkAccessManagers + * + * @note not available in Python bindings + */ +class QgsNetworkDiskCache : public QNetworkDiskCache +{ + Q_OBJECT + + public: + ~QgsNetworkDiskCache(); + + //! @see QNetworkDiskCache::cacheDirectory + QString cacheDirectory() const; + + //! @see QNetworkDiskCache::setCacheDirectory + void setCacheDirectory( const QString &cacheDir ); + + //! @see QNetworkDiskCache::maximumCacheSize() + qint64 maximumCacheSize() const; + + //! @see QNetworkDiskCache::setMaximumCacheSize() + void setMaximumCacheSize( qint64 size ); + + //! @see QNetworkDiskCache::metaData() + QNetworkCacheMetaData metaData( const QUrl &url ) override; + + //! @see QNetworkDiskCache::updateMetaData() + void updateMetaData( const QNetworkCacheMetaData &metaData ) override; + + //! @see QNetworkDiskCache::data() + QIODevice *data( const QUrl &url ) override; + + //! @see QNetworkDiskCache::remove() + bool remove( const QUrl &url ) override; + + //! @see QNetworkDiskCache::cacheSize() + qint64 cacheSize() const override; + + //! @see QNetworkDiskCache::prepare() + QIODevice *prepare( const QNetworkCacheMetaData &metaData ) override; + + //! @see QNetworkDiskCache::insert() + void insert( QIODevice *device ) override; + + //! @see QNetworkDiskCache::fileMetaData() + QNetworkCacheMetaData fileMetaData( const QString &fileName ) const; + + public slots: + //! @see QNetworkDiskCache::clear() + void clear() override; + + protected: + //! @see QNetworkDiskCache::expire() + virtual qint64 expire() override; + + private: + QgsNetworkDiskCache( QObject *parent ); + Q_DISABLE_COPY( QgsNetworkDiskCache ) + + class ExpirableNetworkDiskCache : public QNetworkDiskCache + { + public: + ExpirableNetworkDiskCache( QObject *parent = 0 ) : QNetworkDiskCache( parent ) {} + qint64 runExpire() { return QNetworkDiskCache::expire(); } + }; + + static ExpirableNetworkDiskCache smDiskCache; + static QMutex smDiskCacheMutex; + + friend class QgsNetworkAccessManager; +}; + +#endif // QGSNETWORKDISKCACHE_H diff --git a/src/gui/qgscredentialdialog.cpp b/src/gui/qgscredentialdialog.cpp index 0f4cbb88464..9394ec54818 100644 --- a/src/gui/qgscredentialdialog.cpp +++ b/src/gui/qgscredentialdialog.cpp @@ -67,6 +67,7 @@ bool QgsCredentialDialog::request( const QString& realm, QString &username, QStr void QgsCredentialDialog::requestCredentials( const QString& realm, QString *username, QString *password, const QString& message, bool *ok ) { + Q_ASSERT( qApp->thread() == thread() && thread() == QThread::currentThread() ); QgsDebugMsg( "Entering." ); stackedWidget->setCurrentIndex( 0 ); diff --git a/src/providers/wcs/qgswcscapabilities.cpp b/src/providers/wcs/qgswcscapabilities.cpp index a3abcdafaeb..f98af95d9f8 100644 --- a/src/providers/wcs/qgswcscapabilities.cpp +++ b/src/providers/wcs/qgswcscapabilities.cpp @@ -17,8 +17,6 @@ * (at your option) any later version. * * * ***************************************************************************/ -#include - #include "qgslogger.h" #include "qgswcscapabilities.h" #include "qgsowsconnection.h" @@ -32,25 +30,13 @@ #include "qgsrectangle.h" #include "qgscoordinatereferencesystem.h" #include "qgsnetworkaccessmanager.h" -#include -#include +#include "qgsmessageoutput.h" +#include "qgsmessagelog.h" #include #include -#include -#include - -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include #ifdef _MSC_VER #include @@ -175,10 +161,9 @@ bool QgsWcsCapabilities::sendRequest( QString const & url ) connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) ); - while ( mCapabilitiesReply ) - { - QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); - } + QEventLoop loop; + connect( this, SIGNAL( downloadFinished() ), &loop, SLOT( quit() ) ); + loop.exec( QEventLoop::ExcludeUserInputEvents ); if ( mCapabilitiesResponse.isEmpty() ) { @@ -271,7 +256,10 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( const QString& preferredVer QString url = getCapabilitiesUrl( preferredVersion ); - if ( ! sendRequest( url ) ) { return false; } + if ( !sendRequest( url ) ) + { + return false; + } QgsDebugMsg( "Converting to Dom." ); @@ -325,7 +313,10 @@ bool QgsWcsCapabilities::describeCoverage( QString const &identifier, bool force QString url = getDescribeCoverageUrl( coverage->identifier ); - if ( ! sendRequest( url ) ) { return false; } + if ( !sendRequest( url ) ) + { + return false; + } QgsDebugMsg( "Converting to Dom." ); @@ -416,6 +407,8 @@ void QgsWcsCapabilities::capabilitiesReplyFinished() mCapabilitiesReply->deleteLater(); mCapabilitiesReply = nullptr; + + emit downloadFinished(); } void QgsWcsCapabilities::capabilitiesReplyProgress( qint64 bytesReceived, qint64 bytesTotal ) diff --git a/src/providers/wcs/qgswcscapabilities.h b/src/providers/wcs/qgswcscapabilities.h index afa8213d3b3..c13687eec30 100644 --- a/src/providers/wcs/qgswcscapabilities.h +++ b/src/providers/wcs/qgswcscapabilities.h @@ -206,13 +206,14 @@ class QgsWcsCapabilities : public QObject static QStringList domElementsTexts( const QDomElement &element, const QString &path ); signals: - /** \brief emit a signal to notify of a progress event */ void progressChanged( int theProgress, int theTotalSteps ); /** \brief emit a signal to be caught by qgisapp and display a msg on status bar */ void statusChanged( QString const & theStatusQString ); + void downloadFinished(); + private slots: void capabilitiesReplyFinished(); void capabilitiesReplyProgress( qint64, qint64 ); diff --git a/src/providers/wcs/qgswcsprovider.cpp b/src/providers/wcs/qgswcsprovider.cpp index 672782cd413..cf73afc2183 100644 --- a/src/providers/wcs/qgswcsprovider.cpp +++ b/src/providers/wcs/qgswcsprovider.cpp @@ -3,7 +3,7 @@ OGC Web Coverage Service layers ------------------- begin : 2 July, 2012 - copyright : (C) (C) 2012 by Radim Blazek + copyright : (C) 2012 by Radim Blazek email : radim dot blazek at gmail.com Based on qgswmsprovider.cpp written by Brendan Morley. @@ -19,8 +19,6 @@ * * ***************************************************************************/ -#include - #include "qgslogger.h" #include "qgswcsprovider.h" #include "qgscoordinatetransform.h" @@ -31,20 +29,14 @@ #include "qgscoordinatereferencesystem.h" #include "qgsnetworkaccessmanager.h" #include "qgsnetworkreplyparser.h" -#include "qgsmessageoutput.h" #include "qgsmessagelog.h" #include #include #include -#include #include -#include -#include #include -#include -#include #include #ifdef QGISDEBUG @@ -1589,14 +1581,6 @@ QString QgsWcsProvider::nodeAttribute( const QDomElement &e, const QString& name return defValue; } -void QgsWcsProvider::showMessageBox( const QString& title, const QString& text ) -{ - QgsMessageOutput *message = QgsMessageOutput::createMessageOutput(); - message->setTitle( title ); - message->setMessage( text, QgsMessageOutput::MessageText ); - message->showMessage(); -} - QMap QgsWcsProvider::supportedMimes() { QMap mimes; @@ -1670,16 +1654,13 @@ QGISEXTERN bool isProvider() int QgsWcsDownloadHandler::sErrors = 0; QgsWcsDownloadHandler::QgsWcsDownloadHandler( const QUrl& url, QgsWcsAuthorization& auth, QNetworkRequest::CacheLoadControl cacheLoadControl, QByteArray& cachedData, const QString& wcsVersion, QgsError& cachedError ) - : mNAM( new QgsNetworkAccessManager ) - , mAuth( auth ) + : mAuth( auth ) , mEventLoop( new QEventLoop ) , mCacheReply( nullptr ) , mCachedData( cachedData ) , mWcsVersion( wcsVersion ) , mCachedError( cachedError ) { - mNAM->setupDefaultProxyAndCache(); - QNetworkRequest request( url ); if ( !mAuth.setAuthorization( request ) ) { @@ -1690,7 +1671,7 @@ QgsWcsDownloadHandler::QgsWcsDownloadHandler( const QUrl& url, QgsWcsAuthorizati request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl ); - mCacheReply = mNAM->get( request ); + mCacheReply = QgsNetworkAccessManager::instance()->get( request ); connect( mCacheReply, SIGNAL( finished() ), this, SLOT( cacheReplyFinished() ) ); connect( mCacheReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( cacheReplyProgress( qint64, qint64 ) ) ); } @@ -1698,7 +1679,6 @@ QgsWcsDownloadHandler::QgsWcsDownloadHandler( const QUrl& url, QgsWcsAuthorizati QgsWcsDownloadHandler::~QgsWcsDownloadHandler() { delete mEventLoop; - delete mNAM; } void QgsWcsDownloadHandler::blockingDownload() @@ -1726,7 +1706,7 @@ void QgsWcsDownloadHandler::cacheReplyFinished() tr( "WCS" ) ); return; } - mCacheReply = mNAM->get( request ); + mCacheReply = QgsNetworkAccessManager::instance()->get( request ); connect( mCacheReply, SIGNAL( finished() ), this, SLOT( cacheReplyFinished() ) ); connect( mCacheReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( cacheReplyProgress( qint64, qint64 ) ) ); @@ -1890,7 +1870,7 @@ void QgsWcsDownloadHandler::cacheReplyFinished() mCacheReply->deleteLater(); - mCacheReply = mNAM->get( request ); + mCacheReply = QgsNetworkAccessManager::instance()->get( request ); connect( mCacheReply, SIGNAL( finished() ), this, SLOT( cacheReplyFinished() ), Qt::DirectConnection ); connect( mCacheReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( cacheReplyProgress( qint64, qint64 ) ), Qt::DirectConnection ); diff --git a/src/providers/wcs/qgswcsprovider.h b/src/providers/wcs/qgswcsprovider.h index c40f0d40e5d..8d84cbd2182 100644 --- a/src/providers/wcs/qgswcsprovider.h +++ b/src/providers/wcs/qgswcsprovider.h @@ -211,8 +211,6 @@ class QgsWcsProvider : public QgsRasterDataProvider, QgsGdalProviderBase void dataChanged(); private: - void showMessageBox( const QString& title, const QString& text ); - // case insensitive attribute value lookup static QString nodeAttribute( const QDomElement &e, const QString& name, const QString& defValue = QString::null ); @@ -433,7 +431,6 @@ class QgsWcsDownloadHandler : public QObject protected: void finish() { QMetaObject::invokeMethod( mEventLoop, "quit", Qt::QueuedConnection ); } - QgsNetworkAccessManager* mNAM; QgsWcsAuthorization& mAuth; QEventLoop* mEventLoop; diff --git a/src/providers/wfs/qgswfsdataitems.cpp b/src/providers/wfs/qgswfsdataitems.cpp index 6543bffda17..c3eac8734d9 100644 --- a/src/providers/wfs/qgswfsdataitems.cpp +++ b/src/providers/wfs/qgswfsdataitems.cpp @@ -22,6 +22,7 @@ #include #include +#include QgsWFSLayerItem::QgsWFSLayerItem( QgsDataItem* parent, QString name, QgsDataSourceURI uri, QString featureType, QString title, QString crsString ) @@ -42,7 +43,6 @@ QgsWFSConnectionItem::QgsWFSConnectionItem( QgsDataItem* parent, QString name, Q : QgsDataCollectionItem( parent, name, path ) , mUri( uri ) , mCapabilities( nullptr ) - , mGotCapabilities( false ) { mIconName = "mIconWfs.svg"; } @@ -53,21 +53,17 @@ QgsWFSConnectionItem::~QgsWFSConnectionItem() QVector QgsWFSConnectionItem::createChildren() { - mGotCapabilities = false; - QgsDataSourceURI uri; uri.setEncodedUri( mUri ); QgsDebugMsg( "mUri = " + mUri ); mCapabilities = new QgsWFSCapabilities( mUri ); - connect( mCapabilities, SIGNAL( gotCapabilities() ), this, SLOT( gotCapabilities() ) ); mCapabilities->requestCapabilities(); - while ( !mGotCapabilities ) - { - QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); - } + QEventLoop loop; + connect( mCapabilities, SIGNAL( gotCapabilities() ), &loop, SLOT( quit() ) ); + loop.exec( QEventLoop::ExcludeUserInputEvents ); QVector layers; if ( mCapabilities->errorCode() == QgsWFSCapabilities::NoError ) @@ -92,11 +88,6 @@ QVector QgsWFSConnectionItem::createChildren() return layers; } -void QgsWFSConnectionItem::gotCapabilities() -{ - mGotCapabilities = true; -} - QList QgsWFSConnectionItem::actions() { QList lst; diff --git a/src/providers/wfs/qgswfsdataitems.h b/src/providers/wfs/qgswfsdataitems.h index ade31310d6e..b5e5afb12ad 100644 --- a/src/providers/wfs/qgswfsdataitems.h +++ b/src/providers/wfs/qgswfsdataitems.h @@ -52,8 +52,6 @@ class QgsWFSConnectionItem : public QgsDataCollectionItem virtual QList actions() override; private slots: - void gotCapabilities(); - void editConnection(); void deleteConnection(); @@ -61,7 +59,6 @@ class QgsWFSConnectionItem : public QgsDataCollectionItem QString mUri; QgsWFSCapabilities* mCapabilities; - bool mGotCapabilities; }; diff --git a/src/providers/wms/qgswmscapabilities.cpp b/src/providers/wms/qgswmscapabilities.cpp index 8c091779c53..edc33fb0c2f 100644 --- a/src/providers/wms/qgswmscapabilities.cpp +++ b/src/providers/wms/qgswmscapabilities.cpp @@ -1872,7 +1872,6 @@ QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( bool forceRefresh, QObje , mIsAborted( false ) , mForceRefresh( forceRefresh ) { - connectManager(); } QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( const QString& baseUrl, const QgsWmsAuthorization& auth, bool forceRefresh, QObject *parent ) @@ -1883,17 +1882,6 @@ QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( const QString& baseUrl, , mIsAborted( false ) , mForceRefresh( forceRefresh ) { - connectManager(); -} - -void QgsWmsCapabilitiesDownload::connectManager() -{ - // The instance of this class may live on a thread different from QgsNetworkAccessManager instance's thread, - // so we cannot call QgsNetworkAccessManager::get() directly and we must send a signal instead. - connect( this, SIGNAL( sendRequest( const QNetworkRequest & ) ), - QgsNetworkAccessManager::instance(), SLOT( sendGet( const QNetworkRequest & ) ) ); - connect( this, SIGNAL( deleteReply( QNetworkReply * ) ), - QgsNetworkAccessManager::instance(), SLOT( deleteReply( QNetworkReply * ) ) ); } QgsWmsCapabilitiesDownload::~QgsWmsCapabilitiesDownload() @@ -1934,9 +1922,9 @@ bool QgsWmsCapabilitiesDownload::downloadCapabilities() request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, mForceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); - connect( QgsNetworkAccessManager::instance(), SIGNAL( requestSent( QNetworkReply *, QObject * ) ), - SLOT( requestSent( QNetworkReply *, QObject * ) ) ); - emit sendRequest( request ); + mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); + connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ), Qt::DirectConnection ); + connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ), Qt::DirectConnection ); QEventLoop loop; connect( this, SIGNAL( downloadFinished() ), &loop, SLOT( quit() ) ); @@ -1945,40 +1933,13 @@ bool QgsWmsCapabilitiesDownload::downloadCapabilities() return mError.isEmpty(); } -void QgsWmsCapabilitiesDownload::requestSent( QNetworkReply * reply, QObject *sender ) -{ - QgsDebugMsg( "Entered" ); - if ( sender != this ) // it is not our reply - { - return; - } - disconnect( QgsNetworkAccessManager::instance(), SIGNAL( requestSent( QNetworkReply *, QObject * ) ), - this, SLOT( requestSent( QNetworkReply *, QObject * ) ) ); - - if ( !reply ) - { - emit downloadFinished(); - return; - } - if ( mIsAborted ) - { - emit deleteReply( reply ); - emit downloadFinished(); - return; - } - // Note: the reply was created on QgsNetworkAccessManager's thread - mCapabilitiesReply = reply; - connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ), Qt::DirectConnection ); - connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ), Qt::DirectConnection ); -} - void QgsWmsCapabilitiesDownload::abort() { QgsDebugMsg( "Entered" ); mIsAborted = true; if ( mCapabilitiesReply ) { - emit deleteReply( mCapabilitiesReply ); + mCapabilitiesReply->deleteLater(); mCapabilitiesReply = nullptr; } } @@ -2029,11 +1990,9 @@ void QgsWmsCapabilitiesDownload::capabilitiesReplyFinished() mCapabilitiesReply = nullptr; QgsDebugMsg( QString( "redirected getcapabilities: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ) ); - //mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); - connect( QgsNetworkAccessManager::instance(), - SIGNAL( requestSent( QNetworkReply *, QObject * ) ), - SLOT( requestSent( QNetworkReply *, QObject * ) ) ); - emit sendRequest( request ); + mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); + connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ), Qt::DirectConnection ); + connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ), Qt::DirectConnection ); return; } } diff --git a/src/providers/wms/qgswmscapabilities.h b/src/providers/wms/qgswmscapabilities.h index 7d5b52c2268..c0273a95420 100644 --- a/src/providers/wms/qgswmscapabilities.h +++ b/src/providers/wms/qgswmscapabilities.h @@ -685,11 +685,6 @@ class QgsWmsCapabilities /** Class that handles download of capabilities. - * Methods of this class may only be called directly from the thread to which instance of the class has affinity. - * It is possible to connect to abort() slot from another thread however. - */ -/* The requirement to call methods only from the thread to which this class instance has affinity guarantees that - * abort() cannot be called in the middle of another method and makes it simple to check if the request was aborted. */ class QgsWmsCapabilitiesDownload : public QObject { @@ -710,8 +705,7 @@ class QgsWmsCapabilitiesDownload : public QObject QByteArray response() const { return mHttpCapabilitiesResponse; } - public slots: - /** Abort network request immediately */ + //! Abort network request immediately void abort(); signals: @@ -721,14 +715,7 @@ class QgsWmsCapabilitiesDownload : public QObject /** \brief emit a signal once the download is finished */ void downloadFinished(); - /** Send request via signal/slot to main another thread */ - void sendRequest( const QNetworkRequest & request ); - - /** Abort request through QgsNetworkAccessManager */ - void deleteReply( QNetworkReply * reply ); - protected slots: - void requestSent( QNetworkReply * reply, QObject *sender ); void capabilitiesReplyFinished(); void capabilitiesReplyProgress( qint64, qint64 ); @@ -752,9 +739,6 @@ class QgsWmsCapabilitiesDownload : public QObject bool mIsAborted; bool mForceRefresh; - - private: - void connectManager(); }; diff --git a/src/providers/wms/qgswmsprovider.cpp b/src/providers/wms/qgswmsprovider.cpp index dc3b3ba80ee..9df9a3f3e22 100644 --- a/src/providers/wms/qgswmsprovider.cpp +++ b/src/providers/wms/qgswmsprovider.cpp @@ -24,10 +24,6 @@ * * ***************************************************************************/ -#include - -#include - #include "qgslogger.h" #include "qgswmsprovider.h" #include "qgswmsconnection.h" @@ -50,27 +46,19 @@ #include #include #include -#include - -#include -#include - #include -#include #include #include #include -#include #include #include -#include #include -#include #include - #include #include #include +#include +#include #include @@ -555,10 +543,6 @@ QImage *QgsWmsProvider::draw( QgsRectangle const &viewExtent, int pixelWidth, in QgsWmsImageDownloadHandler handler( dataSourceUri(), url, mSettings.authorization(), mCachedImage ); handler.downloadBlocking(); - - //QTime t; - //t.start(); - } else { @@ -3191,14 +3175,11 @@ QgsWmsImageDownloadHandler::QgsWmsImageDownloadHandler( const QString& providerU : mProviderUri( providerUri ) , mCachedImage( image ) , mEventLoop( new QEventLoop ) - , mNAM( new QgsNetworkAccessManager ) { - mNAM->setupDefaultProxyAndCache(); - QNetworkRequest request( url ); auth.setAuthorization( request ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); - mCacheReply = mNAM->get( request ); + mCacheReply = QgsNetworkAccessManager::instance()->get( request ); connect( mCacheReply, SIGNAL( finished() ), this, SLOT( cacheReplyFinished() ) ); connect( mCacheReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( cacheReplyProgress( qint64, qint64 ) ) ); @@ -3208,7 +3189,6 @@ QgsWmsImageDownloadHandler::QgsWmsImageDownloadHandler( const QString& providerU QgsWmsImageDownloadHandler::~QgsWmsImageDownloadHandler() { - delete mNAM; delete mEventLoop; } @@ -3229,7 +3209,7 @@ void QgsWmsImageDownloadHandler::cacheReplyFinished() mCacheReply->deleteLater(); QgsDebugMsg( QString( "redirected getmap: %1" ).arg( redirect.toString() ) ); - mCacheReply = mNAM->get( QNetworkRequest( redirect.toUrl() ) ); + mCacheReply = QgsNetworkAccessManager::instance()->get( QNetworkRequest( redirect.toUrl() ) ); connect( mCacheReply, SIGNAL( finished() ), this, SLOT( cacheReplyFinished() ) ); return; } @@ -3333,12 +3313,9 @@ QgsWmsTiledImageDownloadHandler::QgsWmsTiledImageDownloadHandler( const QString& , mCachedImage( cachedImage ) , mCachedViewExtent( cachedViewExtent ) , mEventLoop( new QEventLoop ) - , mNAM( new QgsNetworkAccessManager ) , mTileReqNo( tileReqNo ) , mSmoothPixmapTransform( smoothPixmapTransform ) { - mNAM->setupDefaultProxyAndCache(); - Q_FOREACH ( const TileRequest& r, requests ) { QNetworkRequest request( r.url ); @@ -3350,7 +3327,7 @@ QgsWmsTiledImageDownloadHandler::QgsWmsTiledImageDownloadHandler( const QString& request.setAttribute( static_cast( TileRect ), r.rect ); request.setAttribute( static_cast( TileRetry ), 0 ); - QNetworkReply *reply = mNAM->get( request ); + QNetworkReply *reply = QgsNetworkAccessManager::instance()->get( request ); connect( reply, SIGNAL( finished() ), this, SLOT( tileReplyFinished() ) ); mReplies << reply; @@ -3359,7 +3336,6 @@ QgsWmsTiledImageDownloadHandler::QgsWmsTiledImageDownloadHandler( const QString& QgsWmsTiledImageDownloadHandler::~QgsWmsTiledImageDownloadHandler() { - delete mNAM; delete mEventLoop; } @@ -3393,9 +3369,9 @@ void QgsWmsTiledImageDownloadHandler::tileReplyFinished() } #endif - if ( mNAM->cache() ) + if ( QgsNetworkAccessManager::instance()->cache() ) { - QNetworkCacheMetaData cmd = mNAM->cache()->metaData( reply->request().url() ); + QNetworkCacheMetaData cmd = QgsNetworkAccessManager::instance()->cache()->metaData( reply->request().url() ); QNetworkCacheMetaData::RawHeaderList hl; Q_FOREACH ( const QNetworkCacheMetaData::RawHeader &h, cmd.rawHeaders() ) @@ -3412,7 +3388,7 @@ void QgsWmsTiledImageDownloadHandler::tileReplyFinished() cmd.setExpirationDate( QDateTime::currentDateTime().addSecs( s.value( "/qgis/defaultTileExpiry", "24" ).toInt() * 60 * 60 ) ); } - mNAM->cache()->updateMetaData( cmd ); + QgsNetworkAccessManager::instance()->cache()->updateMetaData( cmd ); } int tileReqNo = reply->request().attribute( static_cast( TileReqNo ) ).toInt(); @@ -3448,7 +3424,7 @@ void QgsWmsTiledImageDownloadHandler::tileReplyFinished() reply->deleteLater(); QgsDebugMsg( QString( "redirected gettile: %1" ).arg( redirect.toString() ) ); - reply = mNAM->get( request ); + reply = QgsNetworkAccessManager::instance()->get( request ); mReplies << reply; connect( reply, SIGNAL( finished() ), this, SLOT( tileReplyFinished() ) ); @@ -3624,7 +3600,7 @@ void QgsWmsTiledImageDownloadHandler::repeatTileRequest( QNetworkRequest const & QgsDebugMsg( QString( "repeat tileRequest %1 %2(retry %3) for url: %4" ).arg( tileReqNo ).arg( tileNo ).arg( retry ).arg( url ) ); request.setAttribute( static_cast( TileRetry ), retry ); - QNetworkReply *reply = mNAM->get( request ); + QNetworkReply *reply = QgsNetworkAccessManager::instance()->get( request ); mReplies << reply; connect( reply, SIGNAL( finished() ), this, SLOT( tileReplyFinished() ) ); } diff --git a/src/providers/wms/qgswmsprovider.h b/src/providers/wms/qgswmsprovider.h index d39215bce3c..7e2bed23d04 100644 --- a/src/providers/wms/qgswmsprovider.h +++ b/src/providers/wms/qgswmsprovider.h @@ -589,7 +589,6 @@ class QgsWmsImageDownloadHandler : public QObject QImage* mCachedImage; QEventLoop* mEventLoop; - QgsNetworkAccessManager* mNAM; }; @@ -635,7 +634,6 @@ class QgsWmsTiledImageDownloadHandler : public QObject QgsRectangle mCachedViewExtent; QEventLoop* mEventLoop; - QgsNetworkAccessManager* mNAM; int mTileReqNo; bool mSmoothPixmapTransform;