QGIS API Documentation  2.14.11-Essen
qgsfiledownloader.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfiledownloader.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 "qgsfiledownloader.h"
18 
19 #include <QNetworkAccessManager>
20 #include <QNetworkRequest>
21 #include <QNetworkReply>
22 #include <QMessageBox>
23 #ifndef QT_NO_OPENSSL
24 #include <QSslError>
25 #endif
26 
27 QgsFileDownloader::QgsFileDownloader( QUrl url, QString outputFileName, bool enableGuiNotifications )
28  : mUrl( url )
29  , mReply( nullptr )
30  , mProgressDialog( nullptr )
31  , mDownloadCanceled( false )
32  , mErrors()
33  , mGuiNotificationsEnabled( enableGuiNotifications )
34 {
35  mFile.setFileName( outputFileName );
36  startDownload();
37 }
38 
39 
40 QgsFileDownloader::~QgsFileDownloader()
41 {
42  if ( mReply )
43  {
44  mReply->abort();
45  mReply->deleteLater();
46  }
47  if ( mProgressDialog )
48  {
49  mProgressDialog->deleteLater();
50  }
51 }
52 
53 
54 void QgsFileDownloader::startDownload()
55 {
57 
58  QNetworkRequest request( mUrl );
59 
60  mReply = nam->get( request );
61 
62  connect( mReply, SIGNAL( readyRead() ), this, SLOT( onReadyRead() ) );
63  connect( mReply, SIGNAL( finished() ), this, SLOT( onFinished() ) );
64  connect( mReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( onDownloadProgress( qint64, qint64 ) ) );
65  connect( nam, SIGNAL( requestTimedOut( QNetworkReply* ) ), this, SLOT( onRequestTimedOut() ) );
66 #ifndef QT_NO_OPENSSL
67  connect( nam, SIGNAL( sslErrors( QNetworkReply*, QList<QSslError> ) ), this, SLOT( onSslErrors( QNetworkReply*, QList<QSslError> ) ) );
68 #endif
69  if ( mGuiNotificationsEnabled )
70  {
71  mProgressDialog = new QProgressDialog();
72  mProgressDialog->setWindowTitle( tr( "Download" ) );
73  mProgressDialog->setLabelText( tr( "Downloading %1." ).arg( mFile.fileName() ) );
74  mProgressDialog->show();
75  connect( mProgressDialog, SIGNAL( canceled() ), this, SLOT( onDownloadCanceled() ) );
76  }
77 }
78 
80 {
81  mDownloadCanceled = true;
82  emit downloadCanceled();
83  onFinished();
84 }
85 
86 void QgsFileDownloader::onRequestTimedOut()
87 {
88  error( tr( "Network request %1 timed out" ).arg( mUrl.toString() ) );
89 }
90 
91 #ifndef QT_NO_OPENSSL
92 void QgsFileDownloader::onSslErrors( QNetworkReply *reply, const QList<QSslError> &errors )
93 {
94  Q_UNUSED( reply );
95  QStringList errorMessages;
96  errorMessages << "SSL Errors: ";
97  for ( int end = errors.size(), i = 0; i != end; ++i )
98  {
99  errorMessages << errors[i].errorString();
100  }
101  error( errorMessages );
102 }
103 #endif
104 
105 
106 void QgsFileDownloader::error( QStringList errorMessages )
107 {
108  for ( int end = errorMessages.size(), i = 0; i != end; ++i )
109  {
110  mErrors.append( errorMessages[i] );
111  }
112  // Show error
113  if ( mGuiNotificationsEnabled )
114  {
115  QMessageBox::warning( nullptr, tr( "Download failed" ), mErrors.join( "<br>" ) );
116  }
117  emit downloadError( mErrors );
118 }
119 
120 void QgsFileDownloader::error( QString errorMessage )
121 {
122  error( QStringList() << errorMessage );
123 }
124 
125 void QgsFileDownloader::onReadyRead()
126 {
127  Q_ASSERT( mReply );
128  if ( ! mFile.isOpen() && ! mFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
129  {
130  error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) );
131  onFinished();
132  }
133  else
134  {
135  QByteArray data = mReply->readAll();
136  mFile.write( data );
137  }
138 }
139 
140 void QgsFileDownloader::onFinished()
141 {
142  // when canceled
143  if ( ! mErrors.isEmpty() || mDownloadCanceled )
144  {
145  mFile.close();
146  mFile.remove();
147  if ( mGuiNotificationsEnabled )
148  mProgressDialog->hide();
149  }
150  else
151  {
152  // download finished normally
153  if ( mGuiNotificationsEnabled )
154  mProgressDialog->hide();
155  mFile.flush();
156  mFile.close();
157 
158  // get redirection url
159  QVariant redirectionTarget = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
160  if ( mReply->error() )
161  {
162  mFile.remove();
163  error( tr( "Download failed: %1" ).arg( mReply->errorString() ) );
164  }
165  else if ( !redirectionTarget.isNull() )
166  {
167  QUrl newUrl = mUrl.resolved( redirectionTarget.toUrl() );
168  mUrl = newUrl;
169  mReply->deleteLater();
170  mFile.open( QIODevice::WriteOnly );
171  mFile.resize( 0 );
172  mFile.close();
173  startDownload();
174  return;
175  }
176  else
177  {
178  emit downloadCompleted();
179  }
180  }
181  emit downloadExited();
182  this->deleteLater();
183 }
184 
185 
186 void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
187 {
188  if ( mDownloadCanceled )
189  {
190  return;
191  }
192  if ( mGuiNotificationsEnabled )
193  {
194  mProgressDialog->setMaximum( bytesTotal );
195  mProgressDialog->setValue( bytesReceived );
196  }
197  emit downloadProgress( bytesReceived, bytesTotal );
198 }
199 
QUrl toUrl() const
bool flush()
bool resize(qint64 sz)
void setMaximum(int maximum)
bool remove()
QString errorString() const
void setLabelText(const QString &text)
QString fileName() const
void setFileName(const QString &name)
QString join(const QString &separator) const
QString toString(QFlags< QUrl::FormattingOption > options) const
QString tr(const char *sourceText, const char *disambiguation, int n)
int size() const
void setValue(int progress)
void append(const T &value)
bool isNull() const
bool isEmpty() const
QByteArray readAll()
bool isOpen() const
void deleteLater()
void hide()
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
virtual void abort()=0
virtual void close()
QgsFileDownloader(QUrl url, QString outputFileName, bool guiNotificationsEnabled=true)
QgsFileDownloader.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
Emitted when data ready to be processed.
void setWindowTitle(const QString &)
void downloadCanceled()
Emitted when the download was canceled by the user.
QUrl resolved(const QUrl &relative) const
QVariant attribute(QNetworkRequest::Attribute code) const
qint64 write(const char *data, qint64 maxSize)
NetworkError error() const
void onDownloadCanceled()
Called when a download is canceled by the user this slot aborts the download and deletes the object...
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
void show()
QNetworkReply * get(const QNetworkRequest &request)
void downloadCompleted()
Emitted when the download has completed successfully.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void downloadError(QStringList errorMessages)
Emitted when an error makes the download fail.
void downloadExited()
Emitted always when the downloader exits.