diff --git a/src/server/services/wms/qgslayerrestorer.cpp b/src/server/services/wms/qgslayerrestorer.cpp index 4e28fd62b94..78f9585121d 100644 --- a/src/server/services/wms/qgslayerrestorer.cpp +++ b/src/server/services/wms/qgslayerrestorer.cpp @@ -21,24 +21,15 @@ #include "qgsrasterrenderer.h" #include "qgsmaplayerstylemanager.h" -const QString DEFAULT_NAMED_STYLE = "server_default_style"; - QgsLayerRestorer::QgsLayerRestorer( const QList &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; diff --git a/src/server/services/wms/qgslayerrestorer.h b/src/server/services/wms/qgslayerrestorer.h index 2fb738c8049..199ab05a45a 100644 --- a/src/server/services/wms/qgslayerrestorer.h +++ b/src/server/services/wms/qgslayerrestorer.h @@ -30,6 +30,7 @@ class QgsLayerRestorer { struct QgsLayerSettings { + QString name; double mOpacity; QString mNamedStyle; QDomDocument mSldStyle; diff --git a/src/server/services/wms/qgswmsparameters.cpp b/src/server/services/wms/qgswmsparameters.cpp index 06e28e7b14a..90549ea7844 100644 --- a/src/server/services/wms/qgswmsparameters.cpp +++ b/src/server/services/wms/qgswmsparameters.cpp @@ -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(); + + 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, ';' ); diff --git a/src/server/services/wms/qgswmsparameters.h b/src/server/services/wms/qgswmsparameters.h index 40704709bfc..57bb800f4fa 100644 --- a/src/server/services/wms/qgswmsparameters.h +++ b/src/server/services/wms/qgswmsparameters.h @@ -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 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 ¶meter ); + double toDouble( ParameterName name ) const; + bool toBool( ParameterName name ) const; + int toInt( ParameterName name ) const; QStringList toStringList( ParameterName name, char delimiter = ',' ) const; QList toIntList( QStringList l, ParameterName name ) const; QList toFloatList( QStringList l, ParameterName name ) const; diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index 8486d03b76b..f6fd594edcf 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -67,6 +67,7 @@ #include "qgspallabeling.h" #include "qgslayerrestorer.h" #include "qgsdxfexport.h" +#include "qgssymbollayerutils.h" #include #include @@ -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::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 restorer; + restorer.reset( new QgsLayerRestorer( mNicknameLayers.values() ) ); - QString rule; - int ruleSymbolWidth = 0, ruleSymbolHeight = 0; - QMap::const_iterator ruleIt = mParameters.constFind( QStringLiteral( "RULE" ) ); - if ( ruleIt != mParameters.constEnd() ) - { - rule = ruleIt.value(); + QList layers; + QList params = mWmsParameters.layersParameters(); - QMap::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::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 layerNameMap; - // Create tree layer node for each layer - Q_FOREACH ( const QString &layerId, layerIds ) + std::unique_ptr legendModel; + legendModel.reset( buildLegendTreeModel( layers, scaleDenominator, rootGroup ) ); + + // rendering step + qreal dpmm = dotsPerMm(); + std::unique_ptr image; + std::unique_ptr 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( nodeLayer->layer() ); - if ( !vl || !vl->renderer() ) - continue; - - const SymbolSet &usedSymbols = hitTest[vl]; - QList 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 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( QgsProject::instance()->mapLayer( layerID ) ); + QgsVectorLayer *vl = qobject_cast( 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::const_iterator boxSpaceIt = mParameters.constFind( QStringLiteral( "BOXSPACE" ) ); - boxSpace = ( boxSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendBoxSpace() : boxSpaceIt.value().toDouble(); - QMap::const_iterator layerSpaceIt = mParameters.constFind( QStringLiteral( "LAYERSPACE" ) ); - layerSpace = ( layerSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendLayerSpace() : layerSpaceIt.value().toDouble(); - QMap::const_iterator layerTitleSpaceIt = mParameters.constFind( QStringLiteral( "LAYERTITLESPACE" ) ); - layerTitleSpace = ( layerTitleSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendLayerTitleSpace() : layerTitleSpaceIt.value().toDouble(); - QMap::const_iterator symbolSpaceIt = mParameters.constFind( QStringLiteral( "SYMBOLSPACE" ) ); - symbolSpace = ( symbolSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolSpace() : symbolSpaceIt.value().toDouble(); - QMap::const_iterator iconLabelSpaceIt = mParameters.constFind( QStringLiteral( "ICONLABELSPACE" ) ); - iconLabelSpace = ( iconLabelSpaceIt == mParameters.constEnd() ) ? mConfigParser->legendIconLabelSpace() : iconLabelSpaceIt.value().toDouble(); - QMap::const_iterator symbolWidthIt = mParameters.constFind( QStringLiteral( "SYMBOLWIDTH" ) ); - symbolWidth = ( symbolWidthIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolWidth() : symbolWidthIt.value().toDouble(); - QMap::const_iterator symbolHeightIt = mParameters.constFind( QStringLiteral( "SYMBOLHEIGHT" ) ); - symbolHeight = ( symbolHeightIt == mParameters.constEnd() ) ? mConfigParser->legendSymbolHeight() : symbolHeightIt.value().toDouble(); - - //font properties - layerFont = mConfigParser->legendLayerFont(); - QMap::const_iterator layerFontFamilyIt = mParameters.constFind( QStringLiteral( "LAYERFONTFAMILY" ) ); - if ( layerFontFamilyIt != mParameters.constEnd() ) - { - layerFont.setFamily( layerFontFamilyIt.value() ); - } - QMap::const_iterator layerFontBoldIt = mParameters.constFind( QStringLiteral( "LAYERFONTBOLD" ) ); - if ( layerFontBoldIt != mParameters.constEnd() ) - { - layerFont.setBold( layerFontBoldIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 ); - } - QMap::const_iterator layerFontItalicIt = mParameters.constFind( QStringLiteral( "LAYERFONTITALIC" ) ); - if ( layerFontItalicIt != mParameters.constEnd() ) - { - layerFont.setItalic( layerFontItalicIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 ); - } - QMap::const_iterator layerFontSizeIt = mParameters.constFind( QStringLiteral( "LAYERFONTSIZE" ) ); - layerFont.setPointSizeF( layerFontSizeIt != mParameters.constEnd() ? layerFontSizeIt.value().toDouble() : layerFont.pointSizeF() ); - QMap::const_iterator layerFontColorIt = mParameters.constFind( QStringLiteral( "LAYERFONTCOLOR" ) ); - if ( layerFontColorIt != mParameters.constEnd() ) - { - layerFontColor.setNamedColor( layerFontColorIt.value() ); - } - else - { - layerFontColor = QColor( 0, 0, 0 ); - } - QMap::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::const_iterator itemFontFamilyIt = mParameters.constFind( QStringLiteral( "ITEMFONTFAMILY" ) ); - if ( itemFontFamilyIt != mParameters.constEnd() ) - { - itemFont.setFamily( itemFontFamilyIt.value() ); - } - QMap::const_iterator itemFontBoldIt = mParameters.constFind( QStringLiteral( "ITEMFONTBOLD" ) ); - if ( itemFontBoldIt != mParameters.constEnd() ) - { - itemFont.setBold( itemFontBoldIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 ); - } - QMap::const_iterator itemFontItalicIt = mParameters.constFind( QStringLiteral( "ITEMFONTITALIC" ) ); - if ( itemFontItalicIt != mParameters.constEnd() ) - { - itemFont.setItalic( itemFontItalicIt.value().compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) == 0 ); - } - QMap::const_iterator itemFontSizeIt = mParameters.constFind( QStringLiteral( "ITEMFONTSIZE" ) ); - itemFont.setPointSizeF( itemFontSizeIt != mParameters.constEnd() ? itemFontSizeIt.value().toDouble() : itemFont.pointSizeF() ); - QMap::const_iterator itemFontColorIt = mParameters.constFind( QStringLiteral( "ITEMFONTCOLOR" ) ); - if ( itemFontColorIt != mParameters.constEnd() ) - { - itemFontColor.setNamedColor( itemFontColorIt.value() ); - } - else - { - itemFontColor = QColor( 0, 0, 0 ); - } - QMap::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 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 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 &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( nodeLayer->layer() ); + if ( !vl || !vl->renderer() ) + continue; + + const SymbolSet &usedSymbols = hitTest[vl]; + QList 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 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 tmpImage( createImage( 1, 1, false ) ); + return tmpImage->dotsPerMeterX() / 1000.0; + } } // namespace QgsWms diff --git a/src/server/services/wms/qgswmsrenderer.h b/src/server/services/wms/qgswmsrenderer.h index 274ba6454fc..e3f01764017 100644 --- a/src/server/services/wms/qgswmsrenderer.h +++ b/src/server/services/wms/qgswmsrenderer.h @@ -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 SymbolSet; + typedef QSet SymbolSet; typedef QHash 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 &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=:"AND property > 100",:"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; diff --git a/tests/src/python/test_qgsserver.py b/tests/src/python/test_qgsserver.py index 86175be2aca..5ee167951d6 100644 --- a/tests/src/python/test_qgsserver.py +++ b/tests/src/python/test_qgsserver.py @@ -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') + '/' diff --git a/tests/src/python/test_qgsserver_wms.py b/tests/src/python/test_qgsserver_wms.py index 051f5976fe9..7bfea25f73b 100644 --- a/tests/src/python/test_qgsserver_wms.py +++ b/tests/src/python/test_qgsserver_wms.py @@ -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), diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont.png new file mode 100644 index 00000000000..c78799a44a7 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont_mask.png new file mode 100644 index 00000000000..2e725500de5 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ItemFont/WMS_GetLegendGraphic_ItemFont_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont.png new file mode 100644 index 00000000000..15e6532552a Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont_mask.png new file mode 100644 index 00000000000..cf3ce1d31f2 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerFont/WMS_GetLegendGraphic_LayerFont_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace.png new file mode 100644 index 00000000000..839d4faa238 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace_mask.png new file mode 100644 index 00000000000..4a231783883 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LayerSpace/WMS_GetLegendGraphic_LayerSpace_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount.png new file mode 100644 index 00000000000..7180ef7dda3 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount_mask.png new file mode 100644 index 00000000000..08fe0740a77 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ShowFeatureCount/WMS_GetLegendGraphic_ShowFeatureCount_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule0/WMS_GetLegendGraphic_rule0.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule0/WMS_GetLegendGraphic_rule0.png new file mode 100644 index 00000000000..61f94ee7a9b Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule0/WMS_GetLegendGraphic_rule0.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule1/WMS_GetLegendGraphic_rule1.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule1/WMS_GetLegendGraphic_rule1.png new file mode 100644 index 00000000000..766053a5a7c Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rule1/WMS_GetLegendGraphic_rule1.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false.png new file mode 100644 index 00000000000..55dce944e31 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false_mask.png new file mode 100644 index 00000000000..65a8f41e574 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_rulelabel_false/WMS_GetLegendGraphic_rulelabel_false_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test.png index 4e627b316b5..7deef243e6b 100644 Binary files a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test.png and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test_mask.png index 93818253838..2deb2a63696 100644 Binary files a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test_mask.png and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_test/WMS_GetLegendGraphic_test_mask.png differ diff --git a/tests/testdata/control_images/qgis_server_accesscontrol/WMS_GetLegendGraphic_Hello/WMS_GetLegendGraphic_Hello_mask.png b/tests/testdata/control_images/qgis_server_accesscontrol/WMS_GetLegendGraphic_Hello/WMS_GetLegendGraphic_Hello_mask.png index 0647ca6f530..1e31689f633 100644 Binary files a/tests/testdata/control_images/qgis_server_accesscontrol/WMS_GetLegendGraphic_Hello/WMS_GetLegendGraphic_Hello_mask.png and b/tests/testdata/control_images/qgis_server_accesscontrol/WMS_GetLegendGraphic_Hello/WMS_GetLegendGraphic_Hello_mask.png differ diff --git a/tests/testdata/qgis_server/test_project_legend_rule.qgs b/tests/testdata/qgis_server/test_project_legend_rule.qgs new file mode 100644 index 00000000000..0c3ecb0902f --- /dev/null +++ b/tests/testdata/qgis_server/test_project_legend_rule.qgs @@ -0,0 +1,445 @@ + + + QGIS Test Project + + + + + + + + + testlayer20150528120452665 + + + + + + + + degrees + + 8.20202108826836884 + 44.9009031607650968 + 8.20606418507941449 + 44.90195628381741244 + + 0 + + + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + WGS84 + true + + + 0 + + + + + + + + + + + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer20150528120452665 + ./testlayer.shp + A test vector layer + A test vector layer with unicode òà + + + + testlayer èé + + + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + WGS84 + true + + + ogr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../../../../../.. + + 0 + ../../../../../.. + + 0 + generatedlayout + + + + + + + name + + + + + + + + + + + + + QGIS TestProject + 4 + + 8 + + + meters + m2 + + + true + D + 2 + + + 255 + + + + + true + + + 3452 + 1 + +proj=longlat +datum=WGS84 +no_defs + EPSG:4326 + + + + QGIS dev team + + + + + WGS84 + + true + elpaso@itopen.it + + + 0 + 255 + 255 + 255 + 255 + 255 + 255 + + 90 + + None + Some UTF8 text èòù + + testlayer20150528120452665 + + + + + + 8.20315414376310059 + 44.901236559338642 + 8.204164917965862 + 44.90159838674664172 + + + + testlayer20150528120452665 + + + testlayer20150528120452665 + + + testlayer20150528120452665 + + + + + off + + + 0 + 2 + + + + current_layer + + + + + + + + false + + + false + + Alessandro Pasotti + + false + conditions unknown + true + + + + + +