diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index 2ab201cdcbc..4f5a5f04d6c 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -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 diff --git a/python/core/qgsfiledownloader.sip b/python/core/qgsfiledownloader.sip new file mode 100644 index 00000000000..7c04b2a9843 --- /dev/null +++ b/python/core/qgsfiledownloader.sip @@ -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 * + ************************************************************************/ diff --git a/python/gui/gui_auto.sip b/python/gui/gui_auto.sip index b4a496963c2..114d63a3960 100644 --- a/python/gui/gui_auto.sip +++ b/python/gui/gui_auto.sip @@ -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 diff --git a/python/gui/qgsfiledownloaderdialog.sip b/python/gui/qgsfiledownloaderdialog.sip new file mode 100644 index 00000000000..140527d0c93 --- /dev/null +++ b/python/gui/qgsfiledownloaderdialog.sip @@ -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 * + ************************************************************************/ diff --git a/src/app/qgsidentifyresultsdialog.cpp b/src/app/qgsidentifyresultsdialog.cpp index df13d105f39..04d32699a11 100644 --- a/src/app/qgsidentifyresultsdialog.cpp +++ b/src/app/qgsidentifyresultsdialog.cpp @@ -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 ); } } } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt old mode 100644 new mode 100755 index 6dcce0d9ea6..2467f7eb662 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/gui/qgsfiledownloader.cpp b/src/core/qgsfiledownloader.cpp old mode 100644 new mode 100755 similarity index 82% rename from src/gui/qgsfiledownloader.cpp rename to src/core/qgsfiledownloader.cpp index 85b46c8fb51..dd465117f3f --- a/src/gui/qgsfiledownloader.cpp +++ b/src/core/qgsfiledownloader.cpp @@ -21,18 +21,17 @@ #include #include #include -#include #ifndef QT_NO_SSL #include #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( "
" ) ) ); - } 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 ); } diff --git a/src/gui/qgsfiledownloader.h b/src/core/qgsfiledownloader.h old mode 100644 new mode 100755 similarity index 82% rename from src/gui/qgsfiledownloader.h rename to src/core/qgsfiledownloader.h index 2c719bd63d3..428cd1eacb9 --- a/src/gui/qgsfiledownloader.h +++ b/src/core/qgsfiledownloader.h @@ -19,30 +19,27 @@ #include #include #include -#include -#include "qgis_gui.h" +#include "qgis_core.h" #ifndef QT_NO_SSL #include #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; }; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt old mode 100644 new mode 100755 index df3a6ffd177..d390a64051d --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -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 diff --git a/src/gui/qgsfiledownloaderdialog.cpp b/src/gui/qgsfiledownloaderdialog.cpp new file mode 100644 index 00000000000..ff05a17dfff --- /dev/null +++ b/src/gui/qgsfiledownloaderdialog.cpp @@ -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 + +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( "
" ) ) ); +} + +void QgsFileDownloaderDialog::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal ) +{ + setMaximum( bytesTotal ); + setValue( bytesReceived ); +} + diff --git a/src/gui/qgsfiledownloaderdialog.h b/src/gui/qgsfiledownloaderdialog.h new file mode 100644 index 00000000000..dc6c03e1e73 --- /dev/null +++ b/src/gui/qgsfiledownloaderdialog.h @@ -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 +#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 diff --git a/tests/src/gui/testqgsfiledownloader.cpp b/tests/src/gui/testqgsfiledownloader.cpp old mode 100644 new mode 100755 index 6783c79a829..b7aa1ec6771 --- a/tests/src/gui/testqgsfiledownloader.cpp +++ b/tests/src/gui/testqgsfiledownloader.cpp @@ -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 ); diff --git a/tests/src/python/test_qgsfiledownloader.py b/tests/src/python/test_qgsfiledownloader.py old mode 100644 new mode 100755 index c1e090317dc..f10ba0aea35 --- a/tests/src/python/test_qgsfiledownloader.py +++ b/tests/src/python/test_qgsfiledownloader.py @@ -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'))