QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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
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#include "moc_qgsnetworkcontentfetcherregistry.cpp"
21
22#include "qgsapplication.h"
23#include <QUrl>
24#include <QFileInfo>
25#include <QDir>
26#include <QMimeType>
27#include <QMimeDatabase>
28
30{
31 QMap<QString, QgsFetchedContent *>::const_iterator it = mFileRegistry.constBegin();
32 for ( ; it != mFileRegistry.constEnd(); ++it )
33 {
34 delete it.value();
35 }
36 mFileRegistry.clear();
37}
38
39QgsFetchedContent *QgsNetworkContentFetcherRegistry::fetch( const QString &url, const Qgis::ActionStart fetchingMode, const QString &authConfig )
40{
41
42 if ( mFileRegistry.contains( url ) )
43 {
44 return mFileRegistry.value( url );
45 }
46
47 QgsFetchedContent *content = new QgsFetchedContent( url, nullptr, QgsFetchedContent::NotStarted, authConfig );
48
49 mFileRegistry.insert( url, content );
50
51 if ( fetchingMode == Qgis::ActionStart::Immediate )
52 content->download();
53
54
55 return content;
56}
57
58QFile *QgsNetworkContentFetcherRegistry::localFile( const QString &filePathOrUrl )
59{
60 QFile *file = nullptr;
61 const QString path = filePathOrUrl;
62
63 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
64 {
65 if ( mFileRegistry.contains( path ) )
66 {
67 const QgsFetchedContent *content = mFileRegistry.value( path );
68 if ( content && content->status() == QgsFetchedContent::Finished && content->file() )
69 {
70 file = content->file();
71 }
72 else
73 {
74 // if the file is not downloaded yet or has failed, return nullptr
75 }
76 }
77 else
78 {
79 // if registry doesn't contain the URL, return nullptr
80 }
81 }
82 else
83 {
84 file = new QFile( filePathOrUrl );
85 }
86 return file;
87}
88
89QString QgsNetworkContentFetcherRegistry::localPath( const QString &filePathOrUrl )
90{
91 QString path = filePathOrUrl;
92
93 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
94 {
95 if ( mFileRegistry.contains( path ) )
96 {
97 const QgsFetchedContent *content = mFileRegistry.value( path );
98 if ( content->status() == QgsFetchedContent::Finished && !content->filePath().isEmpty() )
99 {
100 path = content->filePath();
101 }
102 else
103 {
104 // if the file is not downloaded yet or has failed, return empty string
105 path = QString();
106 }
107 }
108 else
109 {
110 // if registry doesn't contain the URL, keep path unchanged
111 }
112 }
113 return path;
114}
115
116
117
118
119void QgsFetchedContent::download( bool redownload )
120{
121
122 if ( redownload && status() == QgsFetchedContent::Downloading )
123 {
124 {
125 if ( mFetchingTask )
126 disconnect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
127 }
128 cancel();
129 }
130 if ( redownload ||
133 {
134 mFetchingTask = new QgsNetworkContentFetcherTask( mUrl, mAuthConfig );
135 // use taskCompleted which is main thread rather than fetched signal in worker thread
136 connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
137 connect( mFetchingTask, &QgsNetworkContentFetcherTask::taskTerminated, this, &QgsFetchedContent::taskCompleted );
139 QgsApplication::taskManager()->addTask( mFetchingTask );
141 }
142
143}
144
146{
147 if ( mFetchingTask && mFetchingTask->canCancel() )
148 {
149 mFetchingTask->cancel();
151 }
152}
153
154
155void QgsFetchedContent::taskCompleted()
156{
157 if ( !mFetchingTask || !mFetchingTask->reply() )
158 {
159 // if no reply, it has been canceled
161 mError = QNetworkReply::OperationCanceledError;
162 mFilePath = QString();
163 }
164 else
165 {
166 QNetworkReply *reply = mFetchingTask->reply();
167 if ( reply->error() == QNetworkReply::NoError )
168 {
169
170 // keep or guess extension, it can be useful when guessing file content
171 // (when loading this file in a Qt WebView for instance)
172
173 // extension from file name
174 QString extension = QFileInfo( reply->request().url().fileName() ).completeSuffix();
175
176 // extension from contentType header if not found from file name
177 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
178 if ( extension.isEmpty() && !contentType.isEmpty() )
179 {
180 const QList<QMimeType> mimeTypes = QMimeDatabase().allMimeTypes();
181 auto it = std::find_if( mimeTypes.constBegin(), mimeTypes.constEnd(), [ = ]( QMimeType mimeType )
182 {
183 return mimeType.name() == contentType;
184 } );
185 if ( it != mimeTypes.constEnd() )
186 {
187 extension = ( *it ).preferredSuffix();
188 }
189 }
190
191 QTemporaryFile *tf = new QTemporaryFile( extension.isEmpty() ? QString( "XXXXXX" ) :
192 QString( "%1/XXXXXX.%2" ).arg( QDir::tempPath(), extension ) );
193 mFile = tf;
194 tf->open();
195 mFile->write( reply->readAll() );
196 // Qt docs notes that on some system if fileName is not called before close, file might get deleted
197 mFilePath = tf->fileName();
198 tf->close();
200 }
201 else
202 {
204 mError = reply->error();
205 mFilePath = QString();
206 }
207 }
208
209 emit fetched();
210}
ActionStart
Enum to determine when an operation would begin.
Definition qgis.h:1074
@ Immediate
Action will start immediately.
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.
QFile * file() const
Returns a pointer to the local file, or nullptr if the file is not accessible yet.
ContentStatus status() const
Returns the status of the download.
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.
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....