Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
nyalldawson committed Aug 19, 2014
1 parent f93e536 commit 9d18220
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 38 deletions.
26 changes: 24 additions & 2 deletions python/core/composer/qgscomposerpicture.sip
Expand Up @@ -44,16 +44,38 @@ class QgsComposerPicture: QgsComposerItem
* @param path full path to the source image
* @see usePictureExpression
* @see pictureFile
* @deprecated use setPicturePath instead
*/
void setPictureFile( const QString& path );
void setPictureFile( const QString& path ) /Deprecated/;

/**Returns the path of the source image file. Data defined picture source may override
* this value.
* @returns path to the source image
* @see usePictureExpression
* @see setPictureFile
* @deprecated use picturePath instead
*/
QString pictureFile() const;
QString pictureFile() const /Deprecated/;

/**Sets the source path of the image (may be svg or a raster format). Data defined
* picture source may override this value. The path can either be a local path
* or a remote (http) path.
* @param path path for the source image
* @see usePictureExpression
* @see picturePath
* @note added in QGIS 2.5
*/
void setPicturePath( const QString& path );

/**Returns the path of the source image. Data defined picture source may override
* this value. The path can either be a local path or a remote (http) path.
* @returns path for the source image
* @see usePictureExpression
* @see setPicturePath
* @note added in QGIS 2.5
*/
QString picturePath() const;


/**Sets this items bound in scene coordinates such that 1 item size units
* corresponds to 1 scene size unit and resizes the svg symbol / image
Expand Down
8 changes: 4 additions & 4 deletions src/app/composer/qgscomposerpicturewidget.cpp
Expand Up @@ -114,7 +114,7 @@ void QgsComposerPictureWidget::on_mPictureBrowseButton_clicked()
if ( mPicture )
{
mPicture->beginCommand( tr( "Picture changed" ) );
mPicture->setPictureFile( filePath );
mPicture->setPicturePath( filePath );
mPicture->update();
mPicture->endCommand();
}
Expand All @@ -130,7 +130,7 @@ void QgsComposerPictureWidget::on_mPictureLineEdit_editingFinished()
QFileInfo fileInfo( filePath );

mPicture->beginCommand( tr( "Picture changed" ) );
mPicture->setPictureFile( filePath );
mPicture->setPicturePath( filePath );
mPicture->update();
mPicture->endCommand();
}
Expand All @@ -156,7 +156,7 @@ void QgsComposerPictureWidget::on_mPreviewListWidget_currentItemChanged( QListWi

QString absoluteFilePath = current->data( Qt::UserRole ).toString();
mPicture->beginCommand( tr( "Picture changed" ) );
mPicture->setPictureFile( absoluteFilePath );
mPicture->setPicturePath( absoluteFilePath );
mPictureLineEdit->setText( absoluteFilePath );
mPicture->update();
mPicture->endCommand();
Expand Down Expand Up @@ -382,7 +382,7 @@ void QgsComposerPictureWidget::setGuiElementValues()
mResizeModeComboBox->blockSignals( true );
mAnchorPointComboBox->blockSignals( true );

mPictureLineEdit->setText( mPicture->pictureFile() );
mPictureLineEdit->setText( mPicture->picturePath() );
mPictureRotationSpinBox->setValue( mPicture->pictureRotation() );

refreshMapComboBox();
Expand Down
98 changes: 79 additions & 19 deletions src/core/composer/qgscomposerpicture.cpp
Expand Up @@ -25,13 +25,17 @@
#include "qgsvectorlayer.h"
#include "qgsmessagelog.h"
#include "qgsdatadefined.h"
#include "qgsnetworkcontentfetcher.h"
#include <QDomDocument>
#include <QDomElement>
#include <QFileInfo>
#include <QImageReader>
#include <QPainter>
#include <QSvgRenderer>

#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QCoreApplication>

QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ) :
QgsComposerItem( composition ),
Expand Down Expand Up @@ -268,20 +272,17 @@ QRect QgsComposerPicture::clippedImageRect( double &boundRectWidthMM, double &bo
break;
}


return QRect( leftClip, topClip, boundRectWidthPixels, boundRectHeightPixels );

}

void QgsComposerPicture::setPictureFile( const QString& path )
{
mSourceFile.setFileName( path );
refreshPicture();
setPicturePath( path );
}

void QgsComposerPicture::refreshPicture()
{
QString source = mSourceFile.fileName();
QString source = mSourcePath;

//data defined source set?
mHasExpressionError = false;
Expand All @@ -301,25 +302,55 @@ void QgsComposerPicture::refreshPicture()
}
}

QFile path;
path.setFileName( source );
loadPicture( path );
loadPicture( source );
}

void QgsComposerPicture::loadPicture( const QFile& file )
void QgsComposerPicture::loadRemotePicture( const QString &url )
{
if ( !file.exists() )
//remote location

QgsNetworkContentFetcher fetcher;
//pause until HTML fetch
mLoaded = false;
fetcher.fetchContent( QUrl( url ) );
connect( &fetcher, SIGNAL( finished() ), this, SLOT( remotePictureLoaded() ) );

while ( !mLoaded )
{
qApp->processEvents();
}

QNetworkReply* reply = fetcher.reply();
if ( reply )
{
QImageReader imageReader( reply );
mImage = imageReader.read();
mMode = RASTER;
reply->deleteLater();
}
else
{
mMode = Unknown;
}
}

void QgsComposerPicture::loadLocalPicture( const QString &path )
{
QFile pic;
pic.setFileName( path );

if ( !pic.exists() )
{
mMode = Unknown;
}
else
{
QFileInfo sourceFileInfo( file );
QFileInfo sourceFileInfo( pic );
QString sourceFileSuffix = sourceFileInfo.suffix();
if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
{
//try to open svg
mSVG.load( file.fileName() );
mSVG.load( pic.fileName() );
if ( mSVG.isValid() )
{
mMode = SVG;
Expand All @@ -335,7 +366,7 @@ void QgsComposerPicture::loadPicture( const QFile& file )
else
{
//try to open raster with QImageReader
QImageReader imageReader( file.fileName() );
QImageReader imageReader( pic.fileName() );
if ( imageReader.read( &mImage ) )
{
mMode = RASTER;
Expand All @@ -347,11 +378,30 @@ void QgsComposerPicture::loadPicture( const QFile& file )
}
}

}

void QgsComposerPicture::remotePictureLoaded()
{
mLoaded = true;
}

void QgsComposerPicture::loadPicture( const QString &path )
{
if ( path.startsWith( "http" ) )
{
//remote location
loadRemotePicture( path );
}
else
{
//local location
loadLocalPicture( path );
}
if ( mMode != Unknown ) //make sure we start with a new QImage
{
recalculateSize();
}
else if ( mHasExpressionError || !( file.fileName().isEmpty() ) )
else if ( mHasExpressionError || !( path.isEmpty() ) )
{
//trying to load an invalid file or bad expression, show cross picture
mMode = SVG;
Expand Down Expand Up @@ -589,7 +639,18 @@ void QgsComposerPicture::setPictureExpression( QString expression )

QString QgsComposerPicture::pictureFile() const
{
return mSourceFile.fileName();
return picturePath();
}

void QgsComposerPicture::setPicturePath( const QString &path )
{
mSourcePath = path;
refreshPicture();
}

QString QgsComposerPicture::picturePath() const
{
return mSourcePath;
}

bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
Expand All @@ -599,7 +660,7 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
return false;
}
QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourcePath ) );
composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
composerPictureElem.setAttribute( "resizeMode", QString::number(( int )mResizeMode ) );
Expand Down Expand Up @@ -668,8 +729,7 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
setDataDefinedProperty( QgsComposerObject::PictureSource, expressionActive, true, sourceExpression, QString() );
}

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

//picture rotation
if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )
Expand Down
42 changes: 38 additions & 4 deletions src/core/composer/qgscomposerpicture.h
Expand Up @@ -67,16 +67,37 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
* @param path full path to the source image
* @see usePictureExpression
* @see pictureFile
* @deprecated use setPicturePath instead
*/
void setPictureFile( const QString& path );
Q_DECL_DEPRECATED void setPictureFile( const QString& path );

/**Returns the path of the source image file. Data defined picture source may override
* this value.
* @returns path to the source image
* @see usePictureExpression
* @see setPictureFile
* @deprecated use picturePath instead
*/
QString pictureFile() const;
Q_DECL_DEPRECATED QString pictureFile() const;

/**Sets the source path of the image (may be svg or a raster format). Data defined
* picture source may override this value. The path can either be a local path
* or a remote (http) path.
* @param path path for the source image
* @see usePictureExpression
* @see picturePath
* @note added in QGIS 2.5
*/
void setPicturePath( const QString& path );

/**Returns the path of the source image. Data defined picture source may override
* this value. The path can either be a local path or a remote (http) path.
* @returns path for the source image
* @see usePictureExpression
* @see setPicturePath
* @note added in QGIS 2.5
*/
QString picturePath() const;

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

QImage mImage;
QSvgRenderer mSVG;
QFile mSourceFile;
QString mSourcePath;
Mode mMode;

QSize mDefaultSvgSize;
Expand All @@ -302,9 +323,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
QgsComposerItem::ItemPositionMode mPictureAnchor;

bool mHasExpressionError;
bool mLoaded;

/**loads an image file into the picture item and redraws the item*/
void loadPicture( const QFile &file );
void loadPicture( const QString &path );

/**sets up the picture item and connects to relevant signals*/
void init();
Expand All @@ -313,6 +335,18 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
* anchor settings
*/
QRect clippedImageRect( double &boundRectWidthMM, double &boundRectHeightMM, QSize imageRectPixels );

/**Loads a remote picture for the item
*/
void loadRemotePicture( const QString &url );

/**Loads a local picture for the item
*/
void loadLocalPicture( const QString &path );

private slots:

void remotePictureLoaded();
};

#endif

0 comments on commit 9d18220

Please sign in to comment.