Skip to content

Commit

Permalink
[FEATURE][composer] Allow remote urls to be entered as picture path
Browse files Browse the repository at this point in the history
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.