Split QgsFileDownloader into separate core/gui classes

So that the guts of this class can be used from non-gui code
This commit is contained in:
Nyall Dawson 2017-10-18 12:56:27 +10:00
parent a406739975
commit 587072cae9
13 changed files with 311 additions and 53 deletions

View File

@ -310,6 +310,7 @@
%Include qgsfieldformatterregistry.sip
%Include qgsfieldmodel.sip
%Include qgsfieldproxymodel.sip
%Include qgsfiledownloader.sip
%Include qgsgeometryvalidator.sip
%Include qgsgml.sip
%Include qgsgmlschema.sip

View File

@ -0,0 +1,94 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsfiledownloader.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsFileDownloader : QObject
{
%Docstring
QgsFileDownloader is a utility class for downloading files.
To use this class, it is necessary to pass the URL and an output file name as
arguments to the constructor, the download will start immediately.
The download is asynchronous.
The object will destroy itself when the request completes, errors or is canceled.
An optional authentication configuration can be specified.
.. versionadded:: 2.18.1
%End
%TypeHeaderCode
#include "qgsfiledownloader.h"
%End
public:
QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString(), bool delayStart = false );
%Docstring
QgsFileDownloader
\param url the download url
\param outputFileName file name where the downloaded content will be stored
\param authcfg optionally apply this authentication configuration
\param delayStart if true, the download will not be commenced immediately and must
be triggered by a later call to startDownload(). This can be useful if connections need
to be made to the downloader and there's a chance the download will emit
signals before these connections have been made.
%End
signals:
void downloadCompleted();
%Docstring
Emitted when the download has completed successfully
%End
void downloadExited();
%Docstring
Emitted always when the downloader exits
%End
void downloadCanceled();
%Docstring
Emitted when the download was canceled by the user
%End
void downloadError( QStringList errorMessages );
%Docstring
Emitted when an error makes the download fail
%End
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
%Docstring
Emitted when data are ready to be processed
%End
public slots:
void onDownloadCanceled();
%Docstring
Called when a download is canceled by the user
this slot aborts the download and deletes
the object.
Never call this slot directly: this is meant to
be managed by the signal-slot system.
%End
void startDownload();
%Docstring
Called to start the download
%End
protected:
~QgsFileDownloader();
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsfiledownloader.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -18,7 +18,6 @@
%Include qgsuserinputdockwidget.sip
%Include qgsbrowserdockwidget.sip
%Include qgsvertexmarker.sip
%Include qgsfiledownloader.sip
%Include qgsabstractdatasourcewidget.sip
%Include qgssourceselectprovider.sip
%Include qgssourceselectproviderregistry.sip
@ -201,6 +200,7 @@
%Include qgstreewidgetitem.sip
%Include qgsunitselectionwidget.sip
%Include qgsvariableeditorwidget.sip
%Include qgsfiledownloaderdialog.sip
%Include raster/qgsmultibandcolorrendererwidget.sip
%Include raster/qgspalettedrendererwidget.sip
%Include raster/qgsrasterbandcombobox.sip

View File

@ -0,0 +1,68 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsfiledownloaderdialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsFileDownloaderDialog : QProgressDialog
{
%Docstring
QgsFileDownloaderDialog is a QProgressDialog subclass which
handles file downloads and user feedback.
Internally, it uses QgsFileDownloader to handle the download,
while showing progress via a progress dialog and supporting
cancelation.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsfiledownloaderdialog.h"
%End
public:
QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString() );
%Docstring
QgsFileDownloader
\param url the download url
\param outputFileName file name where the downloaded content will be stored
\param authcfg optionally apply this authentication configuration
%End
signals:
void downloadCompleted();
%Docstring
Emitted when the download has completed successfully
%End
void downloadExited();
%Docstring
Emitted always when the downloader exits
%End
void downloadCanceled();
%Docstring
Emitted when the download was canceled by the user
%End
void downloadError( QStringList errorMessages );
%Docstring
Emitted when an error makes the download fail
%End
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
%Docstring
Emitted when data are ready to be processed
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsfiledownloaderdialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -42,7 +42,7 @@
#include "qgswebframe.h"
#include "qgsstringutils.h"
#include "qgstreewidgetitem.h"
#include "qgsfiledownloader.h"
#include "qgsfiledownloaderdialog.h"
#include "qgsfieldformatterregistry.h"
#include "qgsfieldformatter.h"
#include "qgssettings.h"
@ -132,7 +132,7 @@ void QgsIdentifyResultsWebView::handleDownload( QUrl url )
{
settings.setValue( DOWNLOADER_LAST_DIR_KEY, QFileInfo( targetFile ).dir().absolutePath() );
// Start the download
new QgsFileDownloader( url, targetFile );
new QgsFileDownloaderDialog( url, targetFile );
}
}
}

2
src/core/CMakeLists.txt Normal file → Executable file
View File

@ -182,6 +182,7 @@ SET(QGIS_CORE_SRCS
qgsfieldmodel.cpp
qgsfieldproxymodel.cpp
qgsfields.cpp
qgsfiledownloader.cpp
qgsfontutils.cpp
qgsgeometrysimplifier.cpp
qgsgeometryvalidator.cpp
@ -588,6 +589,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsfieldformatterregistry.h
qgsfieldmodel.h
qgsfieldproxymodel.h
qgsfiledownloader.h
qgsgeometryvalidator.h
qgsgml.h
qgsgmlschema.h

View File

@ -21,18 +21,17 @@
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMessageBox>
#ifndef QT_NO_SSL
#include <QSslError>
#endif
QgsFileDownloader::QgsFileDownloader( const QUrl &url, const QString &outputFileName, bool enableGuiNotifications, const QString &authcfg )
QgsFileDownloader::QgsFileDownloader(const QUrl &url, const QString &outputFileName, const QString &authcfg , bool delayStart)
: mUrl( url )
, mDownloadCanceled( false )
, mGuiNotificationsEnabled( enableGuiNotifications )
{
mFile.setFileName( outputFileName );
mAuthCfg = authcfg;
if ( !delayStart )
startDownload();
}
@ -44,10 +43,6 @@ QgsFileDownloader::~QgsFileDownloader()
mReply->abort();
mReply->deleteLater();
}
if ( mProgressDialog )
{
mProgressDialog->deleteLater();
}
}
@ -83,14 +78,6 @@ void QgsFileDownloader::startDownload()
#ifndef QT_NO_SSL
connect( nam, &QgsNetworkAccessManager::sslErrors, this, &QgsFileDownloader::onSslErrors, Qt::UniqueConnection );
#endif
if ( mGuiNotificationsEnabled )
{
mProgressDialog = new QProgressDialog();
mProgressDialog->setWindowTitle( tr( "Download" ) );
mProgressDialog->setLabelText( tr( "Downloading %1." ).arg( mFile.fileName() ) );
mProgressDialog->show();
connect( mProgressDialog, &QProgressDialog::canceled, this, &QgsFileDownloader::onDownloadCanceled );
}
}
void QgsFileDownloader::onDownloadCanceled()
@ -126,11 +113,6 @@ void QgsFileDownloader::error( const QStringList &errorMessages )
{
mErrors << errorMessages[i];
}
// Show error
if ( mGuiNotificationsEnabled )
{
QMessageBox::warning( nullptr, tr( "Download failed" ), mErrors.join( QStringLiteral( "<br>" ) ) );
}
emit downloadError( mErrors );
}
@ -161,14 +143,10 @@ void QgsFileDownloader::onFinished()
{
mFile.close();
mFile.remove();
if ( mGuiNotificationsEnabled )
mProgressDialog->hide();
}
else
{
// download finished normally
if ( mGuiNotificationsEnabled )
mProgressDialog->hide();
mFile.flush();
mFile.close();
@ -206,11 +184,6 @@ void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTo
{
return;
}
if ( mGuiNotificationsEnabled )
{
mProgressDialog->setMaximum( bytesTotal );
mProgressDialog->setValue( bytesReceived );
}
emit downloadProgress( bytesReceived, bytesTotal );
}

View File

@ -19,30 +19,27 @@
#include <QObject>
#include <QFile>
#include <QNetworkReply>
#include <QProgressDialog>
#include "qgis_gui.h"
#include "qgis_core.h"
#ifndef QT_NO_SSL
#include <QSslError>
#endif
/**
* \ingroup gui
* \ingroup core
* QgsFileDownloader is a utility class for downloading files.
*
* To use this class, it is necessary to pass the URL and an output file name as
* arguments to the constructor, the download will start immediately.
* The download is asynchronous and depending on the guiNotificationsEnabled
* parameter accepted by the constructor (default = true) the class will
* show a progress dialog and report all errors in a QMessageBox::warning dialog.
* If the guiNotificationsEnabled parameter is set to false, the class can still
* be used through the signals and slots mechanism.
*
* The download is asynchronous.
*
* The object will destroy itself when the request completes, errors or is canceled.
* An optional authentication configuration can be specified.
*
* \since QGIS 2.18.1
*/
class GUI_EXPORT QgsFileDownloader : public QObject
class CORE_EXPORT QgsFileDownloader : public QObject
{
Q_OBJECT
public:
@ -51,10 +48,13 @@ class GUI_EXPORT QgsFileDownloader : public QObject
* QgsFileDownloader
* \param url the download url
* \param outputFileName file name where the downloaded content will be stored
* \param guiNotificationsEnabled if false, the downloader will not display any progress bar or error message
* \param authcfg optionally apply this authentication configuration
* \param delayStart if true, the download will not be commenced immediately and must
* be triggered by a later call to startDownload(). This can be useful if connections need
* to be made to the downloader and there's a chance the download will emit
* signals before these connections have been made.
*/
QgsFileDownloader( const QUrl &url, const QString &outputFileName, bool guiNotificationsEnabled = true, const QString &authcfg = QString() );
QgsFileDownloader( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString(), bool delayStart = false );
signals:
//! Emitted when the download has completed successfully
@ -79,6 +79,9 @@ class GUI_EXPORT QgsFileDownloader : public QObject
*/
void onDownloadCanceled();
//! Called to start the download
void startDownload();
private slots:
//! Called when the network reply data are ready
void onReadyRead();
@ -88,8 +91,7 @@ class GUI_EXPORT QgsFileDownloader : public QObject
void onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal );
//! Called when a network request times out
void onRequestTimedOut();
//! Called to start the download
void startDownload();
#ifndef QT_NO_SSL
/**
@ -114,10 +116,8 @@ class GUI_EXPORT QgsFileDownloader : public QObject
QUrl mUrl;
QNetworkReply *mReply = nullptr;
QFile mFile;
QProgressDialog *mProgressDialog = nullptr;
bool mDownloadCanceled;
QStringList mErrors;
bool mGuiNotificationsEnabled;
QString mAuthCfg;
};

5
src/gui/CMakeLists.txt Normal file → Executable file
View File

@ -349,7 +349,7 @@ SET(QGIS_GUI_SRCS
qgsuserinputdockwidget.cpp
qgsvariableeditorwidget.cpp
qgsvertexmarker.cpp
qgsfiledownloader.cpp
qgsfiledownloaderdialog.cpp
qgsdatasourcemanagerdialog.cpp
qgsabstractdatasourcewidget.cpp
qgssourceselectprovider.cpp
@ -509,7 +509,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsunitselectionwidget.h
qgsuserinputdockwidget.h
qgsvariableeditorwidget.h
qgsfiledownloader.h
qgsfiledownloaderdialog.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
@ -716,7 +716,6 @@ SET(QGIS_GUI_HDRS
qgsbrowserdockwidget.h
qgsbrowserdockwidget_p.h
qgsvertexmarker.h
qgsfiledownloader.h
qgsdatasourcemanagerdialog.h
qgsabstractdatasourcewidget.h
qgssourceselectprovider.h

View File

@ -0,0 +1,50 @@
/***************************************************************************
qgsfiledownloaderdialog.cpp
--------------------------------------
Date : November 2016
Copyright : (C) 2016 by Alessandro Pasotti
Email : apasotti at boundlessgeo dot com
***************************************************************************
* *
* 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 "qgsfiledownloaderdialog.h"
#include "qgsfiledownloader.h"
#include <QMessageBox>
QgsFileDownloaderDialog::QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg )
: mDownloader( new QgsFileDownloader( url, outputFileName, authcfg, true ) )
{
setWindowTitle( tr( "Download" ) );
setLabelText( tr( "Downloading %1." ).arg( outputFileName ) );
show();
connect( this, &QProgressDialog::canceled, mDownloader, &QgsFileDownloader::onDownloadCanceled );
connect( mDownloader, &QgsFileDownloader::downloadError, this, &QgsFileDownloaderDialog::onError );
connect( mDownloader, &QgsFileDownloader::downloadProgress, this, &QgsFileDownloaderDialog::onDownloadProgress );
connect( mDownloader, &QgsFileDownloader::downloadExited, this, &QgsFileDownloaderDialog::deleteLater );
connect( mDownloader, &QgsFileDownloader::downloadCompleted, this, &QgsFileDownloaderDialog::downloadCompleted );
connect( mDownloader, &QgsFileDownloader::downloadCanceled, this, &QgsFileDownloaderDialog::downloadCanceled );
connect( mDownloader, &QgsFileDownloader::downloadExited, this, &QgsFileDownloaderDialog::downloadExited );
connect( mDownloader, &QgsFileDownloader::downloadError, this, &QgsFileDownloaderDialog::downloadError );
connect( mDownloader, &QgsFileDownloader::downloadProgress, this, &QgsFileDownloaderDialog::downloadProgress );
mDownloader->startDownload();
}
void QgsFileDownloaderDialog::onError( const QStringList &errors )
{
QMessageBox::warning( nullptr, tr( "Download failed" ), errors.join( QStringLiteral( "<br>" ) ) );
}
void QgsFileDownloaderDialog::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
{
setMaximum( bytesTotal );
setValue( bytesReceived );
}

View File

@ -0,0 +1,71 @@
/***************************************************************************
qgsfiledownloaderdialog.h
--------------------------------------
Date : November 2016
Copyright : (C) 2016 by Alessandro Pasotti
Email : apasotti at boundlessgeo dot com
***************************************************************************
* *
* 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 QGSFILEDOWNLOADERDIALOG_H
#define QGSFILEDOWNLOADERDIALOG_H
#include <QProgressDialog>
#include "qgis_gui.h"
class QgsFileDownloader;
/**
* \ingroup gui
* QgsFileDownloaderDialog is a QProgressDialog subclass which
* handles file downloads and user feedback.
*
* Internally, it uses QgsFileDownloader to handle the download,
* while showing progress via a progress dialog and supporting
* cancelation.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsFileDownloaderDialog : public QProgressDialog
{
Q_OBJECT
public:
/**
* QgsFileDownloader
* \param url the download url
* \param outputFileName file name where the downloaded content will be stored
* \param authcfg optionally apply this authentication configuration
*/
QgsFileDownloaderDialog( const QUrl &url, const QString &outputFileName, const QString &authcfg = QString() );
signals:
//! Emitted when the download has completed successfully
void downloadCompleted();
//! Emitted always when the downloader exits
void downloadExited();
//! Emitted when the download was canceled by the user
void downloadCanceled();
//! Emitted when an error makes the download fail
void downloadError( QStringList errorMessages );
//! Emitted when data are ready to be processed
void downloadProgress( qint64 bytesReceived, qint64 bytesTotal );
private slots:
void onError( const QStringList &errors );
void onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal );
private:
QgsFileDownloader *mDownloader = nullptr;
};
#endif // QGSFILEDOWNLOADERDIALOG_H

2
tests/src/gui/testqgsfiledownloader.cpp Normal file → Executable file
View File

@ -94,7 +94,7 @@ void TestQgsFileDownloader::makeCall( QUrl url, QString fileName, bool cancel )
{
QEventLoop loop;
mFileDownloader = new QgsFileDownloader( url, fileName, false );
mFileDownloader = new QgsFileDownloader( url, fileName );
connect( mFileDownloader, &QgsFileDownloader::downloadCompleted, this, &TestQgsFileDownloader::downloadCompleted );
connect( mFileDownloader, &QgsFileDownloader::downloadCanceled, this, &TestQgsFileDownloader::downloadCanceled );
connect( mFileDownloader, &QgsFileDownloader::downloadExited, this, &TestQgsFileDownloader::downloadExited );

4
tests/src/python/test_qgsfiledownloader.py Normal file → Executable file
View File

@ -15,7 +15,7 @@ import os
import tempfile
from functools import partial
from qgis.PyQt.QtCore import QEventLoop, QUrl
from qgis.gui import (QgsFileDownloader,)
from qgis.core import (QgsFileDownloader,)
from qgis.testing import start_app, unittest
__author__ = 'Alessandro Pasotti'
@ -43,7 +43,7 @@ class TestQgsFileDownloader(unittest.TestCase):
loop = QEventLoop()
downloader = QgsFileDownloader(QUrl(url), destination, False)
downloader = QgsFileDownloader(QUrl(url), destination)
downloader.downloadCompleted.connect(partial(self._set_slot, 'completed'))
downloader.downloadExited.connect(partial(self._set_slot, 'exited'))
downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled'))