QGIS API Documentation 4.1.0-Master (60fea48833c)
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 <QString>
28#include <QUrl>
29
30#include "moc_qgsnetworkcontentfetcherregistry.cpp"
31
32using namespace Qt::StringLiterals;
33
35{
36 QMap<QString, QgsFetchedContent *>::const_iterator it = mFileRegistry.constBegin();
37 for ( ; it != mFileRegistry.constEnd(); ++it )
38 {
39 delete it.value();
40 }
41 mFileRegistry.clear();
42}
43
44QgsFetchedContent *QgsNetworkContentFetcherRegistry::fetch( const QString &url, const Qgis::ActionStart fetchingMode, const QString &authConfig, const QgsHttpHeaders &headers )
45{
46 if ( mFileRegistry.contains( url ) )
47 {
48 return mFileRegistry.value( url );
49 }
50
51 QgsFetchedContent *content = new QgsFetchedContent( url, nullptr, QgsFetchedContent::NotStarted, authConfig, headers );
52
53 mFileRegistry.insert( url, content );
54
55 if ( fetchingMode == Qgis::ActionStart::Immediate )
56 content->download();
57
58
59 return content;
60}
61
62QFile *QgsNetworkContentFetcherRegistry::localFile( const QString &filePathOrUrl )
63{
64 QFile *file = nullptr;
65 const QString path = filePathOrUrl;
66
67 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
68 {
69 if ( mFileRegistry.contains( path ) )
70 {
71 const QgsFetchedContent *content = mFileRegistry.value( path );
72 if ( content && content->status() == QgsFetchedContent::Finished && content->file() )
73 {
74 file = content->file();
75 }
76 else
77 {
78 // if the file is not downloaded yet or has failed, return nullptr
79 }
80 }
81 else
82 {
83 // if registry doesn't contain the URL, return nullptr
84 }
85 }
86 else
87 {
88 file = new QFile( filePathOrUrl );
89 }
90 return file;
91}
92
93QString QgsNetworkContentFetcherRegistry::localPath( const QString &filePathOrUrl )
94{
95 QString path = filePathOrUrl;
96
97 if ( !QUrl::fromUserInput( filePathOrUrl ).isLocalFile() )
98 {
99 auto it = mFileRegistry.constFind( path );
100 if ( it != mFileRegistry.constEnd() )
101 {
102 const QgsFetchedContent *content = it.value();
103 if ( content->status() == QgsFetchedContent::Finished && !content->filePath().isEmpty() )
104 {
105 path = content->filePath();
106 }
107 else
108 {
109 // if the file is not downloaded yet or has failed, return empty string
110 path = QString();
111 }
112 }
113 else
114 {
115 // if registry doesn't contain the URL, keep path unchanged
116 }
117 }
118 return path;
119}
120
121
122void QgsFetchedContent::download( bool redownload )
123{
124 if ( redownload && status() == QgsFetchedContent::Downloading )
125 {
126 {
127 if ( mFetchingTask )
128 disconnect( mFetchingTask, &QgsNetworkContentFetcherTask::taskCompleted, this, &QgsFetchedContent::taskCompleted );
129 }
130 cancel();
131 }
133 {
134 mFetchingTask = new QgsNetworkContentFetcherTask( mUrl, mAuthConfig, QgsTask::CanCancel, QString(), mHeaders );
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
145{
146 if ( mFetchingTask && mFetchingTask->canCancel() )
147 {
148 mFetchingTask->cancel();
150 }
151}
152
153
154void QgsFetchedContent::taskCompleted()
155{
156 if ( !mFetchingTask || !mFetchingTask->reply() )
157 {
158 // if no reply, it has been canceled
160 mError = QNetworkReply::OperationCanceledError;
161 mFilePath = QString();
162 }
163 else
164 {
165 QNetworkReply *reply = mFetchingTask->reply();
166 if ( reply->error() == QNetworkReply::NoError )
167 {
168 // keep or guess extension, it can be useful when guessing file content
169 // (when loading this file in a Qt WebView for instance)
170
171 // extension from file name
172 QString extension = QFileInfo( reply->request().url().fileName() ).completeSuffix();
173
174 // extension from contentType header if not found from file name
175 const QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString();
176 if ( extension.isEmpty() && !contentType.isEmpty() )
177 {
178 const QList<QMimeType> mimeTypes = QMimeDatabase().allMimeTypes();
179 auto it = std::find_if( mimeTypes.constBegin(), mimeTypes.constEnd(), [contentType]( QMimeType mimeType ) { return mimeType.name() == contentType; } );
180 if ( it != mimeTypes.constEnd() )
181 {
182 extension = ( *it ).preferredSuffix();
183 }
184 }
185
186 mFile = std::make_unique<QTemporaryFile>( extension.isEmpty() ? QString( "XXXXXX" ) : QString( "%1/XXXXXX.%2" ).arg( QDir::tempPath(), extension ) );
187 if ( !mFile->open() )
188 {
189 QgsDebugError( u"Can't open temporary file %1"_s.arg( mFile->fileName() ) );
191 return;
192 }
193 mFile->write( reply->readAll() );
194 // Qt docs notes that on some system if fileName is not called before close, file might get deleted
195 mFilePath = mFile->fileName();
196 mFile->close();
198 }
199 else
200 {
202 mError = reply->error();
203 mFilePath = QString();
204 }
205 }
206
207 emit fetched();
208}
ActionStart
Enum to determine when an operation would begin.
Definition qgis.h:1169
@ Immediate
Action will start immediately.
Definition qgis.h:1171
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.
Implements simple HTTP header management.
QString localPath(const QString &filePathOrUrl)
Returns the path to 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(), const QgsHttpHeaders &headers=QgsHttpHeaders())
Initialize a download for the given URL.
QFile * localFile(const QString &filePathOrUrl)
Returns a QFile from a local file or to a temporary file previously fetched by the registry.
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.
@ CanCancel
Task can be canceled.
void taskTerminated()
Will be emitted by task if it has terminated for any reason other then completion (e....
#define QgsDebugError(str)
Definition qgslogger.h:59