Skip to content

Commit 9d18220

Browse files
committed
[FEATURE][composer] Allow remote urls to be entered as picture path
for picture items, and automatically fetch them. Sponsored by the City of Uster, Switzerland.
1 parent f93e536 commit 9d18220

File tree

6 files changed

+170
-38
lines changed

6 files changed

+170
-38
lines changed

python/core/composer/qgscomposerpicture.sip

+24-2
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,38 @@ class QgsComposerPicture: QgsComposerItem
4444
* @param path full path to the source image
4545
* @see usePictureExpression
4646
* @see pictureFile
47+
* @deprecated use setPicturePath instead
4748
*/
48-
void setPictureFile( const QString& path );
49+
void setPictureFile( const QString& path ) /Deprecated/;
4950

5051
/**Returns the path of the source image file. Data defined picture source may override
5152
* this value.
5253
* @returns path to the source image
5354
* @see usePictureExpression
5455
* @see setPictureFile
56+
* @deprecated use picturePath instead
5557
*/
56-
QString pictureFile() const;
58+
QString pictureFile() const /Deprecated/;
59+
60+
/**Sets the source path of the image (may be svg or a raster format). Data defined
61+
* picture source may override this value. The path can either be a local path
62+
* or a remote (http) path.
63+
* @param path path for the source image
64+
* @see usePictureExpression
65+
* @see picturePath
66+
* @note added in QGIS 2.5
67+
*/
68+
void setPicturePath( const QString& path );
69+
70+
/**Returns the path of the source image. Data defined picture source may override
71+
* this value. The path can either be a local path or a remote (http) path.
72+
* @returns path for the source image
73+
* @see usePictureExpression
74+
* @see setPicturePath
75+
* @note added in QGIS 2.5
76+
*/
77+
QString picturePath() const;
78+
5779

5880
/**Sets this items bound in scene coordinates such that 1 item size units
5981
* corresponds to 1 scene size unit and resizes the svg symbol / image

src/app/composer/qgscomposerpicturewidget.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void QgsComposerPictureWidget::on_mPictureBrowseButton_clicked()
114114
if ( mPicture )
115115
{
116116
mPicture->beginCommand( tr( "Picture changed" ) );
117-
mPicture->setPictureFile( filePath );
117+
mPicture->setPicturePath( filePath );
118118
mPicture->update();
119119
mPicture->endCommand();
120120
}
@@ -130,7 +130,7 @@ void QgsComposerPictureWidget::on_mPictureLineEdit_editingFinished()
130130
QFileInfo fileInfo( filePath );
131131

132132
mPicture->beginCommand( tr( "Picture changed" ) );
133-
mPicture->setPictureFile( filePath );
133+
mPicture->setPicturePath( filePath );
134134
mPicture->update();
135135
mPicture->endCommand();
136136
}
@@ -156,7 +156,7 @@ void QgsComposerPictureWidget::on_mPreviewListWidget_currentItemChanged( QListWi
156156

157157
QString absoluteFilePath = current->data( Qt::UserRole ).toString();
158158
mPicture->beginCommand( tr( "Picture changed" ) );
159-
mPicture->setPictureFile( absoluteFilePath );
159+
mPicture->setPicturePath( absoluteFilePath );
160160
mPictureLineEdit->setText( absoluteFilePath );
161161
mPicture->update();
162162
mPicture->endCommand();
@@ -382,7 +382,7 @@ void QgsComposerPictureWidget::setGuiElementValues()
382382
mResizeModeComboBox->blockSignals( true );
383383
mAnchorPointComboBox->blockSignals( true );
384384

385-
mPictureLineEdit->setText( mPicture->pictureFile() );
385+
mPictureLineEdit->setText( mPicture->picturePath() );
386386
mPictureRotationSpinBox->setValue( mPicture->pictureRotation() );
387387

388388
refreshMapComboBox();

src/core/composer/qgscomposerpicture.cpp

+79-19
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@
2525
#include "qgsvectorlayer.h"
2626
#include "qgsmessagelog.h"
2727
#include "qgsdatadefined.h"
28+
#include "qgsnetworkcontentfetcher.h"
2829
#include <QDomDocument>
2930
#include <QDomElement>
3031
#include <QFileInfo>
3132
#include <QImageReader>
3233
#include <QPainter>
3334
#include <QSvgRenderer>
34-
35+
#include <QNetworkRequest>
36+
#include <QNetworkReply>
37+
#include <QEventLoop>
38+
#include <QCoreApplication>
3539

3640
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ) :
3741
QgsComposerItem( composition ),
@@ -268,20 +272,17 @@ QRect QgsComposerPicture::clippedImageRect( double &boundRectWidthMM, double &bo
268272
break;
269273
}
270274

271-
272275
return QRect( leftClip, topClip, boundRectWidthPixels, boundRectHeightPixels );
273-
274276
}
275277

276278
void QgsComposerPicture::setPictureFile( const QString& path )
277279
{
278-
mSourceFile.setFileName( path );
279-
refreshPicture();
280+
setPicturePath( path );
280281
}
281282

282283
void QgsComposerPicture::refreshPicture()
283284
{
284-
QString source = mSourceFile.fileName();
285+
QString source = mSourcePath;
285286

286287
//data defined source set?
287288
mHasExpressionError = false;
@@ -301,25 +302,55 @@ void QgsComposerPicture::refreshPicture()
301302
}
302303
}
303304

304-
QFile path;
305-
path.setFileName( source );
306-
loadPicture( path );
305+
loadPicture( source );
307306
}
308307

309-
void QgsComposerPicture::loadPicture( const QFile& file )
308+
void QgsComposerPicture::loadRemotePicture( const QString &url )
310309
{
311-
if ( !file.exists() )
310+
//remote location
311+
312+
QgsNetworkContentFetcher fetcher;
313+
//pause until HTML fetch
314+
mLoaded = false;
315+
fetcher.fetchContent( QUrl( url ) );
316+
connect( &fetcher, SIGNAL( finished() ), this, SLOT( remotePictureLoaded() ) );
317+
318+
while ( !mLoaded )
319+
{
320+
qApp->processEvents();
321+
}
322+
323+
QNetworkReply* reply = fetcher.reply();
324+
if ( reply )
325+
{
326+
QImageReader imageReader( reply );
327+
mImage = imageReader.read();
328+
mMode = RASTER;
329+
reply->deleteLater();
330+
}
331+
else
332+
{
333+
mMode = Unknown;
334+
}
335+
}
336+
337+
void QgsComposerPicture::loadLocalPicture( const QString &path )
338+
{
339+
QFile pic;
340+
pic.setFileName( path );
341+
342+
if ( !pic.exists() )
312343
{
313344
mMode = Unknown;
314345
}
315346
else
316347
{
317-
QFileInfo sourceFileInfo( file );
348+
QFileInfo sourceFileInfo( pic );
318349
QString sourceFileSuffix = sourceFileInfo.suffix();
319350
if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
320351
{
321352
//try to open svg
322-
mSVG.load( file.fileName() );
353+
mSVG.load( pic.fileName() );
323354
if ( mSVG.isValid() )
324355
{
325356
mMode = SVG;
@@ -335,7 +366,7 @@ void QgsComposerPicture::loadPicture( const QFile& file )
335366
else
336367
{
337368
//try to open raster with QImageReader
338-
QImageReader imageReader( file.fileName() );
369+
QImageReader imageReader( pic.fileName() );
339370
if ( imageReader.read( &mImage ) )
340371
{
341372
mMode = RASTER;
@@ -347,11 +378,30 @@ void QgsComposerPicture::loadPicture( const QFile& file )
347378
}
348379
}
349380

381+
}
382+
383+
void QgsComposerPicture::remotePictureLoaded()
384+
{
385+
mLoaded = true;
386+
}
387+
388+
void QgsComposerPicture::loadPicture( const QString &path )
389+
{
390+
if ( path.startsWith( "http" ) )
391+
{
392+
//remote location
393+
loadRemotePicture( path );
394+
}
395+
else
396+
{
397+
//local location
398+
loadLocalPicture( path );
399+
}
350400
if ( mMode != Unknown ) //make sure we start with a new QImage
351401
{
352402
recalculateSize();
353403
}
354-
else if ( mHasExpressionError || !( file.fileName().isEmpty() ) )
404+
else if ( mHasExpressionError || !( path.isEmpty() ) )
355405
{
356406
//trying to load an invalid file or bad expression, show cross picture
357407
mMode = SVG;
@@ -589,7 +639,18 @@ void QgsComposerPicture::setPictureExpression( QString expression )
589639

590640
QString QgsComposerPicture::pictureFile() const
591641
{
592-
return mSourceFile.fileName();
642+
return picturePath();
643+
}
644+
645+
void QgsComposerPicture::setPicturePath( const QString &path )
646+
{
647+
mSourcePath = path;
648+
refreshPicture();
649+
}
650+
651+
QString QgsComposerPicture::picturePath() const
652+
{
653+
return mSourcePath;
593654
}
594655

595656
bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
@@ -599,7 +660,7 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
599660
return false;
600661
}
601662
QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
602-
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
663+
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourcePath ) );
603664
composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
604665
composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
605666
composerPictureElem.setAttribute( "resizeMode", QString::number(( int )mResizeMode ) );
@@ -668,8 +729,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
668729
setDataDefinedProperty( QgsComposerObject::PictureSource, expressionActive, true, sourceExpression, QString() );
669730
}
670731

671-
QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
672-
mSourceFile.setFileName( fileName );
732+
mSourcePath = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
673733

674734
//picture rotation
675735
if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )

src/core/composer/qgscomposerpicture.h

+38-4
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,37 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
6767
* @param path full path to the source image
6868
* @see usePictureExpression
6969
* @see pictureFile
70+
* @deprecated use setPicturePath instead
7071
*/
71-
void setPictureFile( const QString& path );
72+
Q_DECL_DEPRECATED void setPictureFile( const QString& path );
7273

7374
/**Returns the path of the source image file. Data defined picture source may override
7475
* this value.
7576
* @returns path to the source image
7677
* @see usePictureExpression
7778
* @see setPictureFile
79+
* @deprecated use picturePath instead
7880
*/
79-
QString pictureFile() const;
81+
Q_DECL_DEPRECATED QString pictureFile() const;
82+
83+
/**Sets the source path of the image (may be svg or a raster format). Data defined
84+
* picture source may override this value. The path can either be a local path
85+
* or a remote (http) path.
86+
* @param path path for the source image
87+
* @see usePictureExpression
88+
* @see picturePath
89+
* @note added in QGIS 2.5
90+
*/
91+
void setPicturePath( const QString& path );
92+
93+
/**Returns the path of the source image. Data defined picture source may override
94+
* this value. The path can either be a local path or a remote (http) path.
95+
* @returns path for the source image
96+
* @see usePictureExpression
97+
* @see setPicturePath
98+
* @note added in QGIS 2.5
99+
*/
100+
QString picturePath() const;
80101

81102
/**Sets this items bound in scene coordinates such that 1 item size units
82103
* corresponds to 1 scene size unit and resizes the svg symbol / image
@@ -284,7 +305,7 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
284305

285306
QImage mImage;
286307
QSvgRenderer mSVG;
287-
QFile mSourceFile;
308+
QString mSourcePath;
288309
Mode mMode;
289310

290311
QSize mDefaultSvgSize;
@@ -302,9 +323,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
302323
QgsComposerItem::ItemPositionMode mPictureAnchor;
303324

304325
bool mHasExpressionError;
326+
bool mLoaded;
305327

306328
/**loads an image file into the picture item and redraws the item*/
307-
void loadPicture( const QFile &file );
329+
void loadPicture( const QString &path );
308330

309331
/**sets up the picture item and connects to relevant signals*/
310332
void init();
@@ -313,6 +335,18 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
313335
* anchor settings
314336
*/
315337
QRect clippedImageRect( double &boundRectWidthMM, double &boundRectHeightMM, QSize imageRectPixels );
338+
339+
/**Loads a remote picture for the item
340+
*/
341+
void loadRemotePicture( const QString &url );
342+
343+
/**Loads a local picture for the item
344+
*/
345+
void loadLocalPicture( const QString &path );
346+
347+
private slots:
348+
349+
void remotePictureLoaded();
316350
};
317351

318352
#endif

0 commit comments

Comments
 (0)