Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsalgorithmfiledownloader.cpp
3 : : ---------------------
4 : : begin : October 2017
5 : : copyright : (C) 2017 by Etienne Trimaille
6 : : email : etienne at kartoza dot com
7 : : ***************************************************************************/
8 : :
9 : : /***************************************************************************
10 : : * *
11 : : * This program is free software; you can redistribute it and/or modify *
12 : : * it under the terms of the GNU General Public License as published by *
13 : : * the Free Software Foundation; either version 2 of the License, or *
14 : : * (at your option) any later version. *
15 : : * *
16 : : ***************************************************************************/
17 : :
18 : : #include "qgsalgorithmfiledownloader.h"
19 : : #include "qgsfiledownloader.h"
20 : : #include "qgsfileutils.h"
21 : : #include <QEventLoop>
22 : : #include <QFileInfo>
23 : : #include <QTimer>
24 : : #include <QUrl>
25 : :
26 : : ///@cond PRIVATE
27 : :
28 : 0 : QString QgsFileDownloaderAlgorithm::name() const
29 : : {
30 : 0 : return QStringLiteral( "filedownloader" );
31 : : }
32 : :
33 : 0 : QString QgsFileDownloaderAlgorithm::displayName() const
34 : : {
35 : 0 : return tr( "Download file" );
36 : : }
37 : :
38 : 0 : QStringList QgsFileDownloaderAlgorithm::tags() const
39 : : {
40 : 0 : return tr( "file,downloader,internet,url,fetch,get,https" ).split( ',' );
41 : 0 : }
42 : :
43 : 0 : QString QgsFileDownloaderAlgorithm::group() const
44 : : {
45 : 0 : return tr( "File tools" );
46 : : }
47 : :
48 : 0 : QString QgsFileDownloaderAlgorithm::groupId() const
49 : : {
50 : 0 : return QStringLiteral( "filetools" );
51 : : }
52 : :
53 : 0 : QString QgsFileDownloaderAlgorithm::shortHelpString() const
54 : : {
55 : 0 : return tr( "This algorithm downloads a URL on the file system." );
56 : : }
57 : :
58 : 0 : QgsFileDownloaderAlgorithm *QgsFileDownloaderAlgorithm::createInstance() const
59 : : {
60 : 0 : return new QgsFileDownloaderAlgorithm();
61 : 0 : }
62 : :
63 : 0 : void QgsFileDownloaderAlgorithm::initAlgorithm( const QVariantMap & )
64 : : {
65 : 0 : addParameter( new QgsProcessingParameterString( QStringLiteral( "URL" ), tr( "URL" ), QVariant(), false, false ) );
66 : 0 : addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ),
67 : 0 : tr( "File destination" ), QObject::tr( "All files (*.*)" ), QVariant(), true ) );
68 : 0 : }
69 : :
70 : 0 : QVariantMap QgsFileDownloaderAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
71 : : {
72 : 0 : mFeedback = feedback;
73 : 0 : QString url = parameterAsString( parameters, QStringLiteral( "URL" ), context );
74 : 0 : if ( url.isEmpty() )
75 : 0 : throw QgsProcessingException( tr( "No URL specified" ) );
76 : 0 : QString outputFile = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT" ), context );
77 : :
78 : 0 : QEventLoop loop;
79 : 0 : QTimer timer;
80 : 0 : QUrl downloadedUrl;
81 : 0 : QgsFileDownloader *downloader = new QgsFileDownloader( QUrl( url ), outputFile, QString(), true );
82 : 0 : connect( mFeedback, &QgsFeedback::canceled, downloader, &QgsFileDownloader::cancelDownload );
83 : 0 : connect( downloader, &QgsFileDownloader::downloadError, this, &QgsFileDownloaderAlgorithm::reportErrors );
84 : 0 : connect( downloader, &QgsFileDownloader::downloadProgress, this, &QgsFileDownloaderAlgorithm::receiveProgressFromDownloader );
85 : 0 : connect( downloader, &QgsFileDownloader::downloadCompleted, this, [&downloadedUrl]( const QUrl url ) { downloadedUrl = url; } );
86 : 0 : connect( downloader, &QgsFileDownloader::downloadExited, &loop, &QEventLoop::quit );
87 : 0 : connect( &timer, &QTimer::timeout, this, &QgsFileDownloaderAlgorithm::sendProgressFeedback );
88 : 0 : downloader->startDownload();
89 : 0 : timer.start( 1000 );
90 : :
91 : 0 : loop.exec();
92 : :
93 : 0 : timer.stop();
94 : 0 : bool exists = QFileInfo::exists( outputFile );
95 : 0 : if ( !feedback->isCanceled() && !exists )
96 : 0 : throw QgsProcessingException( tr( "Output file doesn't exist." ) );
97 : :
98 : 0 : url = downloadedUrl.toDisplayString();
99 : 0 : feedback->pushInfo( QObject::tr( "Successfully downloaded %1" ).arg( url ) );
100 : :
101 : 0 : if ( outputFile.startsWith( QgsProcessingUtils::tempFolder() ) )
102 : : {
103 : : // the output is temporary and its file name automatically generated, try to add a file extension
104 : 0 : const int length = url.size();
105 : 0 : const int lastDotIndex = url.lastIndexOf( "." );
106 : 0 : const int lastSlashIndex = url.lastIndexOf( "/" );
107 : 0 : if ( lastDotIndex > -1 && lastDotIndex > lastSlashIndex && length - lastDotIndex <= 6 )
108 : : {
109 : 0 : QFile tmpFile( outputFile );
110 : 0 : tmpFile.rename( tmpFile.fileName() + url.mid( lastDotIndex ) );
111 : 0 : outputFile += url.mid( lastDotIndex );
112 : 0 : }
113 : 0 : }
114 : :
115 : 0 : QVariantMap outputs;
116 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), exists ? outputFile : QString() );
117 : 0 : return outputs;
118 : 0 : }
119 : :
120 : 0 : void QgsFileDownloaderAlgorithm::reportErrors( const QStringList &errors )
121 : : {
122 : 0 : throw QgsProcessingException( errors.join( '\n' ) );
123 : 0 : }
124 : :
125 : 0 : void QgsFileDownloaderAlgorithm::sendProgressFeedback()
126 : : {
127 : 0 : if ( !mReceived.isEmpty() && mLastReport != mReceived )
128 : : {
129 : 0 : mLastReport = mReceived;
130 : 0 : if ( mTotal.isEmpty() )
131 : 0 : mFeedback->pushInfo( tr( "%1 downloaded." ).arg( mReceived ) );
132 : : else
133 : 0 : mFeedback->pushInfo( tr( "%1 of %2 downloaded." ).arg( mReceived, mTotal ) );
134 : 0 : }
135 : 0 : }
136 : :
137 : 0 : void QgsFileDownloaderAlgorithm::receiveProgressFromDownloader( qint64 bytesReceived, qint64 bytesTotal )
138 : : {
139 : 0 : mReceived = QgsFileUtils::representFileSize( bytesReceived );
140 : 0 : if ( bytesTotal > 0 )
141 : : {
142 : 0 : if ( mTotal.isEmpty() )
143 : 0 : mTotal = QgsFileUtils::representFileSize( bytesTotal );
144 : :
145 : 0 : mFeedback->setProgress( ( bytesReceived * 100 ) / bytesTotal );
146 : 0 : }
147 : 0 : }
148 : :
149 : : ///@endcond
|