Skip to content

Commit

Permalink
added getLegendGrafic feature to WmsDataProvider - Developed with fun…
Browse files Browse the repository at this point in the history
…ding from Regione Toscana-SITA

better scale management to avoid call getLegendGraphics everytime + some defaults + added code example to manage LegendURL when it will be correctly parsed - Developed with funding from Regione Toscana-SITA
  • Loading branch information
luipir committed Oct 18, 2013
1 parent 03a60d3 commit d770843
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/core/raster/qgsrasterdataprovider.h
Expand Up @@ -24,6 +24,7 @@

#include <QDateTime>
#include <QVariant>
#include <QImage>

#include "qgscolorrampshader.h"
#include "qgscoordinatereferencesystem.h"
Expand Down Expand Up @@ -186,6 +187,15 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
return QStringList();
}

/** \brief Returns the legend rendered as pixmap
* useful for that layer that need to get legend layer remotly as WMS */
virtual QImage getLegendGraphic( double scale=0, bool forceRefresh = false )
{
Q_UNUSED( scale );
Q_UNUSED( forceRefresh );
return QImage();
}

/** \brief Create pyramid overviews */
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
Expand Down
187 changes: 186 additions & 1 deletion src/providers/wms/qgswmsprovider.cpp
Expand Up @@ -59,7 +59,6 @@
#include <QImage>
#include <QImageReader>
#include <QPainter>
#include <QPixmap>
#include <QSet>
#include <QSettings>
#include <QEventLoop>
Expand All @@ -84,6 +83,9 @@ QgsWmsProvider::QgsWmsProvider( QString const &uri )
: QgsRasterDataProvider( uri )
, mHttpUri( uri )
, mHttpCapabilitiesResponse( 0 )
, mHttpGetLegendGraphicResponse( 0 )
, mGetLegendGraphicImage()
, mGetLegendGraphicScale( 0 )
, mImageCrs( DEFAULT_LATLON_CRS )
, mCachedImage( 0 )
, mCacheReply( 0 )
Expand Down Expand Up @@ -4588,6 +4590,189 @@ void QgsWmsProvider::showMessageBox( const QString& title, const QString& text )
message->showMessage();
}

QImage QgsWmsProvider::getLegendGraphic( double scale, bool forceRefresh )
{
// TODO manage return basing of getCapablity => avoid call if service is not available
// some services dowsn't expose getLegendGraphic in capabilities but adding LegendURL in
// the layer tags inside capabilities
QgsDebugMsg( "entering." );

if ( !scale && !mGetLegendGraphicScale)
{
QgsDebugMsg( QString( "No scale factor set" ) );
return QImage();
}

if ( scale && scale != mGetLegendGraphicScale )
{
forceRefresh = true;
QgsDebugMsg( QString( "Download again due to scale change from: %1 to: %2" ).arg( mGetLegendGraphicScale ).arg( scale ) );
}

if ( forceRefresh )
{
if ( scale )
{
mGetLegendGraphicScale = scale;
}

// if style is not defined, set as "default"
QString currentStyle("default");
if ( mActiveSubStyles[0] != "" )
{
currentStyle = mActiveSubStyles[0];
}

// add WMS GetGraphicLegend request
// TODO set sld version using instance var something like mSldVersion
// TODO at this moment LSD version can be get from LegendURL in getCapability,but parsing of
// this tag is not complete. Below the code that should work if pasing whould correct
// if ( mActiveSubLayers[0] == mCapabilities.capability.layer.name )
// {
// foreach( QgsWmsStyleProperty style, mCapabilities.capability.layer.style )
// {
// if ( currentStyle == style.name )
// {
// url.setUrl( style.legendUrl[0].onlineResource.xlinkHref, QUrl::StrictMode );
// }
// }
// } // is a sublayer
// else if ( mActiveSubLayers[0].contains( mCapabilities.capability.layer.name ) )
// {
// foreach( QgsWmsLayerProperty layerProperty, mCapabilities.capability.layer.layer )
// {
// if ( mActiveSubLayers[0] == layerProperty.name )
// {
// foreach( QgsWmsStyleProperty style, layerProperty.style )
// {
// if ( currentStyle == style.name )
// {
// url.setUrl( style.legendUrl[0].onlineResource.xlinkHref, QUrl::StrictMode );
// }
// }
// }
// }
// }
QUrl url( mIgnoreGetMapUrl ? mBaseUrl : getMapUrl(), QUrl::StrictMode );
setQueryItem( url, "SERVICE", "WMS" );
setQueryItem( url, "VERSION", mCapabilities.version );
setQueryItem( url, "SLD_VERSION", "1.1.0" ); // can not determine SLD_VERSION
setQueryItem( url, "REQUEST", "GetLegendGraphic" );
setQueryItem( url, "LAYER", mActiveSubLayers[0] );
setQueryItem( url, "STYLE", currentStyle );
setQueryItem( url, "SCALE", QString::number( scale, 'f') );
setQueryItem( url, "FORMAT", mImageMimeType );

mError = "";

QNetworkRequest request( url );
setAuthorization( request );
request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork );
request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );

QgsDebugMsg( QString( "getlegendgraphics: %1" ).arg( url.toString() ) );
mGetLegendGraphicReply = QgsNetworkAccessManager::instance()->get( request );

connect( mGetLegendGraphicReply, SIGNAL( finished() ), this, SLOT( getLegendGraphicReplyFinished() ) );
connect( mGetLegendGraphicReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( getLegendGraphicReplyProgress( qint64, qint64 ) ) );

while ( mGetLegendGraphicReply )
{
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents, WMS_THRESHOLD );
}
}
else
{
QgsDebugMsg( "get cached pixmap." );
}

QgsDebugMsg( "exiting." );

return mGetLegendGraphicImage;
}

void QgsWmsProvider::getLegendGraphicReplyFinished()
{
QgsDebugMsg( "entering." );
if ( mGetLegendGraphicReply->error() == QNetworkReply::NoError )
{
QgsDebugMsg( "reply ok" );
QVariant redirect = mGetLegendGraphicReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
if ( !redirect.isNull() )
{
emit statusChanged( tr( "GetLegendGraphic request redirected." ) );

const QUrl& toUrl = redirect.toUrl();
mGetLegendGraphicReply->request();
if ( toUrl == mGetLegendGraphicReply->url() )
{
mErrorFormat = "text/plain";
mError = tr( "Redirect loop detected: %1" ).arg( toUrl.toString() );
QgsMessageLog::logMessage( mError, tr( "WMS" ) );
mHttpGetLegendGraphicResponse.clear();
}
else
{
QNetworkRequest request( toUrl );
setAuthorization( request );
request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork );
request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );

mGetLegendGraphicReply->deleteLater();
QgsDebugMsg( QString( "redirected GetLegendGraphic: %1" ).arg( redirect.toString() ) );
mGetLegendGraphicReply = QgsNetworkAccessManager::instance()->get( request );

connect( mGetLegendGraphicReply, SIGNAL( finished() ), this, SLOT( getLegendGraphicReplyFinished() ) );
connect( mGetLegendGraphicReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( getLegendGraphicReplyProgress( qint64, qint64 ) ) );
return;
}
}

QVariant status = mGetLegendGraphicReply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
if ( !status.isNull() && status.toInt() >= 400 )
{
QVariant phrase = mGetLegendGraphicReply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
showMessageBox( tr( "GetLegendGraphic request error" ), tr( "Status: %1\nReason phrase: %2" ).arg( status.toInt() ).arg( phrase.toString() ) );
}
else
{
QImage myLocalImage = QImage::fromData( mGetLegendGraphicReply->readAll() ) ;
if ( myLocalImage.isNull() )
{
QgsMessageLog::logMessage( tr( "Returned legend image is flawed [URL: %2]" )
.arg( mGetLegendGraphicReply->url().toString() ), tr( "WMS" ) );
}
else
{
mGetLegendGraphicImage = myLocalImage;

#ifdef QGISDEBUG
QString filename = QDir::tempPath() + "/GetLegendGraphic.png";
mGetLegendGraphicImage.save(filename);
QgsDebugMsg( "saved GetLegendGraphic result in debug ile: "+filename );
#endif
}
}
}
else
{
mErrorFormat = "text/plain";
mError = tr( "Download of GetLegendGraphic failed: %1" ).arg( mGetLegendGraphicReply->errorString() );
QgsMessageLog::logMessage( mError, tr( "WMS" ) );
mHttpGetLegendGraphicResponse.clear();
}

mGetLegendGraphicReply->deleteLater();
mGetLegendGraphicReply = 0;
}

void QgsWmsProvider::getLegendGraphicReplyProgress( qint64 bytesReceived, qint64 bytesTotal )
{
QString msg = tr( "%1 of %2 bytes of GetLegendGraphic downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QString( "unknown number of" ) : QString::number( bytesTotal ) );
QgsDebugMsg( msg );
emit statusChanged( msg );
}

/**
* Class factory to return a pointer to a newly created
* QgsWmsProvider object
Expand Down
35 changes: 35 additions & 0 deletions src/providers/wms/qgswmsprovider.h
Expand Up @@ -632,6 +632,19 @@ class QgsWmsProvider : public QgsRasterDataProvider
QStringList subLayerStyles() const;


/**
* \brief Get GetLegendGraphic if service available otherwise QImage()
* BEAWARE call it the first time specifying scale parameter otherwise it always return QImage()
* \todo some services dowsn't expose getLegendGraphic in capabilities but adding LegendURL in
* the layer tags inside capabilities, but LegendURL parsing is still not developed => getLegendGraphic is
* always called assuming that error means service is not available. Other drowback is that SLD_VERSION
* is inside LegendURL, so at this moment it is fixed to 1.1.0 waiting a correct parsing of LegendURL
* in getCapability
* \param scale Optional parameter that is the Scale of the wms layer
* \param forceRefresh Optional bool parameter to force refresh getLegendGraphic call
*/
QImage getLegendGraphic( double scale = 0, bool forceRefresh = false );

// TODO: Get the WMS connection

// TODO: Get the table name associated with this provider instance
Expand Down Expand Up @@ -736,6 +749,8 @@ class QgsWmsProvider : public QgsRasterDataProvider
void capabilitiesReplyProgress( qint64, qint64 );
void identifyReplyFinished();
void tileReplyFinished();
void getLegendGraphicReplyFinished();
void getLegendGraphicReplyProgress( qint64, qint64 );

private:
void showMessageBox( const QString& title, const QString& text );
Expand Down Expand Up @@ -913,6 +928,21 @@ class QgsWmsProvider : public QgsRasterDataProvider
*/
QDomDocument mCapabilitiesDom;

/**
* GetLegendGraphic of the WMS (raw)
*/
QByteArray mHttpGetLegendGraphicResponse;

/**
* GetLegendGraphic WMS Pixmap result
*/
QImage mGetLegendGraphicImage;

/**
* GetLegendGraphic scale for the WMS Pixmap result
*/
double mGetLegendGraphicScale;

/**
* Last Service Exception Report from the WMS
*/
Expand Down Expand Up @@ -1003,6 +1033,11 @@ class QgsWmsProvider : public QgsRasterDataProvider
*/
QNetworkReply *mCapabilitiesReply;

/**
* The reply to the GetLegendGraphic request
*/
QNetworkReply *mGetLegendGraphicReply;

/**
* The reply to the capabilities request
*/
Expand Down

0 comments on commit d770843

Please sign in to comment.