QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 
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  if ( mReply )
118  mReply->abort();
119  emit downloadError( mErrors );
120 }
121 
122 void QgsFileDownloader::error( QString errorMessage )
123 {
124  error( QStringList() << errorMessage );
125 }
126 
127 void QgsFileDownloader::onReadyRead()
128 {
129  Q_ASSERT( mReply );
130  if ( ! mFile.isOpen() && ! mFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
131  {
132  error( tr( "Cannot open output file: %1" ).arg( mFile.fileName() ) );
133  onFinished();
134  }
135  else
136  {
137  QByteArray data = mReply->readAll();
138  mFile.write( data );
139  }
140 }
141 
142 void QgsFileDownloader::onFinished()
143 {
144  // when canceled
145  if ( ! mErrors.isEmpty() || mDownloadCanceled )
146  {
147  mFile.close();
148  mFile.remove();
149  if ( mGuiNotificationsEnabled )
150  mProgressDialog->hide();
151  }
152  else
153  {
154  // download finished normally
155  if ( mGuiNotificationsEnabled )
156  mProgressDialog->hide();
157  mFile.flush();
158  mFile.close();
159 
160  // get redirection url
161  QVariant redirectionTarget = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
162  if ( mReply->error() )
163  {
164  mFile.remove();
165  error( tr( "Download failed: %1" ).arg( mReply->errorString() ) );
166  }
167  else if ( !redirectionTarget.isNull() )
168  {
169  QUrl newUrl = mUrl.resolved( redirectionTarget.toUrl() );
170  mUrl = newUrl;
171  mReply->deleteLater();
172  mFile.open( QIODevice::WriteOnly );
173  mFile.resize( 0 );
174  mFile.close();
175  startDownload();
176  return;
177  }
178  else
179  {
180  emit downloadCompleted();
181  }
182  }
183  emit downloadExited();
184  this->deleteLater();
185 }
186 
187 
188 void QgsFileDownloader::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
189 {
190  if ( mDownloadCanceled )
191  {
192  return;
193  }
194  if ( mGuiNotificationsEnabled )
195  {
196  mProgressDialog->setMaximum( bytesTotal );
197  mProgressDialog->setValue( bytesReceived );
198  }
199  emit downloadProgress( bytesReceived, bytesTotal );
200 }
201 
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.
network access manager for QGIS