Merge pull request #4699 from pblottiere/getlegendgraphic

[Server] WMS GetLegendGraphics refactoring
This commit is contained in:
rldhont 2017-06-12 09:40:57 +02:00 committed by GitHub
commit faa7c750bc
24 changed files with 1689 additions and 514 deletions

View File

@ -21,24 +21,15 @@
#include "qgsrasterrenderer.h"
#include "qgsmaplayerstylemanager.h"
const QString DEFAULT_NAMED_STYLE = "server_default_style";
QgsLayerRestorer::QgsLayerRestorer( const QList<QgsMapLayer *> &layers )
{
Q_FOREACH ( QgsMapLayer *layer, layers )
{
QgsLayerSettings settings;
settings.name = layer->name();
QString style = layer->styleManager()->currentStyle();
if ( style.isEmpty() )
{
layer->styleManager()->addStyleFromLayer( DEFAULT_NAMED_STYLE );
settings.mNamedStyle = DEFAULT_NAMED_STYLE;
}
else
{
settings.mNamedStyle = style;
}
settings.mNamedStyle = layer->styleManager()->currentStyle();
// set a custom property allowing to keep in memory if a SLD file has
// been loaded for rendering
@ -80,6 +71,7 @@ QgsLayerRestorer::~QgsLayerRestorer()
{
QgsLayerSettings settings = mLayerSettings[layer];
layer->styleManager()->setCurrentStyle( settings.mNamedStyle );
layer->setName( mLayerSettings[layer].name );
// if a SLD file has been loaded for rendering, we restore the previous one
QString errMsg;

View File

@ -30,6 +30,7 @@ class QgsLayerRestorer
{
struct QgsLayerSettings
{
QString name;
double mOpacity;
QString mNamedStyle;
QDomDocument mSldStyle;

View File

@ -23,6 +23,90 @@ namespace QgsWms
{
QgsWmsParameters::QgsWmsParameters()
{
const Parameter pBoxSpace = { ParameterName::BOXSPACE,
QVariant::Double,
QVariant( 2.0 ),
QVariant()
};
save( pBoxSpace );
const Parameter pSymbSpace = { ParameterName::SYMBOLSPACE,
QVariant::Double,
QVariant( 2.0 ),
QVariant()
};
save( pSymbSpace );
const Parameter pLayerSpace = { ParameterName::LAYERSPACE,
QVariant::Double,
QVariant( 3.0 ),
QVariant()
};
save( pLayerSpace );
const Parameter pTitleSpace = { ParameterName::LAYERTITLESPACE,
QVariant::Double,
QVariant( 3.0 ),
QVariant()
};
save( pTitleSpace );
const Parameter pSymbHeight = { ParameterName::SYMBOLHEIGHT,
QVariant::Double,
QVariant( 4.0 ),
QVariant()
};
save( pSymbHeight );
const Parameter pSymbWidth = { ParameterName::SYMBOLWIDTH,
QVariant::Double,
QVariant( 7.0 ),
QVariant()
};
save( pSymbWidth );
const Parameter pIcLabelSpace = { ParameterName::ICONLABELSPACE,
QVariant::Double,
QVariant( 2.0 ),
QVariant()
};
save( pIcLabelSpace );
const Parameter pItFontFamily = { ParameterName::ITEMFONTFAMILY,
QVariant::String,
QVariant( "" ),
QVariant()
};
save( pItFontFamily );
const Parameter pItFontBold = { ParameterName::ITEMFONTBOLD,
QVariant::Bool,
QVariant( false ),
QVariant()
};
save( pItFontBold );
const Parameter pItFontItalic = { ParameterName::ITEMFONTITALIC,
QVariant::Bool,
QVariant( false ),
QVariant()
};
save( pItFontItalic );
const Parameter pItFontSize = { ParameterName::ITEMFONTSIZE,
QVariant::Double,
QVariant( -1 ),
QVariant()
};
save( pItFontSize );
const Parameter pItFontColor = { ParameterName::ITEMFONTCOLOR,
QVariant::String,
QVariant( "black" ),
QVariant()
};
save( pItFontColor );
const Parameter pHighlightGeom = { ParameterName::HIGHLIGHT_GEOM,
QVariant::String,
QVariant( "" ),
@ -30,6 +114,13 @@ namespace QgsWms
};
save( pHighlightGeom );
const Parameter pShowFeatureCount = { ParameterName::SHOWFEATURECOUNT,
QVariant::Bool,
QVariant( false ),
QVariant()
};
save( pShowFeatureCount );
const Parameter pHighlightSymbol = { ParameterName::HIGHLIGHT_SYMBOL,
QVariant::String,
QVariant( "" ),
@ -46,7 +137,7 @@ namespace QgsWms
const Parameter pHighlightColor = { ParameterName::HIGHLIGHT_LABELCOLOR,
QVariant::String,
QVariant( "" ),
QVariant( "black" ),
QVariant()
};
save( pHighlightColor );
@ -74,7 +165,7 @@ namespace QgsWms
const Parameter pHighlightBufferColor = { ParameterName::HIGHLIGHT_LABELBUFFERCOLOR,
QVariant::String,
QVariant( "" ),
QVariant( "black" ),
QVariant()
};
save( pHighlightBufferColor );
@ -93,6 +184,34 @@ namespace QgsWms
};
save( pCRS );
const Parameter pFormat = { ParameterName::FORMAT,
QVariant::String,
QVariant( "" ),
QVariant()
};
save( pFormat );
const Parameter pRule = { ParameterName::RULE,
QVariant::String,
QVariant( "" ),
QVariant()
};
save( pRule );
const Parameter pRuleLabel = { ParameterName::RULELABEL,
QVariant::Bool,
QVariant( true ),
QVariant()
};
save( pRuleLabel );
const Parameter pScale = { ParameterName::SCALE,
QVariant::Double,
QVariant( "" ),
QVariant()
};
save( pScale );
const Parameter pHeight = { ParameterName::HEIGHT,
QVariant::Int,
QVariant( 0 ),
@ -135,6 +254,48 @@ namespace QgsWms
};
save( pLayers );
const Parameter pLayerTitle = { ParameterName::LAYERTITLE,
QVariant::Bool,
QVariant( true ),
QVariant()
};
save( pLayerTitle );
const Parameter pLayerFtFamily = { ParameterName::LAYERFONTFAMILY,
QVariant::String,
QVariant( "" ),
QVariant()
};
save( pLayerFtFamily );
const Parameter pLayerFtBold = { ParameterName::LAYERFONTBOLD,
QVariant::Bool,
QVariant( false ),
QVariant()
};
save( pLayerFtBold );
const Parameter pLayerFtItalic = { ParameterName::LAYERFONTITALIC,
QVariant::Bool,
QVariant( false ),
QVariant()
};
save( pLayerFtItalic );
const Parameter pLayerFtSize = { ParameterName::LAYERFONTSIZE,
QVariant::Double,
QVariant( -1 ),
QVariant()
};
save( pLayerFtSize );
const Parameter pLayerFtColor = { ParameterName::LAYERFONTCOLOR,
QVariant::String,
QVariant( "black" ),
QVariant()
};
save( pLayerFtColor );
const Parameter pStyle = { ParameterName::STYLE,
QVariant::String,
QVariant( "" ),
@ -226,6 +387,11 @@ namespace QgsWms
return mParameters[name].mValue;
}
QVariant QgsWmsParameters::defaultValue( ParameterName name ) const
{
return mParameters[name].mDefaultValue;
}
QStringList QgsWmsParameters::highlightGeom() const
{
return toStringList( ParameterName::HIGHLIGHT_GEOM, ';' );
@ -303,26 +469,77 @@ namespace QgsWms
return extent;
}
int QgsWmsParameters::height() const
QString QgsWmsParameters::height() const
{
bool ok = false;
int height = value( ParameterName::HEIGHT ).toInt( &ok );
if ( ! ok )
raiseError( ParameterName::HEIGHT );
return height;
return value( ParameterName::HEIGHT ).toString();
}
int QgsWmsParameters::width() const
QString QgsWmsParameters::width() const
{
bool ok = false;
int width = value( ParameterName::WIDTH ).toInt( &ok );
return value( ParameterName::WIDTH ).toString();
}
if ( ! ok )
raiseError( ParameterName::WIDTH );
int QgsWmsParameters::heightAsInt() const
{
return toInt( ParameterName::HEIGHT );
}
return width;
int QgsWmsParameters::widthAsInt() const
{
return toInt( ParameterName::WIDTH );
}
double QgsWmsParameters::toDouble( ParameterName p ) const
{
double val = defaultValue( p ).toDouble();
QString valStr = value( p ).toString();
if ( ! valStr.isEmpty() )
{
bool ok;
val = value( p ).toDouble( &ok );
if ( !ok )
{
QString n = name( p );
QString msg = n + " ('" + valStr + "') cannot be converted into a double";
raiseError( msg );
}
}
return val;
}
bool QgsWmsParameters::toBool( ParameterName p ) const
{
bool val = defaultValue( p ).toBool();
QString valStr = value( p ).toString();
if ( ! valStr.isEmpty() )
val = value( p ).toBool();
return val;
}
int QgsWmsParameters::toInt( ParameterName p ) const
{
int val = defaultValue( p ).toInt();
QString valStr = value( p ).toString();
if ( ! valStr.isEmpty() )
{
bool ok;
val = value( p ).toInt( &ok );
if ( !ok )
{
QString n = name( p );
QString msg = n + " ('" + valStr + "') cannot be converted into int";
raiseError( msg );
}
}
return val;
}
QStringList QgsWmsParameters::toStringList( ParameterName name, char delimiter ) const
@ -404,6 +621,285 @@ namespace QgsWms
return elements;
}
QString QgsWmsParameters::formatAsString() const
{
return value( ParameterName::FORMAT ).toString();
}
QgsWmsParameters::Format QgsWmsParameters::format() const
{
Format f = Format::PNG;
QString fStr = formatAsString();
if ( fStr.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0
|| fStr.compare( QLatin1String( "jpeg" ), Qt::CaseInsensitive ) == 0
|| fStr.compare( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) == 0 )
f = Format::JPG;
return f;
}
QString QgsWmsParameters::rule() const
{
return value( ParameterName::RULE ).toString();
}
QString QgsWmsParameters::ruleLabel() const
{
return value( ParameterName::RULELABEL ).toString();
}
bool QgsWmsParameters::ruleLabelAsBool() const
{
return toBool( ParameterName::RULELABEL );
}
QString QgsWmsParameters::scale() const
{
return value( ParameterName::SCALE ).toString();
}
double QgsWmsParameters::scaleAsDouble() const
{
return toDouble( ParameterName::SCALE );
}
QString QgsWmsParameters::showFeatureCount() const
{
return value( ParameterName::SHOWFEATURECOUNT ).toString();
}
bool QgsWmsParameters::showFeatureCountAsBool() const
{
return toBool( ParameterName::SHOWFEATURECOUNT );
}
QString QgsWmsParameters::boxSpace() const
{
return value( ParameterName::BOXSPACE ).toString();
}
double QgsWmsParameters::boxSpaceAsDouble() const
{
return toDouble( ParameterName::BOXSPACE );
}
QString QgsWmsParameters::layerSpace() const
{
return value( ParameterName::LAYERSPACE ).toString();
}
double QgsWmsParameters::layerSpaceAsDouble() const
{
return toDouble( ParameterName::LAYERSPACE );
}
QString QgsWmsParameters::layerTitleSpace() const
{
return value( ParameterName::LAYERTITLESPACE ).toString();
}
double QgsWmsParameters::layerTitleSpaceAsDouble() const
{
return toDouble( ParameterName::LAYERTITLESPACE );
}
QString QgsWmsParameters::symbolSpace() const
{
return value( ParameterName::SYMBOLSPACE ).toString();
}
double QgsWmsParameters::symbolSpaceAsDouble() const
{
return toDouble( ParameterName::SYMBOLSPACE );
}
QString QgsWmsParameters::symbolHeight() const
{
return value( ParameterName::SYMBOLHEIGHT ).toString();
}
double QgsWmsParameters::symbolHeightAsDouble() const
{
return toDouble( SYMBOLHEIGHT );
}
QString QgsWmsParameters::symbolWidth() const
{
return value( ParameterName::SYMBOLWIDTH ).toString();
}
double QgsWmsParameters::symbolWidthAsDouble() const
{
return toDouble( SYMBOLWIDTH );
}
QString QgsWmsParameters::iconLabelSpace() const
{
return value( ParameterName::ICONLABELSPACE ).toString();
}
double QgsWmsParameters::iconLabelSpaceAsDouble() const
{
return toDouble( ICONLABELSPACE );
}
QString QgsWmsParameters::layerFontFamily() const
{
return value( ParameterName::LAYERFONTFAMILY ).toString();
}
QString QgsWmsParameters::itemFontFamily() const
{
return value( ParameterName::ITEMFONTFAMILY ).toString();
}
QString QgsWmsParameters::layerFontBold() const
{
return value( ParameterName::LAYERFONTBOLD ).toString();
}
bool QgsWmsParameters::layerFontBoldAsBool() const
{
return toBool( ParameterName::LAYERFONTBOLD );
}
QString QgsWmsParameters::itemFontBold() const
{
return value( ParameterName::ITEMFONTBOLD ).toString();
}
bool QgsWmsParameters::itemFontBoldAsBool() const
{
return toBool( ParameterName::ITEMFONTBOLD );
}
QString QgsWmsParameters::layerFontItalic() const
{
return value( ParameterName::LAYERFONTITALIC ).toString();
}
bool QgsWmsParameters::layerFontItalicAsBool() const
{
return toBool( ParameterName::LAYERFONTITALIC );
}
QString QgsWmsParameters::itemFontItalic() const
{
return value( ParameterName::ITEMFONTITALIC ).toString();
}
bool QgsWmsParameters::itemFontItalicAsBool() const
{
return toBool( ParameterName::ITEMFONTITALIC );
}
QString QgsWmsParameters::layerFontSize() const
{
return value( ParameterName::LAYERFONTSIZE ).toString();
}
double QgsWmsParameters::layerFontSizeAsDouble() const
{
return toDouble( LAYERFONTSIZE );
}
QString QgsWmsParameters::layerFontColor() const
{
return value( ParameterName::LAYERFONTCOLOR ).toString();
}
QColor QgsWmsParameters::layerFontColorAsColor() const
{
ParameterName p = ParameterName::LAYERFONTCOLOR;
QColor c = defaultValue( p ).value<QColor>();
if ( !layerFontColor().isEmpty() )
{
c = QColor( layerFontColor() );
if ( !c.isValid() )
{
QString val = value( p ).toString();
QString n = name( p );
QString msg = n + " ('" + val + "') cannot be converted into a color";
raiseError( msg );
}
}
return c;
}
QString QgsWmsParameters::itemFontSize() const
{
return value( ParameterName::ITEMFONTSIZE ).toString();
}
double QgsWmsParameters::itemFontSizeAsDouble() const
{
return toDouble( ITEMFONTSIZE );
}
QFont QgsWmsParameters::layerFont() const
{
QFont font;
font.fromString( "" );
font.setBold( layerFontBoldAsBool() );
font.setItalic( layerFontItalicAsBool() );
if ( ! layerFontSize().isEmpty() )
font.setPointSizeF( layerFontSizeAsDouble() );
if ( !layerFontFamily().isEmpty() )
font.setFamily( layerFontFamily() );
return font;
}
QFont QgsWmsParameters::itemFont() const
{
QFont font;
font.fromString( "" );
font.setBold( itemFontBoldAsBool() );
font.setItalic( itemFontItalicAsBool() );
if ( ! itemFontSize().isEmpty() )
font.setPointSizeF( itemFontSizeAsDouble() );
if ( !itemFontFamily().isEmpty() )
font.setFamily( itemFontFamily() );
return font;
}
QString QgsWmsParameters::layerTitle() const
{
return value( ParameterName::LAYERTITLE ).toString();
}
bool QgsWmsParameters::layerTitleAsBool() const
{
return toBool( ParameterName::LAYERTITLE );
}
QgsLegendSettings QgsWmsParameters::legendSettings() const
{
QgsLegendSettings settings;
settings.setTitle( QString() );
settings.setBoxSpace( boxSpaceAsDouble() );
settings.setSymbolSize( QSizeF( symbolWidthAsDouble(), symbolHeightAsDouble() ) );
settings.rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, layerSpaceAsDouble() );
settings.rstyle( QgsLegendStyle::Subgroup ).setFont( layerFont() );
settings.rstyle( QgsLegendStyle::SymbolLabel ).setFont( itemFont() );
settings.rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, symbolSpaceAsDouble() );
settings.rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, iconLabelSpaceAsDouble() );
return settings;
}
QStringList QgsWmsParameters::highlightLabelString() const
{
return toStringList( ParameterName::HIGHLIGHT_LABELSTRING, ';' );

View File

@ -25,6 +25,7 @@
#include "qgsrectangle.h"
#include "qgswmsserviceexception.h"
#include "qgsserverrequest.h"
#include "qgslegendsettings.h"
#include "qgsgeometry.h"
/** QgsWmsParameters provides an interface to retrieve and manipulate WMS
@ -63,18 +64,41 @@ namespace QgsWms
public:
enum ParameterName
{
BOXSPACE,
CRS, // instead of SRS for WMS 1.3.0
// SRS, // for WMS 1.1.1
WIDTH,
HEIGHT,
BBOX,
ICONLABELSPACE,
ITEMFONTFAMILY,
ITEMFONTBOLD,
ITEMFONTITALIC,
ITEMFONTSIZE,
ITEMFONTCOLOR,
LAYER,
LAYERFONTFAMILY,
LAYERFONTBOLD,
LAYERFONTITALIC,
LAYERFONTSIZE,
LAYERFONTCOLOR,
LAYERTITLE,
LAYERS,
LAYERSPACE,
LAYERTITLESPACE,
SHOWFEATURECOUNT,
STYLE,
STYLES,
SYMBOLSPACE,
SYMBOLHEIGHT,
SYMBOLWIDTH,
OPACITIES,
SLD,
FILTER,
FORMAT,
RULE,
RULELABEL,
SCALE,
SELECTION,
HIGHLIGHT_GEOM,
HIGHLIGHT_SYMBOL,
@ -88,6 +112,13 @@ namespace QgsWms
};
Q_ENUM( ParameterName )
enum Format
{
NONE,
JPG,
PNG
};
struct Parameter
{
ParameterName mName;
@ -119,19 +150,31 @@ namespace QgsWms
*/
QString crs() const;
/** Returns WIDTH parameter as an int (0 if not defined). An exception is
* raised if it cannot be converted.
/** Returns WIDTH parameter or an empty string if not defined.
* \returns width parameter
*/
QString width() const;
/** Returns WIDTH parameter as an int or its default value if not
* defined. An exception is raised if WIDTH is defined and cannot be
* converted.
* \returns width parameter
* \throws QgsBadRequestException
*/
int width() const;
int widthAsInt() const;
/** Returns HEIGHT parameter as an int (0 if not defined). An exception
* is raised if it cannot be converted.
/** Returns HEIGHT parameter or an empty string if not defined.
* \returns height parameter
*/
QString height() const;
/** Returns HEIGHT parameter as an int or its default value if not
* defined. An exception is raised if HEIGHT is defined and cannot be
* converted.
* \returns height parameter
* \throws QgsBadRequestException
*/
int height() const;
int heightAsInt() const;
/** Returns BBOX if defined or an empty string.
* \returns bbox parameter
@ -188,6 +231,278 @@ namespace QgsWms
*/
QList<QgsWmsParametersLayer> layersParameters() const;
/** Returns FORMAT parameter as a string.
* \returns FORMAT parameter as string
*/
QString formatAsString() const;
/** Returns format. If the FORMAT parameter is not used, then the
* default value is PNG.
* \returns format
*/
Format format() const;
/** Returns RULE parameter or an empty string if none is defined
* \returns RULE parameter or an empty string if none is defined
*/
QString rule() const;
/** Returns RULELABEL parameter or an empty string if none is defined
* \returns RULELABEL parameter or an empty string if none is defined
*/
QString ruleLabel() const;
/** Returns RULELABEL as a bool. An exception is raised if an invalid
* parameter is found.
* \returns ruleLabel
* \throws QgsBadRequestException
*/
bool ruleLabelAsBool() const;
/** Returns SHOWFEATURECOUNT parameter or an empty string if none is defined
* \returns SHOWFEATURECOUNT parameter or an empty string if none is defined
*/
QString showFeatureCount() const;
/** Returns SHOWFEATURECOUNT as a bool. An exception is raised if an invalid
* parameter is found.
* \returns showFeatureCount
* \throws QgsBadRequestException
*/
bool showFeatureCountAsBool() const;
/** Returns SCALE parameter or an empty string if none is defined
* \returns SCALE parameter or an empty string if none is defined
*/
QString scale() const;
/** Returns SCALE as a double. An exception is raised if an invalid
* parameter is found.
* \returns scale
* \throws QgsBadRequestException
*/
double scaleAsDouble() const;
/** Returns BOXSPACE parameter or an empty string if not defined.
* \returns BOXSPACE parameter or an empty string if not defined.
*/
QString boxSpace() const;
/** Returns BOXSPACE as a double or its default value if not defined.
* An exception is raised if an invalid parameter is found.
* \returns boxSpace
* \throws QgsBadRequestException
*/
double boxSpaceAsDouble() const;
/** Returns LAYERSPACE parameter or an empty string if not defined.
* \returns LAYERSPACE parameter or an empty string if not defined.
*/
QString layerSpace() const;
/** Returns LAYERSPACE as a double or its default value if not defined.
* An exception is raised if an invalid parameter is found.
* \returns layerSpace
* \throws QgsBadRequestException
*/
double layerSpaceAsDouble() const;
/** Returns LAYERTITLESPACE parameter or an empty string if not defined.
* \returns LAYERTITLESPACE parameter or an empty string if not defined.
*/
QString layerTitleSpace() const;
/** Returns LAYERTITLESPACE as a double. An exception is raised if an invalid
* parameter is found.
* \returns layerTitleSpace
* \throws QgsBadRequestException
*/
double layerTitleSpaceAsDouble() const;
/** Returns SYMBOLSPACE parameter or an empty string if not defined.
* \returns SYMBOLSPACE parameter or an empty string if not defined.
*/
QString symbolSpace() const;
/** Returns SYMBOLSPACE as a double or its default value if not defined.
* An exception is raised if an invalid parameter is found.
* \returns symbolSpace
* \throws QgsBadRequestException
*/
double symbolSpaceAsDouble() const;
/** Returns ICONLABELSPACE parameter or an empty string if not defined.
* \returns ICONLABELSPACE parameter or an empty string if not defined.
*/
QString iconLabelSpace() const;
/** Returns ICONLABELSPACE as a double or its default value if not
* defined. An exception is raised if an invalid parameter is found.
* \returns iconLabelSpace
* \throws QgsBadRequestException
*/
double iconLabelSpaceAsDouble() const;
/** Returns SYMBOLWIDTH parameter or an empty string if not defined.
* \returns SYMBOLWIDTH parameter or an empty string if not defined.
*/
QString symbolWidth() const;
/** Returns SYMBOLWIDTH as a double or its default value if not defined.
* An exception is raised if an invalid parameter is found.
* \returns symbolWidth
* \throws QgsBadRequestException
*/
double symbolWidthAsDouble() const;
/** Returns SYMBOLHEIGHT parameter or an empty string if not defined.
* \returns SYMBOLHEIGHT parameter or an empty string if not defined.
*/
QString symbolHeight() const;
/** Returns SYMBOLHEIGHT as a double or its default value if not defined.
* An exception is raised if an invalid parameter is found.
* \returns symbolHeight
* \throws QgsBadRequestException
*/
double symbolHeightAsDouble() const;
/** Returns the layer font (built thanks to the LAYERFONTFAMILY,
* LAYERFONTSIZE, LAYERFONTBOLD, ... parameters).
* \returns layerFont
*/
QFont layerFont() const;
/** Returns LAYERFONTFAMILY parameter or an empty string if not defined.
* \returns LAYERFONTFAMILY parameter or an empty string if not defined.
*/
QString layerFontFamily() const;
/** Returns LAYERFONTBOLD parameter or an empty string if not defined.
* \returns LAYERFONTBOLD parameter or an empty string if not defined.
*/
QString layerFontBold() const;
/** Returns LAYERFONTBOLD as a boolean or its default value if not
* defined. An exception is raised if an
* invalid parameter is found.
* \returns layerFontBold
* \throws QgsBadRequestException
*/
bool layerFontBoldAsBool() const;
/** Returns LAYERFONTITALIC parameter or an empty string if not defined.
* \returns LAYERFONTITALIC parameter or an empty string if not defined.
*/
QString layerFontItalic() const;
/** Returns LAYERFONTITALIC as a boolean or its default value if not
* defined. An exception is raised if an invalid parameter is found.
* \returns layerFontItalic
* \throws QgsBadRequestException
*/
bool layerFontItalicAsBool() const;
/** Returns LAYERFONTSIZE parameter or an empty string if not defined.
* \returns LAYERFONTSIZE parameter or an empty string if not defined.
*/
QString layerFontSize() const;
/** Returns LAYERFONTSIZE as a double. An exception is raised if an invalid
* parameter is found.
* \returns layerFontSize
* \throws QgsBadRequestException
*/
double layerFontSizeAsDouble() const;
/** Returns LAYERFONTCOLOR parameter or an empty string if not defined.
* \returns LAYERFONTCOLOR parameter or an empty string if not defined.
*/
QString layerFontColor() const;
/** Returns LAYERFONTCOLOR as a color or its defined value if not
* defined. An exception is raised if an invalid parameter is found.
* \returns layerFontColor
* \throws QgsBadRequestException
*/
QColor layerFontColorAsColor() const;
/** Returns the item font (built thanks to the ITEMFONTFAMILY,
* ITEMFONTSIZE, ITEMFONTBOLD, ... parameters).
* \returns itemFont
*/
QFont itemFont() const;
/** Returns ITEMFONTFAMILY parameter or an empty string if not defined.
* \returns ITEMFONTFAMILY parameter or an empty string if not defined.
*/
QString itemFontFamily() const;
/** Returns ITEMFONTBOLD parameter or an empty string if not defined.
* \returns ITEMFONTBOLD parameter or an empty string if not defined.
*/
QString itemFontBold() const;
/** Returns ITEMFONTBOLD as a boolean or its default value if not
* defined. An exception is raised if an invalid parameter is found.
* \returns itemFontBold
* \throws QgsBadRequestException
*/
bool itemFontBoldAsBool() const;
/** Returns ITEMFONTITALIC parameter or an empty string if not defined.
* \returns ITEMFONTITALIC parameter or an empty string if not defined.
*/
QString itemFontItalic() const;
/** Returns ITEMFONTITALIC as a boolean or its default value if not
* defined. An exception is raised if an invalid parameter is found.
* \returns itemFontItalic
* \throws QgsBadRequestException
*/
bool itemFontItalicAsBool() const;
/** Returns ITEMFONTSIZE parameter or an empty string if not defined.
* \returns ITEMFONTSIZE parameter or an empty string if not defined.
*/
QString itemFontSize() const;
/** Returns ITEMFONTSIZE as a double. An exception is raised if an
* invalid parameter is found.
* \returns itemFontSize
* \throws QgsBadRequestException
*/
double itemFontSizeAsDouble() const;
/** Returns ITEMFONTCOLOR parameter or an empty string if not defined.
* \returns ITEMFONTCOLOR parameter or an empty string if not defined.
*/
QString itemFontColor() const;
/** Returns ITEMFONTCOLOR as a color. An exception is raised if an
* invalid parameter is found.
* \returns itemFontColor
* \throws QgsBadRequestException
*/
QColor itemFontColorAsColor() const;
/** Returns LAYERTITLE parameter or an empty string if not defined.
* \returns LAYERTITLE parameter or an empty string if not defined.
*/
QString layerTitle() const;
/** Returns LAYERTITLE as a bool or its default value if not defined. An
* exception is raised if an invalid parameter is found.
* \returns layerTitle
* \throws QgsBadRequestException
*/
bool layerTitleAsBool() const;
/** Returns legend settings
* \returns legend settings
*/
QgsLegendSettings legendSettings() const;
/** Returns parameters for each highlight layer.
* \returns parameters for each highlight layer
*/
@ -286,8 +601,12 @@ namespace QgsWms
void raiseError( const QString &msg ) const;
void initParameters();
QVariant value( ParameterName name ) const;
QVariant defaultValue( ParameterName name ) const;
void log( const QString &msg ) const;
void save( const Parameter &parameter );
double toDouble( ParameterName name ) const;
bool toBool( ParameterName name ) const;
int toInt( ParameterName name ) const;
QStringList toStringList( ParameterName name, char delimiter = ',' ) const;
QList<int> toIntList( QStringList l, ParameterName name ) const;
QList<float> toFloatList( QStringList l, ParameterName name ) const;

View File

@ -67,6 +67,7 @@
#include "qgspallabeling.h"
#include "qgslayerrestorer.h"
#include "qgsdxfexport.h"
#include "qgssymbollayerutils.h"
#include <QImage>
#include <QPainter>
@ -111,8 +112,6 @@ namespace QgsWms
QgsWmsConfigParser *parser )
: mParameters( parameters )
, mOwnsConfigParser( false )
, mDrawLegendLayerLabel( true )
, mDrawLegendItemLabel( true )
, mConfigParser( parser )
, mAccessControl( serverIface->accessControls() )
, mSettings( *serverIface->serverSettings() )
@ -138,290 +137,100 @@ namespace QgsWms
QImage *QgsRenderer::getLegendGraphics()
{
if ( !mConfigParser )
{
throw QgsException( QStringLiteral( "No config parser" ) );
}
if ( !mParameters.contains( QStringLiteral( "LAYER" ) ) && !mParameters.contains( QStringLiteral( "LAYERS" ) ) )
{
// check parameters
if ( mWmsParameters.allLayersNickname().isEmpty() )
throw QgsBadRequestException( QStringLiteral( "LayerNotSpecified" ),
QStringLiteral( "LAYER is mandatory for GetLegendGraphic operation" ) );
}
if ( !mParameters.contains( QStringLiteral( "FORMAT" ) ) )
{
if ( mWmsParameters.format() == QgsWmsParameters::Format::NONE )
throw QgsBadRequestException( QStringLiteral( "FormatNotSpecified" ),
QStringLiteral( "FORMAT is mandatory for GetLegendGraphic operation" ) );
}
bool contentBasedLegend = false;
QgsRectangle contentBasedLegendExtent;
if ( mParameters.contains( QStringLiteral( "BBOX" ) ) )
{
contentBasedLegend = true;
contentBasedLegendExtent = parseBbox( mParameters.value( QStringLiteral( "BBOX" ) ) );
if ( contentBasedLegendExtent.isEmpty() )
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ),
QStringLiteral( "Invalid BBOX parameter" ) );
if ( mParameters.contains( QStringLiteral( "RULE" ) ) )
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ),
QStringLiteral( "BBOX parameter cannot be combined with RULE" ) );
}
QStringList layersList, stylesList;
readLayersAndStyles( mParameters, layersList, stylesList );
if ( layersList.isEmpty() )
{
return nullptr;
}
//scale
double scaleDenominator = -1;
QMap<QString, QString>::const_iterator scaleIt = mParameters.constFind( QStringLiteral( "SCALE" ) );
if ( scaleIt != mParameters.constEnd() )
{
bool conversionSuccess;
double scaleValue = scaleIt.value().toDouble( &conversionSuccess );
if ( conversionSuccess )
{
scaleDenominator = scaleValue;
}
}
if ( ! mWmsParameters.scale().isEmpty() )
scaleDenominator = mWmsParameters.scaleAsDouble();
QgsCoordinateReferenceSystem dummyCRS;
QStringList layerIds = layerSet( layersList, stylesList, dummyCRS, scaleDenominator );
if ( layerIds.isEmpty() )
{
return nullptr;
}
QgsLegendSettings legendSettings = mWmsParameters.legendSettings();
//get icon size, spaces between legend items and font from config parser
double boxSpace, layerSpace, layerTitleSpace, symbolSpace, iconLabelSpace, symbolWidth, symbolHeight;
QFont layerFont, itemFont;
QColor layerFontColor, itemFontColor;
legendParameters( boxSpace, layerSpace, layerTitleSpace, symbolSpace,
iconLabelSpace, symbolWidth, symbolHeight, layerFont, itemFont, layerFontColor, itemFontColor );
// get layers
std::unique_ptr<QgsLayerRestorer> restorer;
restorer.reset( new QgsLayerRestorer( mNicknameLayers.values() ) );
QString rule;
int ruleSymbolWidth = 0, ruleSymbolHeight = 0;
QMap<QString, QString>::const_iterator ruleIt = mParameters.constFind( QStringLiteral( "RULE" ) );
if ( ruleIt != mParameters.constEnd() )
{
rule = ruleIt.value();
QList<QgsMapLayer *> layers;
QList<QgsWmsParametersLayer> params = mWmsParameters.layersParameters();
QMap<QString, QString>::const_iterator widthIt = mParameters.constFind( QStringLiteral( "WIDTH" ) );
if ( widthIt != mParameters.constEnd() )
{
bool conversionSuccess;
double width = widthIt.value().toDouble( &conversionSuccess );
if ( conversionSuccess )
{
ruleSymbolWidth = width;
}
}
QString sld = mWmsParameters.sld();
if ( !sld.isEmpty() )
layers = sldStylizedLayers( sld );
else
layers = stylizedLayers( params );
QMap<QString, QString>::const_iterator heightIt = mParameters.constFind( QStringLiteral( "HEIGHT" ) );
if ( heightIt != mParameters.constEnd() )
{
bool conversionSuccess;
double width = heightIt.value().toDouble( &conversionSuccess );
if ( conversionSuccess )
{
ruleSymbolHeight = width;
}
}
}
removeUnwantedLayers( layers, scaleDenominator );
std::reverse( layers.begin(), layers.end() );
// Checks showFeatureCount parameter
bool showFeatureCount = false;
if ( mParameters.contains( QStringLiteral( "SHOWFEATURECOUNT" ) ) )
showFeatureCount = QVariant( mParameters[ QStringLiteral( "SHOWFEATURECOUNT" )] ).toBool();
// check permissions
Q_FOREACH ( QgsMapLayer *ml, layers )
checkLayerReadPermissions( ml );
// Create the layer tree root
// build layer tree model for legend
QgsLayerTree rootGroup;
// Store layers' name to reset them
QMap<QString, QString> layerNameMap;
// Create tree layer node for each layer
Q_FOREACH ( const QString &layerId, layerIds )
std::unique_ptr<QgsLayerTreeModel> legendModel;
legendModel.reset( buildLegendTreeModel( layers, scaleDenominator, rootGroup ) );
// rendering step
qreal dpmm = dotsPerMm();
std::unique_ptr<QImage> image;
std::unique_ptr<QPainter> painter;
if ( !mWmsParameters.rule().isEmpty() )
{
// get layer
QgsMapLayer *ml = QgsProject::instance()->mapLayer( layerId );
// create tree layer node
QgsLayerTreeLayer *layer = rootGroup.addLayer( ml );
// store the layer's name
layerNameMap.insert( layerId, ml->name() );
// set layer name with layer's title to have it in legend
if ( !ml->title().isEmpty() )
layer->setName( ml->title() );
// set show feature count
if ( showFeatureCount )
layer->setCustomProperty( QStringLiteral( "showFeatureCount" ), showFeatureCount );
}
QgsLayerTreeModel legendModel( &rootGroup );
QString rule = mWmsParameters.rule();
int width = mWmsParameters.widthAsInt();
int height = mWmsParameters.heightAsInt();
if ( scaleDenominator > 0 )
legendModel.setLegendFilterByScale( scaleDenominator );
image.reset( createImage( width, height, false ) );
painter.reset( new QPainter( image.get() ) );
painter->setRenderHint( QPainter::Antialiasing, true );
painter->scale( dpmm, dpmm );
QgsMapSettings contentBasedMapSettings;
if ( contentBasedLegend )
{
HitTest hitTest;
getMapOld( contentBasedMapSettings, &hitTest );
Q_FOREACH ( QgsLayerTreeNode *node, rootGroup.children() )
{
Q_ASSERT( QgsLayerTree::isLayer( node ) );
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
if ( !vl || !vl->renderer() )
continue;
const SymbolSet &usedSymbols = hitTest[vl];
QList<int> order;
int i = 0;
Q_FOREACH ( const QgsLegendSymbolItem &legendItem, vl->renderer()->legendSymbolItemsV2() )
{
if ( usedSymbols.contains( legendItem.legacyRuleKey() ) )
order.append( i );
++i;
}
// either remove the whole layer or just filter out some items
if ( order.isEmpty() )
rootGroup.removeChildNode( nodeLayer );
else
{
QgsMapLayerLegendUtils::setLegendNodeOrder( nodeLayer, order );
legendModel.refreshLayerLegend( nodeLayer );
}
}
}
// find out DPI
QImage *tmpImage = createImage( 1, 1, false );
if ( !tmpImage )
return nullptr;
qreal dpmm = tmpImage->dotsPerMeterX() / 1000.0;
delete tmpImage;
// setup legend configuration
QgsLegendSettings legendSettings;
legendSettings.setTitle( QString() );
legendSettings.setBoxSpace( boxSpace );
legendSettings.rstyle( QgsLegendStyle::Subgroup ).setMargin( QgsLegendStyle::Top, layerSpace );
// TODO: not available: layer title space
legendSettings.rstyle( QgsLegendStyle::Symbol ).setMargin( QgsLegendStyle::Top, symbolSpace );
legendSettings.rstyle( QgsLegendStyle::SymbolLabel ).setMargin( QgsLegendStyle::Left, iconLabelSpace );
legendSettings.setSymbolSize( QSizeF( symbolWidth, symbolHeight ) );
legendSettings.rstyle( QgsLegendStyle::Subgroup ).setFont( layerFont );
legendSettings.rstyle( QgsLegendStyle::SymbolLabel ).setFont( itemFont );
// TODO: not available: layer font color
legendSettings.setFontColor( itemFontColor );
if ( contentBasedLegend )
{
legendSettings.setMapScale( contentBasedMapSettings.scale() );
}
if ( !rule.isEmpty() )
{
//create second image with the right dimensions
QImage *paintImage = createImage( ruleSymbolWidth, ruleSymbolHeight, false );
//go through the items a second time for painting
QPainter p( paintImage );
p.setRenderHint( QPainter::Antialiasing, true );
p.scale( dpmm, dpmm );
QgsLayerTreeModelLegendNode *legendNode = _findLegendNodeForRule( &legendModel, rule );
QgsLayerTreeModelLegendNode *legendNode = _findLegendNodeForRule( legendModel.get(), rule );
if ( legendNode )
{
QgsLayerTreeModelLegendNode::ItemContext ctx;
ctx.painter = &p;
ctx.painter = painter.get();
ctx.labelXOffset = 0;
ctx.point = QPointF();
double itemHeight = ruleSymbolHeight / dpmm;
double itemHeight = height / dpmm;
legendNode->drawSymbol( legendSettings, &ctx, itemHeight );
}
QgsProject::instance()->removeAllMapLayers();
return paintImage;
}
QList<QgsLayerTreeNode *> rootChildren = rootGroup.children();
Q_FOREACH ( QgsLayerTreeNode *node, rootChildren )
{
if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
#ifdef HAVE_SERVER_PYTHON_PLUGINS
if ( !mAccessControl->layerReadPermission( nodeLayer->layer() ) )
{
throw QgsSecurityException( QStringLiteral( "You are not allowed to access to the layer: " ).arg( nodeLayer->layer()->name() ) );
}
#endif
// layer titles - hidden or not
QgsLegendRenderer::setNodeLegendStyle( nodeLayer, mDrawLegendLayerLabel ? QgsLegendStyle::Subgroup : QgsLegendStyle::Hidden );
// rule item titles
if ( !mDrawLegendItemLabel )
{
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel.layerLegendNodes( nodeLayer ) )
{
legendNode->setUserLabel( QStringLiteral( " " ) ); // empty string = no override, so let's use one space
}
}
else if ( !mDrawLegendLayerLabel )
{
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel.layerLegendNodes( nodeLayer ) )
{
if ( legendNode->isEmbeddedInParent() )
legendNode->setEmbeddedInParent( false );
}
}
painter->end();
}
}
QgsLegendRenderer legendRenderer( &legendModel, legendSettings );
QSizeF minSize = legendRenderer.minimumSize();
QSize s( minSize.width() * dpmm, minSize.height() * dpmm );
QImage *paintImage = createImage( s.width(), s.height(), false );
QPainter p( paintImage );
p.setRenderHint( QPainter::Antialiasing, true );
p.scale( dpmm, dpmm );
legendRenderer.drawLegend( &p );
p.end();
// reset layers' name
Q_FOREACH ( const QString &layerId, layerIds )
else
{
QgsMapLayer *ml = QgsProject::instance()->mapLayer( layerId );
ml->setName( layerNameMap[ layerId ] );
QgsLegendRenderer legendRendererNew( legendModel.get(), legendSettings );
QSizeF minSize = legendRendererNew.minimumSize();
QSize s( minSize.width() * dpmm, minSize.height() * dpmm );
image.reset( createImage( s.width(), s.height(), false ) );
painter.reset( new QPainter( image.get() ) );
painter->setRenderHint( QPainter::Antialiasing, true );
painter->scale( dpmm, dpmm );
legendRendererNew.drawLegend( painter.get() );
painter->end();
}
// clear map layer registry
QgsProject::instance()->removeAllMapLayers();
return paintImage;
return image.release();
}
void QgsRenderer::runHitTest( const QgsMapSettings &mapSettings, HitTest &hitTest ) const
{
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
Q_FOREACH ( const QString &layerID, mapSettings.layerIds() )
Q_FOREACH ( const QString &id, mapSettings.layerIds() )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( layerID ) );
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mProject->mapLayer( id ) );
if ( !vl || !vl->renderer() )
continue;
@ -455,113 +264,15 @@ namespace QgsWms
if ( moreSymbolsPerFeature )
{
Q_FOREACH ( QgsSymbol *s, r->originalSymbolsForFeature( f, context ) )
usedSymbols.insert( s );
usedSymbols.insert( QgsSymbolLayerUtils::symbolProperties( s ) );
}
else
usedSymbols.insert( r->originalSymbolForFeature( f, context ) );
usedSymbols.insert( QgsSymbolLayerUtils::symbolProperties( r->originalSymbolForFeature( f, context ) ) );
}
r->stopRender( context );
}
void QgsRenderer::legendParameters( double &boxSpace, double &layerSpace, double &layerTitleSpace,
double &symbolSpace, double &iconLabelSpace, double &symbolWidth, double &symbolHeight,
QFont &layerFont, QFont &itemFont, QColor &layerFontColor, QColor &itemFontColor )
{
//spaces between legend elements
QMap<QString, QString>::const_iterator boxSpaceIt = mParameters.constFind( QStringLiteral( "BOXSPACE" ) );
boxSpace = ( boxSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendBoxSpace() : boxSpaceIt.value().toDouble();
QMap<QString, QString>::const_iterator layerSpaceIt = mParameters.constFind( QStringLiteral( "LAYERSPACE" ) );
layerSpace = ( layerSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendLayerSpace() : layerSpaceIt.value().toDouble();
QMap<QString, QString>::const_iterator layerTitleSpaceIt = mParameters.constFind( QStringLiteral( "LAYERTITLESPACE" ) );
layerTitleSpace = ( layerTitleSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendLayerTitleSpace() : layerTitleSpaceIt.value().toDouble();
QMap<QString, QString>::const_iterator symbolSpaceIt = mParameters.constFind( QStringLiteral( "SYMBOLSPACE" ) );
symbolSpace = ( symbolSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolSpace() : symbolSpaceIt.value().toDouble();
QMap<QString, QString>::const_iterator iconLabelSpaceIt = mParameters.constFind( QStringLiteral( "ICONLABELSPACE" ) );
iconLabelSpace = ( iconLabelSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendIconLabelSpace() : iconLabelSpaceIt.value().toDouble();
QMap<QString, QString>::const_iterator symbolWidthIt = mParameters.constFind( QStringLiteral( "SYMBOLWIDTH" ) );
symbolWidth = ( symbolWidthIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolWidth() : symbolWidthIt.value().toDouble();
QMap<QString, QString>::const_iterator symbolHeightIt = mParameters.constFind( QStringLiteral( "SYMBOLHEIGHT" ) );
symbolHeight = ( symbolHeightIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolHeight() : symbolHeightIt.value().toDouble();
//font properties
layerFont = mConfigParser->legendLayerFont();
QMap<QString, QString>::const_iterator layerFontFamilyIt = mParameters.constFind( QStringLiteral( "LAYERFONTFAMILY" ) );
if ( layerFontFamilyIt != mParameters.constEnd() )
{
layerFont.setFamily( layerFontFamilyIt.value() );
}
QMap<QString, QString>::const_iterator layerFontBoldIt = mParameters.constFind( QStringLiteral( "LAYERFONTBOLD" ) );
if ( layerFontBoldIt != mParameters.constEnd() )
{
layerFont.setBold( layerFontBoldIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
QMap<QString, QString>::const_iterator layerFontItalicIt = mParameters.constFind( QStringLiteral( "LAYERFONTITALIC" ) );
if ( layerFontItalicIt != mParameters.constEnd() )
{
layerFont.setItalic( layerFontItalicIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
QMap<QString, QString>::const_iterator layerFontSizeIt = mParameters.constFind( QStringLiteral( "LAYERFONTSIZE" ) );
layerFont.setPointSizeF( layerFontSizeIt != mParameters.constEnd() ? layerFontSizeIt.value().toDouble() : layerFont.pointSizeF() );
QMap<QString, QString>::const_iterator layerFontColorIt = mParameters.constFind( QStringLiteral( "LAYERFONTCOLOR" ) );
if ( layerFontColorIt != mParameters.constEnd() )
{
layerFontColor.setNamedColor( layerFontColorIt.value() );
}
else
{
layerFontColor = QColor( 0, 0, 0 );
}
QMap<QString, QString>::const_iterator layerTitleIt = mParameters.constFind( QStringLiteral( "LAYERTITLE" ) );
if ( layerTitleIt != mParameters.constEnd() )
{
mDrawLegendLayerLabel = ( layerTitleIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
else
{
mDrawLegendLayerLabel = true;
}
itemFont = mConfigParser->legendItemFont();
QMap<QString, QString>::const_iterator itemFontFamilyIt = mParameters.constFind( QStringLiteral( "ITEMFONTFAMILY" ) );
if ( itemFontFamilyIt != mParameters.constEnd() )
{
itemFont.setFamily( itemFontFamilyIt.value() );
}
QMap<QString, QString>::const_iterator itemFontBoldIt = mParameters.constFind( QStringLiteral( "ITEMFONTBOLD" ) );
if ( itemFontBoldIt != mParameters.constEnd() )
{
itemFont.setBold( itemFontBoldIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
QMap<QString, QString>::const_iterator itemFontItalicIt = mParameters.constFind( QStringLiteral( "ITEMFONTITALIC" ) );
if ( itemFontItalicIt != mParameters.constEnd() )
{
itemFont.setItalic( itemFontItalicIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
QMap<QString, QString>::const_iterator itemFontSizeIt = mParameters.constFind( QStringLiteral( "ITEMFONTSIZE" ) );
itemFont.setPointSizeF( itemFontSizeIt != mParameters.constEnd() ? itemFontSizeIt.value().toDouble() : itemFont.pointSizeF() );
QMap<QString, QString>::const_iterator itemFontColorIt = mParameters.constFind( QStringLiteral( "ITEMFONTCOLOR" ) );
if ( itemFontColorIt != mParameters.constEnd() )
{
itemFontColor.setNamedColor( itemFontColorIt.value() );
}
else
{
itemFontColor = QColor( 0, 0, 0 );
}
QMap<QString, QString>::const_iterator itemLabelIt = mParameters.constFind( QStringLiteral( "RULELABEL" ) );
if ( itemLabelIt != mParameters.constEnd() )
{
mDrawLegendItemLabel = ( itemLabelIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 );
}
else
{
mDrawLegendItemLabel = true;
}
}
QByteArray *QgsRenderer::getPrint( const QString &formatString )
{
QStringList layersList, stylesList, layerIdList;
@ -707,105 +418,6 @@ namespace QgsWms
}
#endif
QImage *QgsRenderer::getMapOld( HitTest *hitTest )
{
QgsMapSettings mapSettings;
return getMapOld( mapSettings, hitTest );
}
QImage *QgsRenderer::getMapOld( QgsMapSettings &mapSettings, HitTest *hitTest )
{
if ( !checkMaximumWidthHeight() )
{
throw QgsBadRequestException( QStringLiteral( "Size error" ),
QStringLiteral( "The requested map size is too large" ) );
}
QStringList layersList, stylesList, layerIdList;
QImage *image = initializeRendering( layersList, stylesList, layerIdList, mapSettings );
QStringList layerSetIds = mapSettings.layerIds();
QStringList highlightLayersId = QgsWmsConfigParser::addHighlightLayers( mParameters, layerSetIds );
QList<QgsMapLayer *> layerSet;
Q_FOREACH ( QString layerSetId, layerSetIds )
{
layerSet.append( QgsProject::instance()->mapLayer( layerSetId ) );
}
mapSettings.setLayers( layerSet );
#ifdef HAVE_SERVER_PYTHON_PLUGINS
Q_FOREACH ( QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
{
if ( !mAccessControl->layerReadPermission( layer ) )
{
throw QgsSecurityException( QStringLiteral( "You are not allowed to access to the layer: %1" ).arg( layer->name() ) );
}
}
#endif
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
std::unique_ptr< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer( mAccessControl ) );
applyRequestedLayerFilters( layersList, mapSettings, filterRestorer->originalFilters() );
#ifdef HAVE_SERVER_PYTHON_PLUGINS
applyAccessControlLayersFilters( layersList, filterRestorer->originalFilters() );
#endif
QStringList selectedLayerIdList = applyFeatureSelections( layersList );
QList< QPair< QgsVectorLayer *, QgsFeatureRenderer *> > bkVectorRenderers;
QList< QPair< QgsRasterLayer *, QgsRasterRenderer * > > bkRasterRenderers;
QList< QPair< QgsVectorLayer *, double > > labelTransparencies;
QList< QPair< QgsVectorLayer *, double > > labelBufferTransparencies;
applyOpacities( layersList, bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
std::unique_ptr<QPainter> painter;
if ( hitTest )
{
runHitTest( mapSettings, *hitTest );
painter.reset( new QPainter() );
}
else
{
#ifdef HAVE_SERVER_PYTHON_PLUGINS
mAccessControl->resolveFilterFeatures( mapSettings.layers() );
#endif
QgsMapRendererJobProxy renderJob( mSettings.parallelRendering(), mSettings.maxThreads(), mAccessControl );
renderJob.render( mapSettings, image );
painter.reset( renderJob.takePainter() );
}
if ( mConfigParser )
{
//draw configuration format specific overlay items
mConfigParser->drawOverlays( painter.get(), image->dotsPerMeterX() / 1000.0 * 25.4, image->width(), image->height() );
}
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
clearFeatureSelections( selectedLayerIdList );
QgsWmsConfigParser::removeHighlightLayers( highlightLayersId );
if ( !hitTest )
QgsProject::instance()->removeAllMapLayers();
painter->end();
//test if width / height ratio of image is the same as the ratio of WIDTH / HEIGHT parameters. If not, the image has to be scaled (required by WMS spec)
int widthParam = mParameters.value( "WIDTH", "0" ).toInt();
int heightParam = mParameters.value( "HEIGHT", "0" ).toInt();
if ( widthParam != image->width() || heightParam != image->height() )
{
//scale image
*image = image->scaled( widthParam, heightParam, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
}
return image;
}
QImage *QgsRenderer::getMap( HitTest *hitTest )
{
QgsMapSettings mapSettings;
@ -1405,20 +1017,10 @@ namespace QgsWms
bool conversionSuccess;
if ( width < 0 )
{
width = mParameters.value( QStringLiteral( "WIDTH" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
width = 0;
}
width = mWmsParameters.widthAsInt();
if ( height < 0 )
{
height = mParameters.value( QStringLiteral( "HEIGHT" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
{
height = 0;
}
}
height = mWmsParameters.heightAsInt();
//Adapt width / height if the aspect ratio does not correspond with the BBOX.
//Required by WMS spec. 1.3.
@ -2463,15 +2065,15 @@ namespace QgsWms
{
//test if maxWidth / maxHeight set and WIDTH / HEIGHT parameter is in the range
int wmsMaxWidth = QgsServerProjectUtils::wmsMaxWidth( *mProject );
int width = mWmsParameters.width();
if ( wmsMaxWidth != -1 && width != -1 && width > wmsMaxWidth )
int width = mWmsParameters.widthAsInt();
if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
{
return false;
}
int wmsMaxHeight = QgsServerProjectUtils::wmsMaxHeight( *mProject );
int height = mWmsParameters.height();
if ( wmsMaxHeight != -1 && height != -1 && height > wmsMaxHeight )
int height = mWmsParameters.heightAsInt();
if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
{
return false;
}
@ -3272,8 +2874,8 @@ namespace QgsWms
// WIDTH / HEIGHT parameters. If not, the image has to be scaled (required
// by WMS spec)
QImage *scaledImage = nullptr;
int width = mWmsParameters.width();
int height = mWmsParameters.height();
int width = mWmsParameters.widthAsInt();
int height = mWmsParameters.heightAsInt();
if ( width != image->width() || height != image->height() )
{
scaledImage = new QImage( image->scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
@ -3311,4 +2913,125 @@ namespace QgsWms
layers = wantedLayers;
}
QgsLayerTreeModel *QgsRenderer::buildLegendTreeModel( const QList<QgsMapLayer *> &layers, double scaleDenominator, QgsLayerTree &rootGroup )
{
// get params
bool showFeatureCount = mWmsParameters.showFeatureCountAsBool();
bool drawLegendLayerLabel = mWmsParameters.layerTitleAsBool();
bool drawLegendItemLabel = mWmsParameters.ruleLabelAsBool();
bool ruleDefined = false;
if ( !mWmsParameters.rule().isEmpty() )
ruleDefined = true;
bool contentBasedLegend = false;
QgsRectangle contentBasedLegendExtent;
if ( ! mWmsParameters.bbox().isEmpty() )
{
contentBasedLegend = true;
contentBasedLegendExtent = mWmsParameters.bboxAsRectangle();
if ( contentBasedLegendExtent.isEmpty() )
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ),
QStringLiteral( "Invalid BBOX parameter" ) );
if ( !mWmsParameters.rule().isEmpty() )
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ),
QStringLiteral( "BBOX parameter cannot be combined with RULE" ) );
}
// build layer tree
rootGroup.clear();
Q_FOREACH ( QgsMapLayer *ml, layers )
{
QgsLayerTreeLayer *lt = rootGroup.addLayer( ml );
lt->setCustomProperty( QStringLiteral( "showFeatureCount" ), showFeatureCount );
if ( !ml->title().isEmpty() )
lt->setName( ml->title() );
}
// build legend model
QgsLayerTreeModel *legendModel = new QgsLayerTreeModel( &rootGroup );
if ( scaleDenominator > 0 )
legendModel->setLegendFilterByScale( scaleDenominator );
QgsMapSettings contentBasedMapSettings;
if ( contentBasedLegend )
{
HitTest hitTest;
getMap( contentBasedMapSettings, &hitTest );
Q_FOREACH ( QgsLayerTreeNode *node, rootGroup.children() )
{
Q_ASSERT( QgsLayerTree::isLayer( node ) );
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
if ( !vl || !vl->renderer() )
continue;
const SymbolSet &usedSymbols = hitTest[vl];
QList<int> order;
int i = 0;
Q_FOREACH ( const QgsLegendSymbolItem &legendItem, vl->renderer()->legendSymbolItemsV2() )
{
QString sProp = QgsSymbolLayerUtils::symbolProperties( legendItem.legacyRuleKey() );
if ( usedSymbols.contains( sProp ) )
order.append( i );
++i;
}
// either remove the whole layer or just filter out some items
if ( order.isEmpty() )
rootGroup.removeChildNode( nodeLayer );
else
{
QgsMapLayerLegendUtils::setLegendNodeOrder( nodeLayer, order );
legendModel->refreshLayerLegend( nodeLayer );
}
}
}
// if legend is not based on rendering rules
if ( ! ruleDefined )
{
QList<QgsLayerTreeNode *> rootChildren = rootGroup.children();
Q_FOREACH ( QgsLayerTreeNode *node, rootChildren )
{
if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
// layer titles - hidden or not
QgsLegendRenderer::setNodeLegendStyle( nodeLayer, drawLegendLayerLabel ? QgsLegendStyle::Subgroup : QgsLegendStyle::Hidden );
// rule item titles
if ( !drawLegendItemLabel )
{
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel->layerLegendNodes( nodeLayer ) )
{
legendNode->setUserLabel( QStringLiteral( " " ) ); // empty string = no override, so let's use one space
}
}
else if ( !drawLegendLayerLabel )
{
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel->layerLegendNodes( nodeLayer ) )
{
if ( legendNode->isEmbeddedInParent() )
legendNode->setEmbeddedInParent( false );
}
}
}
}
}
return legendModel;
}
qreal QgsRenderer::dotsPerMm() const
{
std::unique_ptr<QImage> tmpImage( createImage( 1, 1, false ) );
return tmpImage->dotsPerMeterX() / 1000.0;
}
} // namespace QgsWms

View File

@ -47,6 +47,8 @@ class QgsSymbol;
class QgsSymbol;
class QgsAccessControl;
class QgsDxfExport;
class QgsLayerTreeModel;
class QgsLayerTree;
class QColor;
class QFile;
@ -88,19 +90,17 @@ namespace QgsWms
of the image object*/
QImage *getLegendGraphics();
typedef QSet<QgsSymbol *> SymbolSet;
typedef QSet<QString> SymbolSet;
typedef QHash<QgsVectorLayer *, SymbolSet> HitTest;
/** Returns the map as an image (or a null pointer in case of error). The caller takes ownership
of the image object). If an instance to existing hit test structure is passed, instead of rendering
it will fill the structure with symbols that would be used for rendering */
QImage *getMap( HitTest *hitTest = nullptr );
QImage *getMapOld( HitTest *hitTest = nullptr );
/** Identical to getMap( HitTest* hitTest ) and updates the map settings actually used.
\since QGIS 3.0 */
QImage *getMap( QgsMapSettings &mapSettings, HitTest *hitTest = nullptr );
QImage *getMapOld( QgsMapSettings &mapSettings, HitTest *hitTest = nullptr );
/** Returns the map as DXF data
\param options: extracted from the FORMAT_OPTIONS parameter
@ -173,6 +173,12 @@ namespace QgsWms
// Check layer read permissions
void checkLayerReadPermissions( QgsMapLayer *layer ) const;
// Build a layer tree model for legend
QgsLayerTreeModel *buildLegendTreeModel( const QList<QgsMapLayer *> &layers, double scaleDenominator, QgsLayerTree &rootGroup );
// Returns default dots per mm
qreal dotsPerMm() const;
/** Initializes WMS layers and configures rendering.
* \param layersList out: list with WMS layer names
* \param stylesList out: list with WMS style names
@ -236,10 +242,6 @@ namespace QgsWms
//! Record which symbols within one layer would be rendered with the given renderer context
void runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, QgsRenderContext &context ) const;
//! Read legend parameter from the request or from the first print composer in the project
void legendParameters( double &boxSpace, double &layerSpace, double &layerTitleSpace,
double &symbolSpace, double &iconLabelSpace, double &symbolWidth, double &symbolHeight, QFont &layerFont, QFont &itemFont, QColor &layerFontColor, QColor &itemFontColor );
/** Apply filter (subset) strings from the request to the layers. Example: '&FILTER=<layer1>:"AND property > 100",<layer2>:"AND bla = 'hallo!'" '
* \param layerList list of layer IDs to filter
* \param originalFilters hash of layer ID to original filter string
@ -313,10 +315,6 @@ namespace QgsWms
bool mOwnsConfigParser; //delete config parser after request (e.g. sent SLD)
// specify if layer or rule item labels should be drawn in the legend graphic with GetLegendGraphics
bool mDrawLegendLayerLabel;
bool mDrawLegendItemLabel;
//! Map containing the WMS parameters
QgsWmsConfigParser *mConfigParser = nullptr;

View File

@ -39,7 +39,7 @@ import email
from io import StringIO
from qgis.server import QgsServer, QgsServerRequest, QgsBufferServerRequest, QgsBufferServerResponse
from qgis.core import QgsRenderChecker, QgsApplication
from qgis.core import QgsRenderChecker, QgsApplication, QgsFontUtils
from qgis.testing import unittest
from qgis.PyQt.QtCore import QSize
from utilities import unitTestDataPath
@ -94,6 +94,9 @@ class QgsServerTestBase(unittest.TestCase):
def setUp(self):
"""Create the server instance"""
self.fontFamily = QgsFontUtils.standardTestFontFamily()
QgsFontUtils.loadStandardTestFonts(['All'])
self.testdata_path = unitTestDataPath('qgis_server') + '/'
d = unitTestDataPath('qgis_server_accesscontrol') + '/'

View File

@ -1026,8 +1026,80 @@ class TestQgsServerWMS(QgsServerTestBase):
self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
def test_getLegendGraphics_invalid_parameters(self):
"""Test that does return an exception"""
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
"SERVICE": "WMS",
"VERSION": "1.1.1",
"REQUEST": "GetLegendGraphic",
"LAYER": "Country,Hello,db_point",
"LAYERTITLE": "FALSE",
"FORMAT": "image/png",
"HEIGHT": "500",
"WIDTH": "500",
"RULE": "1",
"BBOX": "-151.7,-38.9,51.0,78.0",
"CRS": "EPSG:4326"
}.items())])
r, h = self._result(self._execute_request(qs))
err = b"BBOX parameter cannot be combined with RULE" in r
self.assertTrue(err)
def test_wms_GetLegendGraphic_LayerSpace(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
"SERVICE": "WMS",
"VERSION": "1.1.1",
"REQUEST": "GetLegendGraphic",
"LAYER": "Country,Hello",
"FORMAT": "image/png",
# "HEIGHT": "500",
# "WIDTH": "500",
"LAYERSPACE": "50.0",
"LAYERFONTBOLD": "TRUE",
"LAYERFONTSIZE": "30",
"ITEMFONTBOLD": "TRUE",
"ITEMFONTSIZE": "20",
"LAYERFONTFAMILY": self.fontFamily,
"ITEMFONTFAMILY": self.fontFamily,
"LAYERTITLE": "TRUE",
"CRS": "EPSG:3857"
}.items())])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerSpace")
def test_wms_GetLegendGraphic_ShowFeatureCount(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
"SERVICE": "WMS",
"VERSION": "1.1.1",
"REQUEST": "GetLegendGraphic",
"LAYER": "Country,Hello",
"FORMAT": "image/png",
# "HEIGHT": "500",
# "WIDTH": "500",
"LAYERTITLE": "TRUE",
"LAYERFONTBOLD": "TRUE",
"LAYERFONTSIZE": "30",
"LAYERFONTFAMILY": self.fontFamily,
"ITEMFONTFAMILY": self.fontFamily,
"ITEMFONTBOLD": "TRUE",
"ITEMFONTSIZE": "20",
"SHOWFEATURECOUNT": "TRUE",
"CRS": "EPSG:3857"
}.items())])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1))
def test_getLegendGraphics_layertitle(self):
"""Test that does not return an exception but an image"""
print("TEST FONT FAMILY: ", self.fontFamily)
parms = {
'MAP': self.testdata_path + "test_project.qgs",
'SERVICE': 'WMS',
@ -1037,6 +1109,12 @@ class TestQgsServerWMS(QgsServerTestBase):
# 'WIDTH': '20', # optional
# 'HEIGHT': '20', # optional
'LAYER': u'testlayer%20èé',
'LAYERFONTBOLD': 'TRUE',
'LAYERFONTSIZE': '30',
'ITEMFONTBOLD': 'TRUE',
'LAYERFONTFAMILY': self.fontFamily,
'ITEMFONTFAMILY': self.fontFamily,
'ITEMFONTSIZE': '20',
'LAYERTITLE': 'TRUE',
}
qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
@ -1058,6 +1136,78 @@ class TestQgsServerWMS(QgsServerTestBase):
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15))
def test_getLegendGraphics_rulelabel(self):
"""Test that does not return an exception but an image"""
parms = {
'MAP': self.testdata_path + "test_project.qgs",
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetLegendGraphic',
'FORMAT': 'image/png',
'LAYER': u'testlayer%20èé',
'LAYERFONTBOLD': 'TRUE',
'LAYERFONTSIZE': '30',
'LAYERFONTFAMILY': self.fontFamily,
'ITEMFONTFAMILY': self.fontFamily,
'ITEMFONTBOLD': 'TRUE',
'ITEMFONTSIZE': '20',
'RULELABEL': 'TRUE',
}
qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_test", 250, QSize(15, 15))
parms = {
'MAP': self.testdata_path + "test_project.qgs",
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetLegendGraphic',
'FORMAT': 'image/png',
'LAYER': u'testlayer%20èé',
'LAYERFONTBOLD': 'TRUE',
'LAYERFONTSIZE': '30',
'ITEMFONTBOLD': 'TRUE',
'ITEMFONTSIZE': '20',
'LAYERFONTFAMILY': self.fontFamily,
'ITEMFONTFAMILY': self.fontFamily,
'RULELABEL': 'FALSE',
}
qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15))
def test_getLegendGraphics_rule(self):
"""Test that does not return an exception but an image"""
parms = {
'MAP': self.testdata_path + "test_project_legend_rule.qgs",
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetLegendGraphic',
'FORMAT': 'image/png',
'LAYER': u'testlayer%20èé',
'WIDTH': '20',
'HEIGHT': '20',
'RULE': 'rule0',
}
qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule0", 250, QSize(15, 15))
parms = {
'MAP': self.testdata_path + "test_project_legend_rule.qgs",
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetLegendGraphic',
'FORMAT': 'image/png',
'LAYER': u'testlayer%20èé',
'WIDTH': '20',
'HEIGHT': '20',
'RULE': 'rule1',
}
qs = '?' + '&'.join([u"%s=%s" % (k, v) for k, v in parms.items()])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule1", 250, QSize(15, 15))
def test_wms_GetLegendGraphic_Basic(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
@ -1201,6 +1351,54 @@ class TestQgsServerWMS(QgsServerTestBase):
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_SymbolSize")
def test_wms_GetLegendGraphic_LayerFont(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
"SERVICE": "WMS",
"VERSION": "1.1.1",
"REQUEST": "GetLegendGraphic",
"LAYER": "Country,Hello",
"LAYERTITLE": "TRUE",
"LAYERFONTBOLD": "TRUE",
"LAYERFONTITALIC": "TRUE",
"LAYERFONTSIZE": "30",
"ITEMFONTBOLD": "TRUE",
"ITEMFONTSIZE": "20",
"LAYERFONTFAMILY": self.fontFamily,
"ITEMFONTFAMILY": self.fontFamily,
"FORMAT": "image/png",
"HEIGHT": "500",
"WIDTH": "500",
"CRS": "EPSG:3857"
}.items())])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerFont", max_size_diff=QSize(1, 1))
def test_wms_GetLegendGraphic_ItemFont(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),
"SERVICE": "WMS",
"VERSION": "1.1.1",
"REQUEST": "GetLegendGraphic",
"LAYER": "Country,Hello",
"LAYERTITLE": "TRUE",
"LAYERFONTBOLD": "TRUE",
"LAYERFONTSIZE": "30",
"ITEMFONTBOLD": "TRUE",
"ITEMFONTITALIC": "TRUE",
"ITEMFONTSIZE": "20",
"LAYERFONTFAMILY": self.fontFamily,
"ITEMFONTFAMILY": self.fontFamily,
"FORMAT": "image/png",
"HEIGHT": "500",
"WIDTH": "500",
"CRS": "EPSG:3857"
}.items())])
r, h = self._result(self._execute_request(qs))
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ItemFont", max_size_diff=QSize(1, 1))
def test_wms_GetLegendGraphic_BBox(self):
qs = "?" + "&".join(["%s=%s" % i for i in list({
"MAP": urllib.parse.quote(self.projectPath),

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 259 B

View File

@ -0,0 +1,445 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis projectname="QGIS Test Project" version="2.99.0-Master">
<title>QGIS Test Project</title>
<autotransaction active="0"/>
<evaluateDefaultValues active="0"/>
<layer-tree-group>
<customproperties/>
<layer-tree-layer expanded="1" providerKey="ogr" checked="Qt::Checked" source="/home/blottiere/devel/packages/QGIS_pbl_getlegendgraphic/tests/testdata/qgis_server/testlayer.shp" id="testlayer20150528120452665" name="testlayer èé">
<customproperties/>
</layer-tree-layer>
<custom-order enabled="0">
<item>testlayer20150528120452665</item>
</custom-order>
</layer-tree-group>
<snapping-settings type="1" mode="1" unit="2" intersection-snapping="0" tolerance="0" enabled="0">
<individual-layer-settings/>
</snapping-settings>
<relations/>
<mapcanvas annotationsVisible="1" name="theMapCanvas">
<units>degrees</units>
<extent>
<xmin>8.20202108826836884</xmin>
<ymin>44.9009031607650968</ymin>
<xmax>8.20606418507941449</xmax>
<ymax>44.90195628381741244</ymax>
</extent>
<rotation>0</rotation>
<destinationsrs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</destinationsrs>
<rendermaptile>0</rendermaptile>
<layer_coordinate_transform_info>
<layer_coordinate_transform srcAuthId="EPSG:4326" layerid="testlayer20150528120452665" destDatumTransform="-1" destAuthId="EPSG:4326" srcDatumTransform="-1"/>
</layer_coordinate_transform_info>
</mapcanvas>
<legend updateDrawingOrder="true">
<legendlayer showFeatureCount="0" open="true" checked="Qt::Checked" drawingOrder="-1" name="testlayer èé">
<filegroup open="true" hidden="false">
<legendlayerfile layerid="testlayer20150528120452665" visible="1" isInOverview="0"/>
</filegroup>
</legendlayer>
</legend>
<mapViewDocks/>
<projectlayers>
<maplayer simplifyDrawingTol="1" type="vector" readOnly="0" simplifyDrawingHints="0" simplifyMaxScale="1" autoRefreshEnabled="0" autoRefreshTime="0" simplifyAlgorithm="0" hasScaleBasedVisibilityFlag="0" geometry="Point" simplifyLocal="1" minimumScale="0" maximumScale="1e+8">
<extent>
<xmin>8.20345930703634352</xmin>
<ymin>44.90139483904469131</ymin>
<xmax>8.20354699399348775</xmax>
<ymax>44.90148252600183554</ymax>
</extent>
<id>testlayer20150528120452665</id>
<datasource>./testlayer.shp</datasource>
<title>A test vector layer</title>
<abstract>A test vector layer with unicode òà</abstract>
<keywordList>
<value></value>
</keywordList>
<layername>testlayer èé</layername>
<srs>
<spatialrefsys>
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
<srsid>3452</srsid>
<srid>4326</srid>
<authid>EPSG:4326</authid>
<description>WGS 84</description>
<projectionacronym>longlat</projectionacronym>
<ellipsoidacronym>WGS84</ellipsoidacronym>
<geographicflag>true</geographicflag>
</spatialrefsys>
</srs>
<provider encoding="UTF-8">ogr</provider>
<vectorjoins/>
<layerDependencies/>
<dataDependencies/>
<expressionfields/>
<map-layer-style-manager current="">
<map-layer-style name=""/>
</map-layer-style-manager>
<renderer-v2 type="RuleRenderer" forceraster="0" symbollevels="0" enableorderby="0">
<rules key="{9968c7d6-186c-4e91-80fd-b3c1e5541edf}">
<rule symbol="0" label="rule0" key="{42912a46-cc74-4e39-a409-3a5ad6b9f59e}"/>
<rule symbol="1" label="rule1" key="{c4d8fca3-46ba-4eeb-92e1-4efd5a19da74}"/>
</rules>
<symbols>
<symbol alpha="1" clip_to_extent="1" type="marker" name="0">
<layer pass="0" class="SimpleMarker" locked="0" enabled="1">
<prop k="angle" v="0"/>
<prop k="color" v="102,164,67,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="area"/>
<prop k="size" v="2"/>
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
<effect type="effectStack" enabled="0">
<effect type="drawSource">
<prop k="blend_mode" v="0"/>
<prop k="draw_mode" v="2"/>
<prop k="enabled" v="1"/>
<prop k="transparency" v="0"/>
</effect>
</effect>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol alpha="1" clip_to_extent="1" type="marker" name="1">
<layer pass="0" class="SimpleMarker" locked="0" enabled="1">
<prop k="angle" v="0"/>
<prop k="color" v="159,114,97,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="star"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="4"/>
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</symbols>
<effect type="effectStack" enabled="0">
<effect type="drawSource">
<prop k="blend_mode" v="0"/>
<prop k="draw_mode" v="2"/>
<prop k="enabled" v="1"/>
<prop k="transparency" v="0"/>
</effect>
</effect>
</renderer-v2>
<customproperties>
<property value="0" key="embeddedWidgets/count"/>
<property key="variableNames"/>
<property key="variableValues"/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerTransparency>0</layerTransparency>
<SingleCategoryDiagramRenderer diagramType="Pie" attributeLegend="1" sizeLegend="0">
<DiagramCategory penWidth="0" angleOffset="1440" maxScaleDenominator="1e+8" scaleDependency="Area" sizeScale="0,0,0,0,0,0" width="15" transparency="0" backgroundColor="#ffffff" minScaleDenominator="0" diagramOrientation="Up" barWidth="5" backgroundAlpha="255" scaleBasedVisibility="0" labelPlacementMethod="XHeight" penAlpha="255" lineSizeScale="0,0,0,0,0,0" sizeType="MM" minimumSize="0" height="15" enabled="0" lineSizeType="MM" penColor="#000000">
<fontProperties style="" description="Ubuntu,9,-1,5,50,0,0,0,0,0"/>
<attribute label="" color="#000000" field=""/>
</DiagramCategory>
<symbol alpha="1" clip_to_extent="1" type="marker" name="sizeSymbol">
<layer pass="0" class="SimpleMarker" locked="0" enabled="1">
<prop k="angle" v="0"/>
<prop k="color" v="255,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="2"/>
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option name="properties"/>
<Option value="collection" type="QString" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</SingleCategoryDiagramRenderer>
<DiagramLayerSettings priority="0" obstacle="0" showAll="1" dist="0" placement="0" linePlacementFlags="2" zIndex="0">
<properties>
<Option type="Map">
<Option value="" type="QString" name="name"/>
<Option type="Map" name="properties">
<Option type="Map" name="show">
<Option value="true" type="bool" name="active"/>
<Option value="id" type="QString" name="field"/>
<Option value="2" type="int" name="type"/>
</Option>
</Option>
<Option value="collection" type="QString" name="type"/>
</Option>
</properties>
</DiagramLayerSettings>
<fieldConfiguration>
<field name="id">
<editWidget type="TextEdit">
<config>
<Option type="Map">
<Option value="0" type="QString" name="IsMultiline"/>
<Option value="0" type="QString" name="UseHtml"/>
</Option>
</config>
</editWidget>
</field>
<field name="name">
<editWidget type="TextEdit">
<config>
<Option type="Map">
<Option value="0" type="QString" name="IsMultiline"/>
<Option value="0" type="QString" name="UseHtml"/>
</Option>
</config>
</editWidget>
</field>
<field name="utf8nameè">
<editWidget type="TextEdit">
<config>
<Option type="Map">
<Option value="0" type="QString" name="IsMultiline"/>
<Option value="0" type="QString" name="UseHtml"/>
</Option>
</config>
</editWidget>
</field>
</fieldConfiguration>
<aliases>
<alias index="0" field="id" name=""/>
<alias index="1" field="name" name=""/>
<alias index="2" field="utf8nameè" name=""/>
</aliases>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<defaults>
<default field="id" expression=""/>
<default field="name" expression=""/>
<default field="utf8nameè" expression=""/>
</defaults>
<constraints>
<constraint notnull_strength="0" exp_strength="0" field="id" unique_strength="0" constraints="0"/>
<constraint notnull_strength="0" exp_strength="0" field="name" unique_strength="0" constraints="0"/>
<constraint notnull_strength="0" exp_strength="0" field="utf8nameè" unique_strength="0" constraints="0"/>
</constraints>
<constraintExpressions>
<constraint desc="" exp="" field="id"/>
<constraint desc="" exp="" field="name"/>
<constraint desc="" exp="" field="utf8nameè"/>
</constraintExpressions>
<attributeactions>
<defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
</attributeactions>
<attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="0">
<columns>
<column type="field" hidden="0" name="id" width="-1"/>
<column type="field" hidden="0" name="name" width="-1"/>
<column type="field" hidden="0" name="utf8nameè" width="-1"/>
<column type="actions" hidden="1" width="-1"/>
</columns>
</attributetableconfig>
<editform>../../../../../..</editform>
<editforminit/>
<editforminitcodesource>0</editforminitcodesource>
<editforminitfilepath>../../../../../..</editforminitfilepath>
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
"""
QGIS forms can have a Python function that is called when the form is
opened.
Use this function to add extra logic to your forms.
Enter the name of the function in the "Python Init function"
field.
An example follows:
"""
from qgis.PyQt.QtWidgets import QWidget
def my_form_open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget, "MyLineEdit")
]]></editforminitcode>
<featformsuppress>0</featformsuppress>
<editorlayout>generatedlayout</editorlayout>
<widgets/>
<conditionalstyles>
<rowstyles/>
<fieldstyles/>
</conditionalstyles>
<expressionfields/>
<previewExpression>name</previewExpression>
<mapTip></mapTip>
</maplayer>
</projectlayers>
<layerorder>
<layer id="testlayer20150528120452665"/>
</layerorder>
<properties>
<WMSRestrictedLayers type="QStringList"/>
<Variables>
<variableNames type="QStringList"/>
<variableValues type="QStringList"/>
</Variables>
<WMSServiceTitle type="QString">QGIS TestProject</WMSServiceTitle>
<WMSPrecision type="QString">4</WMSPrecision>
<WFSLayersPrecision>
<testlayer20150528120452665 type="int">8</testlayer20150528120452665>
</WFSLayersPrecision>
<Measurement>
<DistanceUnits type="QString">meters</DistanceUnits>
<AreaUnits type="QString">m2</AreaUnits>
</Measurement>
<PositionPrecision>
<Automatic type="bool">true</Automatic>
<DegreeFormat type="QString">D</DegreeFormat>
<DecimalPlaces type="int">2</DecimalPlaces>
</PositionPrecision>
<DefaultStyles>
<AlphaInt type="int">255</AlphaInt>
<Marker type="QString"></Marker>
<Fill type="QString"></Fill>
<ColorRamp type="QString"></ColorRamp>
<Line type="QString"></Line>
<RandomColors type="bool">true</RandomColors>
</DefaultStyles>
<SpatialRefSys>
<ProjectCRSID type="int">3452</ProjectCRSID>
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
<ProjectCRSProj4String type="QString">+proj=longlat +datum=WGS84 +no_defs</ProjectCRSProj4String>
<ProjectCrs type="QString">EPSG:4326</ProjectCrs>
</SpatialRefSys>
<WMSOnlineResource type="QString"></WMSOnlineResource>
<WMSContactPosition type="QString"></WMSContactPosition>
<WMSContactOrganization type="QString">QGIS dev team</WMSContactOrganization>
<WMSKeywordList type="QStringList">
<value></value>
</WMSKeywordList>
<Measure>
<Ellipsoid type="QString">WGS84</Ellipsoid>
</Measure>
<WMSAddWktGeometry type="bool">true</WMSAddWktGeometry>
<WMSContactMail type="QString">elpaso@itopen.it</WMSContactMail>
<WMSContactPhone type="QString"></WMSContactPhone>
<Gui>
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
</Gui>
<WMSImageQuality type="int">90</WMSImageQuality>
<WCSLayers type="QStringList"/>
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
<WMSServiceAbstract type="QString">Some UTF8 text èòù</WMSServiceAbstract>
<WFSLayers type="QStringList">
<value>testlayer20150528120452665</value>
</WFSLayers>
<Identify>
<disabledLayers type="QStringList"/>
</Identify>
<WMSExtent type="QStringList">
<value>8.20315414376310059</value>
<value>44.901236559338642</value>
<value>8.204164917965862</value>
<value>44.90159838674664172</value>
</WMSExtent>
<WFSTLayers>
<Insert type="QStringList">
<value>testlayer20150528120452665</value>
</Insert>
<Update type="QStringList">
<value>testlayer20150528120452665</value>
</Update>
<Delete type="QStringList">
<value>testlayer20150528120452665</value>
</Delete>
</WFSTLayers>
<WCSUrl type="QString"></WCSUrl>
<Digitizing>
<DefaultSnapType type="QString">off</DefaultSnapType>
<LayerSnapToList type="QStringList"/>
<AvoidIntersectionsList type="QStringList"/>
<DefaultSnapTolerance type="double">0</DefaultSnapTolerance>
<DefaultSnapToleranceUnit type="int">2</DefaultSnapToleranceUnit>
<LayerSnappingList type="QStringList"/>
<LayerSnappingToleranceUnitList type="QStringList"/>
<LayerSnappingToleranceList type="QStringList"/>
<SnappingMode type="QString">current_layer</SnappingMode>
<LayerSnappingEnabledList type="QStringList"/>
</Digitizing>
<Macros>
<pythonCode type="QString"></pythonCode>
</Macros>
<WMSRestrictedComposers type="QStringList"/>
<Legend>
<filterByMap type="bool">false</filterByMap>
</Legend>
<Paths>
<Absolute type="bool">false</Absolute>
</Paths>
<WMSContactPerson type="QString">Alessandro Pasotti</WMSContactPerson>
<WMSUrl type="QString"></WMSUrl>
<WMSUseLayerIDs type="bool">false</WMSUseLayerIDs>
<WMSFees type="QString">conditions unknown</WMSFees>
<WMSServiceCapabilities type="bool">true</WMSServiceCapabilities>
<WFSUrl type="QString"></WFSUrl>
</properties>
<visibility-presets/>
<Annotations/>
<Layouts/>
</qgis>