QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsnetworkcontentfetcherregistry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsnetworkcontentfetcherregistry.cpp
3  -------------------
4  begin : April, 2018
5  copyright : (C) 2018 by Denis Rouzaud
6  email : [email protected]
7 
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
20 
21 #include "qgsapplication.h"
22 #include <QUrl>
23 #include <QFileInfo>
24 #include <QDir>
25 
27 {
28  QMap<QString, QgsFetchedContent *>::const_iterator it = mFileRegistry.constBegin();
29  for ( ; it != mFileRegistry.constEnd(); ++it )
30  {
31  delete it.value();
32  }
33  mFileRegistry.clear();
34 }
35 
36 QgsFetchedContent *QgsNetworkContentFetcherRegistry::fetch( const QString &url, const Qgis::ActionStart fetchingMode, const QString &authConfig )
37 {
38 
39  if ( mFileRegistry.contains( url ) )
40  {
41  return mFileRegistry.value( url );
42  }
43 
44  QgsFetchedContent *content = new QgsFetchedContent( url, nullptr, QgsFetchedContent::NotStarted, authConfig );
45 
46  mFileRegistry.insert( url, content );
47 
48  if ( fetchingMode == Qgis::ActionStart::Immediate )
49  content->download();
50 
51 
52  return content;
53 }
54 
55 QFile *QgsNetworkContentFetcherRegistry::localFile( const QString &filePathOrUrl )
56 {
57  QFile *file = nullptr;
58  const QString path = filePathOrUrl;
59 
60  if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
61  {
62  if ( mFileRegistry.contains( path ) )
63  {
64  const QgsFetchedContent *content = mFileRegistry.value( path );
65  if ( content && content->status() == QgsFetchedContent::Finished && content->file() )
66  {
67  file = content->file();
68  }
69  else
70  {
71  // if the file is not downloaded yet or has failed, return nullptr
72  }
73  }
74  else
75  {
76  // if registry doesn't contain the URL, return nullptr
77  }
78  }
79  else
80  {
81  file = new QFile( filePathOrUrl );
82  }
83  return file;
84 }
85 
86 QString QgsNetworkContentFetcherRegistry::localPath( const QString &filePathOrUrl )
87 {
88  QString path = filePathOrUrl;
89 
90  if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
91  {
92  if ( mFileRegistry.contains( path ) )
93  {
94  const QgsFetchedContent *content = mFileRegistry.value( path );
95  if ( content->status() == QgsFetchedContent::Finished && !content->filePath().isEmpty() )
96  {
97  path = content->filePath();
98  }
99  else
100  {
101  // if the file is not downloaded yet or has failed, return empty string
102  path = QString();
103  }
104  }
105  else
106  {
107  // if registry doesn't contain the URL, keep path unchanged
108  }
109  }
110  return path;
111 }
112 
113 
114 
115 
116 void QgsFetchedContent::download( bool redownload )
117 {
118 
119  if ( redownload && status() == QgsFetchedContent::Downloading )
120  {
121  {
122  if ( mFetchingTask )
123  disconnect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
124  }
125  cancel();
126  }
127  if ( redownload ||
130  {
131  mFetchingTask = new QgsNetworkContentFetcherTask( mUrl, mAuthConfig );
132  // use taskCompleted which is main thread rather than fetched signal in worker thread
133  connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
134  connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskTerminated, this, &QgsFetchedContent::taskCompleted );
136  QgsApplication::taskManager()->addTask( mFetchingTask );
138  }
139 
140 }
141 
143 {
144  if ( mFetchingTask && mFetchingTask->canCancel() )
145  {
146  mFetchingTask->cancel();
147  }
148  if ( mFile )
149  {
150  mFile->deleteLater();
151  mFilePath = QString();
152  }
153 }
154 
155 
156 void QgsFetchedContent::taskCompleted()
157 {
158  if ( !mFetchingTask || !mFetchingTask->reply() )
159  {
160  // if no reply, it has been canceled
161  mStatus = QgsFetchedContent::Failed;
162  mError = QNetworkReply::OperationCanceledError;
163  mFilePath = QString();
164  }
165  else
166  {
167  QNetworkReply *reply = mFetchingTask->reply();
168  if ( reply->error() == QNetworkReply::NoError )
169  {
170  // keep extension, it can be useful when guessing file content
171  // (when loading this file in a Qt WebView for instance)
172  const QString extension = QFileInfo( reply->request().url().fileName() ).completeSuffix();
173 
174  QTemporaryFile *tf = new QTemporaryFile( extension.isEmpty() ? QString( "XXXXXX" ) :
175  QString( "%1/XXXXXX.%2" ).arg( QDir::tempPath(), extension ) );
176  mFile = tf;
177  tf->open();
178  mFile->write( reply->readAll() );
179  // Qt docs notes that on some system if fileName is not called before close, file might get deleted
180  mFilePath = tf->fileName();
181  tf->close();
182  mStatus = QgsFetchedContent::Finished;
183  }
184  else
185  {
186  mStatus = QgsFetchedContent::Failed;
187  mError = reply->error();
188  mFilePath = QString();
189  }
190  }
191 
192  emit fetched();
193 }
ActionStart
Enum to determine when an operation would begin.
Definition: qgis.h:432
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
FetchedContent holds useful information about a network content being fetched.
ContentStatus status() const
Returns the status of the download.
QFile * file() const
Returns a pointer to the local file, or nullptr if the file is not accessible yet.
void download(bool redownload=false)
Start the download.
const QString filePath() const
Returns the path to the local file, an empty string if the file is not accessible yet.
void errorOccurred(QNetworkReply::NetworkError code, const QString &errorMsg)
Emitted when an error with code error occurred while processing the request errorMsg is a textual des...
@ Finished
Download finished and successful.
@ NotStarted
No download started for such URL.
@ Downloading
Currently downloading.
void fetched()
Emitted when the file is fetched and accessible.
void cancel()
Cancel the download operation.
QString localPath(const QString &filePathOrUrl)
Returns the path to a local file or to a temporary file previously fetched by the registry.
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
QgsFetchedContent * fetch(const QString &url, Qgis::ActionStart fetchingMode=Qgis::ActionStart::Deferred, const QString &authConfig=QString())
Initialize a download for the given URL.
Handles HTTP network content fetching in a background task.
QNetworkReply * reply()
Returns the network reply.
void cancel() override
Notifies the task that it should terminate.
void errorOccurred(QNetworkReply::NetworkError code, const QString &errorMsg)
Emitted when an error with code error occurred while processing the request errorMsg is a textual des...
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
bool canCancel() const
Returns true if the task can be canceled.