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