Skip to content

Commit e95bf6d

Browse files
committedSep 1, 2015
use signals/slots between QgsWmsCapabilitiesDownload and QgsNetworkAccessManager, fixes crash on start up in #13271
1 parent 4e60022 commit e95bf6d

File tree

4 files changed

+116
-20
lines changed

4 files changed

+116
-20
lines changed
 

‎src/core/qgsnetworkaccessmanager.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,20 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache()
341341
setCache( newcache );
342342
}
343343

344+
void QgsNetworkAccessManager::sendGet( const QNetworkRequest & request )
345+
{
346+
QgsDebugMsg( "Entered" );
347+
QNetworkReply * reply = get( request );
348+
emit requestSent( reply, QObject::sender() );
349+
}
350+
351+
void QgsNetworkAccessManager::deleteReply( QNetworkReply * reply )
352+
{
353+
QgsDebugMsg( "Entered" );
354+
if ( !reply )
355+
{
356+
return;
357+
}
358+
reply->abort();
359+
reply->deleteLater();
360+
}

‎src/core/qgsnetworkaccessmanager.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,29 @@ class CORE_EXPORT QgsNetworkAccessManager : public QNetworkAccessManager
8484

8585
bool useSystemProxy() { return mUseSystemProxy; }
8686

87+
public slots:
88+
/** Send GET request, calls get().
89+
* Emits requestSent().
90+
* @param request request to be sent
91+
*/
92+
void sendGet( const QNetworkRequest & request );
93+
/** Abort and delete reply. This slot may be used to abort reply created by instance of this class
94+
* (and which was not moved to another thread) from a different thread. Such reply cannot
95+
* be aborted directly from a different thread. The reply must be also deleted
96+
* in this slot, otherwise it could happen that abort signal comes after the reply was deleted.
97+
* @param reply reply to be aborted.
98+
*/
99+
void deleteReply( QNetworkReply * reply );
100+
87101
signals:
88102
void requestAboutToBeCreated( QNetworkAccessManager::Operation, const QNetworkRequest &, QIODevice * );
89103
void requestCreated( QNetworkReply * );
90104
void requestTimedOut( QNetworkReply * );
105+
/** Emited when request was sent by request()
106+
* @param reply request reply
107+
* @param sender the object which called request() slot.
108+
*/
109+
void requestSent( QNetworkReply * reply, QObject *sender );
91110

92111
private slots:
93112
void abortRequest();

‎src/providers/wms/qgswmscapabilities.cpp

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,7 @@ QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( QObject *parent )
18591859
, mCapabilitiesReply( 0 )
18601860
, mIsAborted( false )
18611861
{
1862+
connectManager();
18621863
}
18631864

18641865
QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( const QString& baseUrl, const QgsWmsAuthorization& auth, QObject *parent )
@@ -1868,6 +1869,22 @@ QgsWmsCapabilitiesDownload::QgsWmsCapabilitiesDownload( const QString& baseUrl,
18681869
, mCapabilitiesReply( 0 )
18691870
, mIsAborted( false )
18701871
{
1872+
connectManager();
1873+
}
1874+
1875+
void QgsWmsCapabilitiesDownload::connectManager()
1876+
{
1877+
// The instance of this class may live on a thread different from QgsNetworkAccessManager instance's thread,
1878+
// so we cannot call QgsNetworkAccessManager::get() directly and we must send a signal instead.
1879+
connect( this, SIGNAL( sendRequest( const QNetworkRequest & ) ),
1880+
QgsNetworkAccessManager::instance(), SLOT( sendGet( const QNetworkRequest & ) ) );
1881+
connect( this, SIGNAL( deleteReply( QNetworkReply * ) ),
1882+
QgsNetworkAccessManager::instance(), SLOT( deleteReply( QNetworkReply * ) ) );
1883+
}
1884+
1885+
QgsWmsCapabilitiesDownload::~QgsWmsCapabilitiesDownload()
1886+
{
1887+
abort();
18711888
}
18721889

18731890
bool QgsWmsCapabilitiesDownload::downloadCapabilities( const QString& baseUrl, const QgsWmsAuthorization& auth )
@@ -1880,7 +1897,9 @@ bool QgsWmsCapabilitiesDownload::downloadCapabilities( const QString& baseUrl, c
18801897
bool QgsWmsCapabilitiesDownload::downloadCapabilities()
18811898
{
18821899
QgsDebugMsg( "entering." );
1900+
abort(); // cancel previous
18831901
mIsAborted = false;
1902+
18841903
QString url = mBaseUrl;
18851904
QgsDebugMsg( "url = " + url );
18861905
if ( !url.contains( "SERVICE=WMTS" ) &&
@@ -1896,17 +1915,9 @@ bool QgsWmsCapabilitiesDownload::downloadCapabilities()
18961915
request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork );
18971916
request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
18981917

1899-
QgsDebugMsg( QString( "getcapabilities: %1" ).arg( url ) );
1900-
// This is causing Qt warning: "Cannot create children for a parent that is in a different thread."
1901-
// but it only means that the reply will have no parent
1902-
if ( mIsAborted )
1903-
{
1904-
return false;
1905-
}
1906-
mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request );
1907-
1908-
connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ), Qt::DirectConnection );
1909-
connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ), Qt::DirectConnection );
1918+
connect( QgsNetworkAccessManager::instance(), SIGNAL( requestSent( QNetworkReply *, QObject * ) ),
1919+
SLOT( requestSent( QNetworkReply *, QObject * ) ) );
1920+
emit sendRequest( request );
19101921

19111922
QEventLoop loop;
19121923
connect( this, SIGNAL( downloadFinished() ), &loop, SLOT( quit() ) );
@@ -1915,13 +1926,41 @@ bool QgsWmsCapabilitiesDownload::downloadCapabilities()
19151926
return mError.isEmpty();
19161927
}
19171928

1929+
void QgsWmsCapabilitiesDownload::requestSent( QNetworkReply * reply, QObject *sender )
1930+
{
1931+
QgsDebugMsg( "Entered" );
1932+
if ( sender != this ) // it is not our reply
1933+
{
1934+
return;
1935+
}
1936+
disconnect( QgsNetworkAccessManager::instance(), SIGNAL( requestSent( QNetworkReply *, QObject * ) ),
1937+
this, SLOT( requestSent( QNetworkReply *, QObject * ) ) );
1938+
1939+
if ( !reply )
1940+
{
1941+
emit downloadFinished();
1942+
return;
1943+
}
1944+
if ( mIsAborted )
1945+
{
1946+
emit deleteReply( reply );
1947+
emit downloadFinished();
1948+
return;
1949+
}
1950+
// Note: the reply was created on QgsNetworkAccessManager's thread
1951+
mCapabilitiesReply = reply;
1952+
connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ), Qt::DirectConnection );
1953+
connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ), Qt::DirectConnection );
1954+
}
1955+
19181956
void QgsWmsCapabilitiesDownload::abort()
19191957
{
19201958
QgsDebugMsg( "Entered" );
19211959
mIsAborted = true;
19221960
if ( mCapabilitiesReply )
19231961
{
1924-
mCapabilitiesReply->abort();
1962+
emit deleteReply( mCapabilitiesReply );
1963+
mCapabilitiesReply = 0;
19251964
}
19261965
}
19271966

@@ -1935,7 +1974,7 @@ void QgsWmsCapabilitiesDownload::capabilitiesReplyProgress( qint64 bytesReceived
19351974
void QgsWmsCapabilitiesDownload::capabilitiesReplyFinished()
19361975
{
19371976
QgsDebugMsg( "entering." );
1938-
if ( !mIsAborted )
1977+
if ( !mIsAborted && mCapabilitiesReply )
19391978
{
19401979
if ( mCapabilitiesReply->error() == QNetworkReply::NoError )
19411980
{
@@ -1962,10 +2001,8 @@ void QgsWmsCapabilitiesDownload::capabilitiesReplyFinished()
19622001

19632002
mCapabilitiesReply->deleteLater();
19642003
QgsDebugMsg( QString( "redirected getcapabilities: %1" ).arg( redirect.toString() ) );
1965-
mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request );
1966-
1967-
connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) );
1968-
connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) );
2004+
//mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request );
2005+
emit sendRequest( request );
19692006
return;
19702007
}
19712008
}
@@ -1987,8 +2024,11 @@ void QgsWmsCapabilitiesDownload::capabilitiesReplyFinished()
19872024
}
19882025
}
19892026

1990-
mCapabilitiesReply->deleteLater();
1991-
mCapabilitiesReply = 0;
2027+
if ( mCapabilitiesReply )
2028+
{
2029+
mCapabilitiesReply->deleteLater();
2030+
mCapabilitiesReply = 0;
2031+
}
19922032

19932033
emit downloadFinished();
19942034
}

‎src/providers/wms/qgswmscapabilities.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,13 @@ class QgsWmsCapabilities
677677

678678

679679

680-
/** Class that handles download of capabilities */
680+
/** Class that handles download of capabilities.
681+
* Methods of this class may only be called directly from the thread to which instance of the class has affinity.
682+
* It is possible to connect to abort() slot from another thread however.
683+
*/
684+
/* The requirement to call methods only from the thread to which this class instance has affinity guarantees that
685+
* abort() cannot be called in the middle of another method and makes it simple to check if the request was aborted.
686+
*/
681687
class QgsWmsCapabilitiesDownload : public QObject
682688
{
683689
Q_OBJECT
@@ -687,6 +693,8 @@ class QgsWmsCapabilitiesDownload : public QObject
687693

688694
QgsWmsCapabilitiesDownload( const QString& baseUrl, const QgsWmsAuthorization& auth, QObject* parent = 0 );
689695

696+
virtual ~QgsWmsCapabilitiesDownload();
697+
690698
bool downloadCapabilities();
691699

692700
bool downloadCapabilities( const QString& baseUrl, const QgsWmsAuthorization& auth );
@@ -695,16 +703,25 @@ class QgsWmsCapabilitiesDownload : public QObject
695703

696704
QByteArray response() const { return mHttpCapabilitiesResponse; }
697705

706+
public slots:
698707
/** Abort network request immediately */
699708
void abort();
709+
700710
signals:
701711
/** \brief emit a signal to be caught by qgisapp and display a msg on status bar */
702712
void statusChanged( QString const & theStatusQString );
703713

704714
/** \brief emit a signal once the download is finished */
705715
void downloadFinished();
706716

717+
/** Send request via signal/slot to main another thread */
718+
void sendRequest( const QNetworkRequest & request );
719+
720+
/** Abort request through QgsNetworkAccessManager */
721+
void deleteReply( QNetworkReply * reply );
722+
707723
protected slots:
724+
void requestSent( QNetworkReply * reply, QObject *sender );
708725
void capabilitiesReplyFinished();
709726
void capabilitiesReplyProgress( qint64, qint64 );
710727

@@ -727,6 +744,9 @@ class QgsWmsCapabilitiesDownload : public QObject
727744
QByteArray mHttpCapabilitiesResponse;
728745

729746
bool mIsAborted;
747+
748+
private:
749+
void connectManager();
730750
};
731751

732752

0 commit comments

Comments
 (0)
Failed to load comments.