Skip to content

Commit 4e96912

Browse files
committed
[bugfix][forwardport] File downloader for identify dialog hyperlinks
fixes #14703 Include C++ and Python tests Travis won: ported all test cases to Python and disabled C++ companion test (still useful locally and for debugging) For the curious: QTemporaryFile is not working as expected Moved to Qt5 new style signals Disabled C++ test and connected cancel to progress Make string comparison on SSL errors more robust
1 parent 73b283c commit 4e96912

12 files changed

+856
-1
lines changed

ci/travis/linux/script.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
2424
# Set OTB application path (installed in before_install.sh script)
2525
export OTB_APPLICATION_PATH=${HOME}/OTB-5.6.0-Linux64/lib/otb/applications
2626

27-
xvfb-run ctest -V -E "qgis_openstreetmaptest|qgis_wcsprovidertest|PyQgsWFSProviderGUI|qgis_ziplayertest|$(cat ${DIR}/blacklist.txt | paste -sd '|' -)" -S ./qgis-test-travis.ctest --output-on-failure
27+
xvfb-run ctest -V -E "qgis_filedownloader|qgis_openstreetmaptest|qgis_wcsprovidertest|PyQgsWFSProviderGUI|qgis_ziplayertest|$(cat ${DIR}/blacklist.txt | paste -sd '|' -)" -S ./qgis-test-travis.ctest --output-on-failure
2828
# xvfb-run ctest -V -E "qgis_openstreetmaptest|qgis_wcsprovidertest" -S ./qgis-test-travis.ctest --output-on-failure

python/gui/gui.sip

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
%Include qgsfieldvalidator.sip
7878
%Include qgsfiledropedit.sip
7979
%Include qgsfilewidget.sip
80+
%Include qgsfiledownloader.sip
8081
%Include qgsfilterlineedit.sip
8182
%Include qgsfocuswatcher.sip
8283
%Include qgsformannotationitem.sip

python/gui/qgsfiledownloader.sip

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/***************************************************************************
2+
qgsfiledownloader.sip
3+
--------------------------------------
4+
Date : November 2016
5+
Copyright : (C) 2016 by Alessandro Pasotti
6+
Email : elpaso at itopen dot it
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
/** \ingroup gui
17+
* QgsFileDownloader is a utility class for downloading files.
18+
*
19+
* To use this class, it is necessary to pass the URL and an output file name as
20+
* arguments to the constructor, the download will start immediately.
21+
* The download is asynchronous and depending on the guiNotificationsEnabled
22+
* parameter accepted by the constructor (default = true) the class will
23+
* show a progress dialog and report all errors in a QMessageBox::warning dialog.
24+
* If the guiNotificationsEnabled parameter is set to false, the class can still
25+
* be used through the signals and slots mechanism.
26+
* The object will destroy itself when the request completes, errors or is canceled.
27+
*
28+
* @note added in QGIS 2.18.1
29+
*/
30+
class QgsFileDownloader : public QObject
31+
{
32+
%TypeHeaderCode
33+
#include <qgsfiledownloader.h>
34+
%End
35+
public:
36+
/**
37+
* QgsFileDownloader
38+
* @param url the download url
39+
* @param outputFileName file name where the downloaded content will be stored
40+
* @param guiNotificationsEnabled if false, the downloader will not display any progress bar or error message
41+
*/
42+
QgsFileDownloader(QUrl url, QString outputFileName, bool guiNotificationsEnabled = true);
43+
44+
signals:
45+
/** Emitted when the download has completed successfully */
46+
void downloadCompleted();
47+
/** Emitted always when the downloader exits */
48+
void downloadExited();
49+
/** Emitted when the download was canceled by the user */
50+
void downloadCanceled();
51+
/** Emitted when an error makes the download fail */
52+
void downloadError( QStringList errorMessages );
53+
/** Emitted when data ready to be processed */
54+
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
55+
56+
public slots:
57+
/**
58+
* Called when a download is canceled by the user
59+
* this slot aborts the download and deletes the object
60+
* Never call this slot directly: this is meant to
61+
* be managed by the signal-slot system.
62+
*/
63+
void onDownloadCanceled();
64+
65+
private:
66+
~QgsFileDownloader();
67+
68+
};

src/app/qgsidentifyresultsdialog.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "qgswebframe.h"
4343
#include "qgsstringutils.h"
4444
#include "qgstreewidgetitem.h"
45+
#include "qgsfiledownloader.h"
4546

4647
#include <QCloseEvent>
4748
#include <QLabel>
@@ -59,6 +60,11 @@
5960
#include <QMessageBox>
6061
#include <QComboBox>
6162
#include <QTextDocument>
63+
#include <QNetworkRequest>
64+
#include <QNetworkReply>
65+
#include <QFileDialog>
66+
#include <QFileInfo>
67+
#include <QRegExp>
6268

6369
//graph
6470
#include <qwt_plot.h>
@@ -72,13 +78,59 @@ QgsIdentifyResultsWebView::QgsIdentifyResultsWebView( QWidget *parent ) : QgsWeb
7278
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
7379
page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
7480
// page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
81+
page()->setForwardUnsupportedContent( true );
7582
page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
7683
settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true );
7784
settings()->setAttribute( QWebSettings::JavascriptCanOpenWindows, true );
7885
settings()->setAttribute( QWebSettings::PluginsEnabled, true );
7986
#ifdef QGISDEBUG
8087
settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
8188
#endif
89+
connect( page(), SIGNAL( downloadRequested( QNetworkRequest ) ), this, SLOT( downloadRequested( QNetworkRequest ) ) );
90+
connect( page(), SIGNAL( unsupportedContent( QNetworkReply* ) ), this, SLOT( unsupportedContent( QNetworkReply* ) ) );
91+
}
92+
93+
94+
void QgsIdentifyResultsWebView::downloadRequested( const QNetworkRequest &request )
95+
{
96+
handleDownload( request.url() );
97+
}
98+
99+
void QgsIdentifyResultsWebView::unsupportedContent( QNetworkReply * reply )
100+
{
101+
handleDownload( reply->url() );
102+
}
103+
104+
void QgsIdentifyResultsWebView::handleDownload( QUrl url )
105+
{
106+
if ( ! url.isValid() )
107+
{
108+
QMessageBox::warning( this, tr( "Invalid URL" ), tr( "The download URL is not valid: %1" ).arg( url.toString( ) ) );
109+
}
110+
else
111+
{
112+
const QString DOWNLOADER_LAST_DIR_KEY( "Qgis/fileDownloaderLastDir" );
113+
QSettings settings;
114+
// Try to get some information from the URL
115+
QFileInfo info( url.toString( ) );
116+
QString savePath = settings.value( DOWNLOADER_LAST_DIR_KEY ).toString( );
117+
QString fileName = info.fileName().replace( QRegExp( "[^A-z0-9\\-_\\.]" ), "_" );
118+
if ( ! savePath.isEmpty() && ! fileName.isEmpty( ) )
119+
{
120+
savePath = QDir::cleanPath( savePath + QDir::separator() + fileName );
121+
}
122+
QString targetFile = QFileDialog::getSaveFileName( this,
123+
tr( "Save as" ),
124+
savePath,
125+
info.suffix( ).isEmpty() ? QString( ) : "*." + info.suffix( )
126+
);
127+
if ( ! targetFile.isEmpty() )
128+
{
129+
settings.setValue( DOWNLOADER_LAST_DIR_KEY, QFileInfo( targetFile ).dir().absolutePath( ) );
130+
// Start the download
131+
new QgsFileDownloader( url, targetFile );
132+
}
133+
}
82134
}
83135

84136
void QgsIdentifyResultsWebView::print()

src/app/qgsidentifyresultsdialog.h

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
#include <QWidget>
3030
#include <QList>
31+
#include <QNetworkRequest>
32+
#include <QNetworkReply>
33+
#include <QUrl>
3134

3235
class QCloseEvent;
3336
class QTreeWidgetItem;
@@ -57,9 +60,13 @@ class APP_EXPORT QgsIdentifyResultsWebView : public QgsWebView
5760
QSize sizeHint() const override;
5861
public slots:
5962
void print();
63+
void downloadRequested( const QNetworkRequest &request );
64+
void unsupportedContent( QNetworkReply *reply );
6065
protected:
6166
void contextMenuEvent( QContextMenuEvent* ) override;
6267
QgsWebView *createWindow( QWebPage::WebWindowType type ) override;
68+
private:
69+
void handleDownload( QUrl url );
6370
};
6471

6572
class APP_EXPORT QgsIdentifyResultsFeatureItem: public QTreeWidgetItem

src/gui/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ SET(QGIS_GUI_SRCS
317317
qgsuserinputdockwidget.cpp
318318
qgsvariableeditorwidget.cpp
319319
qgsvertexmarker.cpp
320+
qgsfiledownloader.cpp
320321
)
321322

322323
IF (WITH_QTWEBKIT)
@@ -471,6 +472,7 @@ SET(QGIS_GUI_MOC_HDRS
471472
qgsunitselectionwidget.h
472473
qgsuserinputdockwidget.h
473474
qgsvariableeditorwidget.h
475+
qgsfiledownloader.h
474476

475477
raster/qgsmultibandcolorrendererwidget.h
476478
raster/qgspalettedrendererwidget.h
@@ -664,6 +666,7 @@ SET(QGIS_GUI_HDRS
664666
qgsuserinputdockwidget.h
665667
qgsvectorlayertools.h
666668
qgsvertexmarker.h
669+
qgsfiledownloader.h
667670

668671
attributetable/qgsfeaturemodel.h
669672

0 commit comments

Comments
 (0)