Skip to content

Commit 587072c

Browse files
committedOct 18, 2017
Split QgsFileDownloader into separate core/gui classes
So that the guts of this class can be used from non-gui code
1 parent a406739 commit 587072c

13 files changed

+311
-53
lines changed
 

‎python/core/core_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@
310310
%Include qgsfieldformatterregistry.sip
311311
%Include qgsfieldmodel.sip
312312
%Include qgsfieldproxymodel.sip
313+
%Include qgsfiledownloader.sip
313314
%Include qgsgeometryvalidator.sip
314315
%Include qgsgml.sip
315316
%Include qgsgmlschema.sip

‎python/core/qgsfiledownloader.sip

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgsfiledownloader.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
class QgsFileDownloader : QObject
13+
{
14+
%Docstring
15+
QgsFileDownloader is a utility class for downloading files.
16+
17+
To use this class, it is necessary to pass the URL and an output file name as
18+
arguments to the constructor, the download will start immediately.
19+
20+
The download is asynchronous.
21+
22+
The object will destroy itself when the request completes, errors or is canceled.
23+
An optional authentication configuration can be specified.
24+
25+
.. versionadded:: 2.18.1
26+
%End
27+
28+
%TypeHeaderCode
29+
#include "qgsfiledownloader.h"
30+
%End
31+
public:
32+
33+
QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString(), bool delayStart = false );
34+
%Docstring
35+
QgsFileDownloader
36+
\param url the download url
37+
\param outputFileName file name where the downloaded content will be stored
38+
\param authcfg optionally apply this authentication configuration
39+
\param delayStart if true, the download will not be commenced immediately and must
40+
be triggered by a later call to startDownload(). This can be useful if connections need
41+
to be made to the downloader and there's a chance the download will emit
42+
signals before these connections have been made.
43+
%End
44+
45+
signals:
46+
void downloadCompleted();
47+
%Docstring
48+
Emitted when the download has completed successfully
49+
%End
50+
void downloadExited();
51+
%Docstring
52+
Emitted always when the downloader exits
53+
%End
54+
void downloadCanceled();
55+
%Docstring
56+
Emitted when the download was canceled by the user
57+
%End
58+
void downloadError( QStringList errorMessages );
59+
%Docstring
60+
Emitted when an error makes the download fail
61+
%End
62+
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
63+
%Docstring
64+
Emitted when data are ready to be processed
65+
%End
66+
67+
public slots:
68+
69+
void onDownloadCanceled();
70+
%Docstring
71+
Called when a download is canceled by the user
72+
this slot aborts the download and deletes
73+
the object.
74+
Never call this slot directly: this is meant to
75+
be managed by the signal-slot system.
76+
%End
77+
78+
void startDownload();
79+
%Docstring
80+
Called to start the download
81+
%End
82+
83+
protected:
84+
~QgsFileDownloader();
85+
86+
};
87+
88+
/************************************************************************
89+
* This file has been generated automatically from *
90+
* *
91+
* src/core/qgsfiledownloader.h *
92+
* *
93+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
94+
************************************************************************/

‎python/gui/gui_auto.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
%Include qgsuserinputdockwidget.sip
1919
%Include qgsbrowserdockwidget.sip
2020
%Include qgsvertexmarker.sip
21-
%Include qgsfiledownloader.sip
2221
%Include qgsabstractdatasourcewidget.sip
2322
%Include qgssourceselectprovider.sip
2423
%Include qgssourceselectproviderregistry.sip
@@ -201,6 +200,7 @@
201200
%Include qgstreewidgetitem.sip
202201
%Include qgsunitselectionwidget.sip
203202
%Include qgsvariableeditorwidget.sip
203+
%Include qgsfiledownloaderdialog.sip
204204
%Include raster/qgsmultibandcolorrendererwidget.sip
205205
%Include raster/qgspalettedrendererwidget.sip
206206
%Include raster/qgsrasterbandcombobox.sip
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/gui/qgsfiledownloaderdialog.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
class QgsFileDownloaderDialog : QProgressDialog
13+
{
14+
%Docstring
15+
QgsFileDownloaderDialog is a QProgressDialog subclass which
16+
handles file downloads and user feedback.
17+
18+
Internally, it uses QgsFileDownloader to handle the download,
19+
while showing progress via a progress dialog and supporting
20+
cancelation.
21+
22+
.. versionadded:: 3.0
23+
%End
24+
25+
%TypeHeaderCode
26+
#include "qgsfiledownloaderdialog.h"
27+
%End
28+
public:
29+
30+
QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString() );
31+
%Docstring
32+
QgsFileDownloader
33+
\param url the download url
34+
\param outputFileName file name where the downloaded content will be stored
35+
\param authcfg optionally apply this authentication configuration
36+
%End
37+
38+
signals:
39+
void downloadCompleted();
40+
%Docstring
41+
Emitted when the download has completed successfully
42+
%End
43+
void downloadExited();
44+
%Docstring
45+
Emitted always when the downloader exits
46+
%End
47+
void downloadCanceled();
48+
%Docstring
49+
Emitted when the download was canceled by the user
50+
%End
51+
void downloadError( QStringList errorMessages );
52+
%Docstring
53+
Emitted when an error makes the download fail
54+
%End
55+
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
56+
%Docstring
57+
Emitted when data are ready to be processed
58+
%End
59+
60+
};
61+
62+
/************************************************************************
63+
* This file has been generated automatically from *
64+
* *
65+
* src/gui/qgsfiledownloaderdialog.h *
66+
* *
67+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
68+
************************************************************************/

‎src/app/qgsidentifyresultsdialog.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#include "qgswebframe.h"
4343
#include "qgsstringutils.h"
4444
#include "qgstreewidgetitem.h"
45-
#include "qgsfiledownloader.h"
45+
#include "qgsfiledownloaderdialog.h"
4646
#include "qgsfieldformatterregistry.h"
4747
#include "qgsfieldformatter.h"
4848
#include "qgssettings.h"
@@ -132,7 +132,7 @@ void QgsIdentifyResultsWebView::handleDownload( QUrl url )
132132
{
133133
settings.setValue( DOWNLOADER_LAST_DIR_KEY, QFileInfo( targetFile ).dir().absolutePath() );
134134
// Start the download
135-
new QgsFileDownloader( url, targetFile );
135+
new QgsFileDownloaderDialog( url, targetFile );
136136
}
137137
}
138138
}

‎src/core/CMakeLists.txt

100644100755
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ SET(QGIS_CORE_SRCS
182182
qgsfieldmodel.cpp
183183
qgsfieldproxymodel.cpp
184184
qgsfields.cpp
185+
qgsfiledownloader.cpp
185186
qgsfontutils.cpp
186187
qgsgeometrysimplifier.cpp
187188
qgsgeometryvalidator.cpp
@@ -588,6 +589,7 @@ SET(QGIS_CORE_MOC_HDRS
588589
qgsfieldformatterregistry.h
589590
qgsfieldmodel.h
590591
qgsfieldproxymodel.h
592+
qgsfiledownloader.h
591593
qgsgeometryvalidator.h
592594
qgsgml.h
593595
qgsgmlschema.h

‎src/gui/qgsfiledownloader.cpp renamed to ‎src/core/qgsfiledownloader.cpp

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,17 @@
2121
#include <QNetworkAccessManager>
2222
#include <QNetworkRequest>
2323
#include <QNetworkReply>
24-
#include <QMessageBox>
2524
#ifndef QT_NO_SSL
2625
#include <QSslError>
2726
#endif
2827

29-
QgsFileDownloader::QgsFileDownloader( const QUrl &url, const QString &outputFileName, bool enableGuiNotifications, const QString &authcfg )
28+
QgsFileDownloader::QgsFileDownloader(const QUrl &url, const QString &outputFileName, const QString &authcfg , bool delayStart)
3029
: mUrl( url )
3130
, mDownloadCanceled( false )
32-
, mGuiNotificationsEnabled( enableGuiNotifications )
3331
{
3432
mFile.setFileName( outputFileName );
3533
mAuthCfg = authcfg;
34+
if ( !delayStart )
3635
startDownload();
3736
}
3837

@@ -44,10 +43,6 @@ QgsFileDownloader::~QgsFileDownloader()
4443
mReply->abort();
4544
mReply->deleteLater();
4645
}
47-
if ( mProgressDialog )
48-
{
49-
mProgressDialog->deleteLater();
50-
}
5146
}
5247

5348

@@ -83,14 +78,6 @@ void QgsFileDownloader::startDownload()
8378
#ifndef QT_NO_SSL
8479
connect( nam, &QgsNetworkAccessManager::sslErrors, this, &QgsFileDownloader::onSslErrors, Qt::UniqueConnection );
8580
#endif
86-
if ( mGuiNotificationsEnabled )
87-
{
88-
mProgressDialog = new QProgressDialog();
89-
mProgressDialog->setWindowTitle( tr( "Download" ) );
90-
mProgressDialog->setLabelText( tr( "Downloading %1." ).arg( mFile.fileName() ) );
91-
mProgressDialog->show();
92-
connect( mProgressDialog, &QProgressDialog::canceled, this, &QgsFileDownloader::onDownloadCanceled );
93-
}
9481
}
9582

9683
void QgsFileDownloader::onDownloadCanceled()
@@ -126,11 +113,6 @@ void QgsFileDownloader::error( const QStringList &errorMessages )
126113
{
127114
mErrors << errorMessages[i];
128115
}
129-
// Show error
130-
if ( mGuiNotificationsEnabled )
131-
{
132-
QMessageBox::warning( nullptr, tr( "Download failed" ), mErrors.join( QStringLiteral( "<br>" ) ) );
133-
}
134116
emit downloadError( mErrors );
135117
}
136118

@@ -161,14 +143,10 @@ void QgsFileDownloader::onFinished()
161143
{
162144
mFile.close();
163145
mFile.remove();
164-
if ( mGuiNotificationsEnabled )
165-
mProgressDialog->hide();
166146
}
167147
else
168148
{
169149
// download finished normally
170-
if ( mGuiNotificationsEnabled )
171-
mProgressDialog->hide();
172150
mFile.flush();
173151
mFile.close();
174152

@@ -206,11 +184,6 @@ void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTo
206184
{
207185
return;
208186
}
209-
if ( mGuiNotificationsEnabled )
210-
{
211-
mProgressDialog->setMaximum( bytesTotal );
212-
mProgressDialog->setValue( bytesReceived );
213-
}
214187
emit downloadProgress( bytesReceived, bytesTotal );
215188
}
216189

‎src/gui/qgsfiledownloader.h renamed to ‎src/core/qgsfiledownloader.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,27 @@
1919
#include <QObject>
2020
#include <QFile>
2121
#include <QNetworkReply>
22-
#include <QProgressDialog>
23-
#include "qgis_gui.h"
22+
#include "qgis_core.h"
2423

2524
#ifndef QT_NO_SSL
2625
#include <QSslError>
2726
#endif
2827

2928
/**
30-
* \ingroup gui
29+
* \ingroup core
3130
* QgsFileDownloader is a utility class for downloading files.
3231
*
3332
* To use this class, it is necessary to pass the URL and an output file name as
3433
* arguments to the constructor, the download will start immediately.
35-
* The download is asynchronous and depending on the guiNotificationsEnabled
36-
* parameter accepted by the constructor (default = true) the class will
37-
* show a progress dialog and report all errors in a QMessageBox::warning dialog.
38-
* If the guiNotificationsEnabled parameter is set to false, the class can still
39-
* be used through the signals and slots mechanism.
34+
*
35+
* The download is asynchronous.
36+
*
4037
* The object will destroy itself when the request completes, errors or is canceled.
4138
* An optional authentication configuration can be specified.
4239
*
4340
* \since QGIS 2.18.1
4441
*/
45-
class GUI_EXPORT QgsFileDownloader : public QObject
42+
class CORE_EXPORT QgsFileDownloader : public QObject
4643
{
4744
Q_OBJECT
4845
public:
@@ -51,10 +48,13 @@ class GUI_EXPORT QgsFileDownloader : public QObject
5148
* QgsFileDownloader
5249
* \param url the download url
5350
* \param outputFileName file name where the downloaded content will be stored
54-
* \param guiNotificationsEnabled if false, the downloader will not display any progress bar or error message
5551
* \param authcfg optionally apply this authentication configuration
52+
* \param delayStart if true, the download will not be commenced immediately and must
53+
* be triggered by a later call to startDownload(). This can be useful if connections need
54+
* to be made to the downloader and there's a chance the download will emit
55+
* signals before these connections have been made.
5656
*/
57-
QgsFileDownloader( const QUrl &url, const QString &outputFileName, bool guiNotificationsEnabled = true, const QString &authcfg = QString() );
57+
QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString(), bool delayStart = false );
5858

5959
signals:
6060
//! Emitted when the download has completed successfully
@@ -79,6 +79,9 @@ class GUI_EXPORT QgsFileDownloader : public QObject
7979
*/
8080
void onDownloadCanceled();
8181

82+
//! Called to start the download
83+
void startDownload();
84+
8285
private slots:
8386
//! Called when the network reply data are ready
8487
void onReadyRead();
@@ -88,8 +91,7 @@ class GUI_EXPORT QgsFileDownloader : public QObject
8891
void onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal );
8992
//! Called when a network request times out
9093
void onRequestTimedOut();
91-
//! Called to start the download
92-
void startDownload();
94+
9395
#ifndef QT_NO_SSL
9496

9597
/**
@@ -114,10 +116,8 @@ class GUI_EXPORT QgsFileDownloader : public QObject
114116
QUrl mUrl;
115117
QNetworkReply *mReply = nullptr;
116118
QFile mFile;
117-
QProgressDialog *mProgressDialog = nullptr;
118119
bool mDownloadCanceled;
119120
QStringList mErrors;
120-
bool mGuiNotificationsEnabled;
121121
QString mAuthCfg;
122122
};
123123

‎src/gui/CMakeLists.txt

100644100755
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ SET(QGIS_GUI_SRCS
349349
qgsuserinputdockwidget.cpp
350350
qgsvariableeditorwidget.cpp
351351
qgsvertexmarker.cpp
352-
qgsfiledownloader.cpp
352+
qgsfiledownloaderdialog.cpp
353353
qgsdatasourcemanagerdialog.cpp
354354
qgsabstractdatasourcewidget.cpp
355355
qgssourceselectprovider.cpp
@@ -509,7 +509,7 @@ SET(QGIS_GUI_MOC_HDRS
509509
qgsunitselectionwidget.h
510510
qgsuserinputdockwidget.h
511511
qgsvariableeditorwidget.h
512-
qgsfiledownloader.h
512+
qgsfiledownloaderdialog.h
513513
qgsdatasourcemanagerdialog.h
514514
qgsabstractdatasourcewidget.h
515515

@@ -716,7 +716,6 @@ SET(QGIS_GUI_HDRS
716716
qgsbrowserdockwidget.h
717717
qgsbrowserdockwidget_p.h
718718
qgsvertexmarker.h
719-
qgsfiledownloader.h
720719
qgsdatasourcemanagerdialog.h
721720
qgsabstractdatasourcewidget.h
722721
qgssourceselectprovider.h

‎src/gui/qgsfiledownloaderdialog.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/***************************************************************************
2+
qgsfiledownloaderdialog.cpp
3+
--------------------------------------
4+
Date : November 2016
5+
Copyright : (C) 2016 by Alessandro Pasotti
6+
Email : apasotti at boundlessgeo dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsfiledownloaderdialog.h"
17+
#include "qgsfiledownloader.h"
18+
#include <QMessageBox>
19+
20+
QgsFileDownloaderDialog::QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg )
21+
: mDownloader( new QgsFileDownloader( url, outputFileName, authcfg, true ) )
22+
{
23+
setWindowTitle( tr( "Download" ) );
24+
setLabelText( tr( "Downloading %1." ).arg( outputFileName ) );
25+
show();
26+
27+
connect( this, &QProgressDialog::canceled, mDownloader, &QgsFileDownloader::onDownloadCanceled );
28+
connect( mDownloader, &QgsFileDownloader::downloadError, this, &QgsFileDownloaderDialog::onError );
29+
connect( mDownloader, &QgsFileDownloader::downloadProgress, this, &QgsFileDownloaderDialog::onDownloadProgress );
30+
connect( mDownloader, &QgsFileDownloader::downloadExited, this, &QgsFileDownloaderDialog::deleteLater );
31+
32+
connect( mDownloader, &QgsFileDownloader::downloadCompleted, this, &QgsFileDownloaderDialog::downloadCompleted );
33+
connect( mDownloader, &QgsFileDownloader::downloadCanceled, this, &QgsFileDownloaderDialog::downloadCanceled );
34+
connect( mDownloader, &QgsFileDownloader::downloadExited, this, &QgsFileDownloaderDialog::downloadExited );
35+
connect( mDownloader, &QgsFileDownloader::downloadError, this, &QgsFileDownloaderDialog::downloadError );
36+
connect( mDownloader, &QgsFileDownloader::downloadProgress, this, &QgsFileDownloaderDialog::downloadProgress );
37+
mDownloader->startDownload();
38+
}
39+
40+
void QgsFileDownloaderDialog::onError( const QStringList &errors )
41+
{
42+
QMessageBox::warning( nullptr, tr( "Download failed" ), errors.join( QStringLiteral( "<br>" ) ) );
43+
}
44+
45+
void QgsFileDownloaderDialog::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
46+
{
47+
setMaximum( bytesTotal );
48+
setValue( bytesReceived );
49+
}
50+

‎src/gui/qgsfiledownloaderdialog.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/***************************************************************************
2+
qgsfiledownloaderdialog.h
3+
--------------------------------------
4+
Date : November 2016
5+
Copyright : (C) 2016 by Alessandro Pasotti
6+
Email : apasotti at boundlessgeo dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSFILEDOWNLOADERDIALOG_H
17+
#define QGSFILEDOWNLOADERDIALOG_H
18+
19+
#include <QProgressDialog>
20+
#include "qgis_gui.h"
21+
22+
class QgsFileDownloader;
23+
24+
/**
25+
* \ingroup gui
26+
* QgsFileDownloaderDialog is a QProgressDialog subclass which
27+
* handles file downloads and user feedback.
28+
*
29+
* Internally, it uses QgsFileDownloader to handle the download,
30+
* while showing progress via a progress dialog and supporting
31+
* cancelation.
32+
*
33+
* \since QGIS 3.0
34+
*/
35+
class GUI_EXPORT QgsFileDownloaderDialog : public QProgressDialog
36+
{
37+
Q_OBJECT
38+
public:
39+
40+
/**
41+
* QgsFileDownloader
42+
* \param url the download url
43+
* \param outputFileName file name where the downloaded content will be stored
44+
* \param authcfg optionally apply this authentication configuration
45+
*/
46+
QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString() );
47+
48+
signals:
49+
//! Emitted when the download has completed successfully
50+
void downloadCompleted();
51+
//! Emitted always when the downloader exits
52+
void downloadExited();
53+
//! Emitted when the download was canceled by the user
54+
void downloadCanceled();
55+
//! Emitted when an error makes the download fail
56+
void downloadError( QStringList errorMessages );
57+
//! Emitted when data are ready to be processed
58+
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
59+
60+
private slots:
61+
62+
void onError( const QStringList &errors );
63+
void onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal );
64+
65+
private:
66+
67+
QgsFileDownloader *mDownloader = nullptr;
68+
69+
};
70+
71+
#endif // QGSFILEDOWNLOADERDIALOG_H

‎tests/src/gui/testqgsfiledownloader.cpp

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void TestQgsFileDownloader::makeCall( QUrl url, QString fileName, bool cancel )
9494
{
9595
QEventLoop loop;
9696

97-
mFileDownloader = new QgsFileDownloader( url, fileName, false );
97+
mFileDownloader = new QgsFileDownloader( url, fileName );
9898
connect( mFileDownloader, &QgsFileDownloader::downloadCompleted, this, &TestQgsFileDownloader::downloadCompleted );
9999
connect( mFileDownloader, &QgsFileDownloader::downloadCanceled, this, &TestQgsFileDownloader::downloadCanceled );
100100
connect( mFileDownloader, &QgsFileDownloader::downloadExited, this, &TestQgsFileDownloader::downloadExited );

‎tests/src/python/test_qgsfiledownloader.py

100644100755
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import tempfile
1616
from functools import partial
1717
from qgis.PyQt.QtCore import QEventLoop, QUrl
18-
from qgis.gui import (QgsFileDownloader,)
18+
from qgis.core import (QgsFileDownloader,)
1919
from qgis.testing import start_app, unittest
2020

2121
__author__ = 'Alessandro Pasotti'
@@ -43,7 +43,7 @@ def _make_download(self, url, destination, cancel=False):
4343

4444
loop = QEventLoop()
4545

46-
downloader = QgsFileDownloader(QUrl(url), destination, False)
46+
downloader = QgsFileDownloader(QUrl(url), destination)
4747
downloader.downloadCompleted.connect(partial(self._set_slot, 'completed'))
4848
downloader.downloadExited.connect(partial(self._set_slot, 'exited'))
4949
downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled'))

0 commit comments

Comments
 (0)
Please sign in to comment.