Skip to content

Commit

Permalink
Merge pull request #50854 from elpaso/raster-maptips-2
Browse files Browse the repository at this point in the history
Raster maptips
  • Loading branch information
troopa81 committed Nov 14, 2022
2 parents 1373d2b + 4f0239c commit 91e5130
Show file tree
Hide file tree
Showing 24 changed files with 600 additions and 153 deletions.
Expand Up @@ -198,6 +198,16 @@ Sets the expression context variables which are available for expressions trigge
a map tool capture like add feature.

.. versionadded:: 3.0
%End

static QgsExpressionContextScope *mapLayerPositionScope( const QgsPointXY &position ) /Factory/;
%Docstring
Sets the expression context variables which are available for expressions triggered by moving the mouse over a feature
of the currently selected layer.

:param position: map coordinates of the current pointer position in the CRS of the layer which triggered the action.

.. versionadded:: 3.30
%End

static QgsExpressionContextScope *updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope = 0 );
Expand Down
38 changes: 38 additions & 0 deletions python/core/auto_generated/qgsmaplayer.sip.in
Expand Up @@ -1508,6 +1508,33 @@ Set placeholder image for legend. If the string is empty, a generated legend wil
.. versionadded:: 3.22
%End

QString mapTipTemplate() const;
%Docstring
The mapTip is a pretty, html representation for feature information.

It may also contain embedded expressions.

.. note::

this method was only available for vector layers since QGIS 3.0

.. versionadded:: 3.30
%End

void setMapTipTemplate( const QString &mapTipTemplate );
%Docstring
The mapTip is a pretty, html representation for feature information.

It may also contain embedded expressions.

.. note::

this method was only available for vector layers since QGIS 3.0

.. versionadded:: 3.30
%End


public slots:

void setMinimumScale( double scale );
Expand Down Expand Up @@ -1846,6 +1873,17 @@ Emitted when edited changes have been successfully written to the data provider.
Emitted when modifications has been done on layer

.. versionadded:: 3.22
%End

void mapTipTemplateChanged();
%Docstring
Emitted when the map tip template changes

.. note::

this method was only available for vector layers since QGIS 3.0

.. versionadded:: 3.30
%End

protected:
Expand Down
1 change: 0 additions & 1 deletion python/core/auto_generated/raster/qgsrasterlayer.sip.in
Expand Up @@ -467,7 +467,6 @@ Emitted when the layer's subset string has changed.
.. versionadded:: 3.12
%End


protected:
virtual bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );

Expand Down
25 changes: 0 additions & 25 deletions python/core/auto_generated/vector/qgsvectorlayer.sip.in
Expand Up @@ -2571,24 +2571,6 @@ This defines the appearance of the attribute table.
%Docstring
Sets the attribute table configuration object.
This defines the appearance of the attribute table.
%End

QString mapTipTemplate() const;
%Docstring
The mapTip is a pretty, html representation for feature information.

It may also contain embedded expressions.

.. versionadded:: 3.0
%End

void setMapTipTemplate( const QString &mapTipTemplate );
%Docstring
The mapTip is a pretty, html representation for feature information.

It may also contain embedded expressions.

.. versionadded:: 3.0
%End

virtual QgsExpressionContext createExpressionContext() const ${SIP_FINAL};
Expand Down Expand Up @@ -2986,13 +2968,6 @@ to this signal and update the element accordingly.
:param element: The XML element where you can add additional style information to.
:param doc: The XML document that you can use to create new XML nodes.
:param errorMessage: Write error messages into this string.
%End

void mapTipTemplateChanged();
%Docstring
Emitted when the map tip changes

.. versionadded:: 3.0
%End

void displayExpressionChanged();
Expand Down
15 changes: 15 additions & 0 deletions resources/function_help/json/map_to_html_dl
@@ -0,0 +1,15 @@
{
"name": "map_to_html_dl",
"type": "function",
"groups": ["Maps"],
"description": "Merge map elements into a HTML definition list string.",
"arguments": [{
"arg": "map",
"description": "the input map"
}],
"examples": [{
"expression": "map_to_html_dl(map('qgis','rocks'))",
"returns": "<dl><dt>qgis</dt><dd>rocks</dd></dl>"
}],
"tags": ["formatted", "map", "html"]
}
15 changes: 15 additions & 0 deletions resources/function_help/json/map_to_html_table
@@ -0,0 +1,15 @@
{
"name": "map_to_html_table",
"type": "function",
"groups": ["Maps"],
"description": "Merge map elements into a HTML table string.",
"arguments": [{
"arg": "map",
"description": "the input map"
}],
"examples": [{
"expression": "map_to_html_table(map('qgis','rocks'))",
"returns": "<table><thead><th>qgis</th></thead><tbody><tr><td>rocks</td></tr></tbody></table>"
}],
"tags": ["formatted", "map", "html"]
}
21 changes: 21 additions & 0 deletions resources/function_help/json/raster_attributes
@@ -0,0 +1,21 @@
{
"name": "raster_attributes",
"type": "function",
"groups": ["Rasters"],
"description": "Returns a map with the fields names as keys and the raster attribute table values as values from the attribute table entry that matches the given raster value.",
"arguments": [{
"arg": "layer",
"description": "the name or id of a raster layer"
}, {
"arg": "band",
"description": "the band number for the associated attribute table lookup."
}, {
"arg": "value",
"description": "raster value"
}],
"examples": [{
"expression": "raster_attributes('vegetation', 1, raster_value('vegetation', 1, make_point(1,1)))",
"returns": "{'class': 'Vegetated', 'subclass': 'Trees'}"
}],
"tags": ["provider", "point", "raster", "found", "attributes"]
}
14 changes: 3 additions & 11 deletions src/app/qgisapp.cpp
Expand Up @@ -14419,23 +14419,15 @@ void QgisApp::removeMapToolMessage()
void QgisApp::showMapTip()
{
// Only show maptips if the mouse is still over the map canvas when timer is triggered
if ( mMapCanvas->underMouse() )
if ( mMapTipsVisible && mMapCanvas->underMouse() )
{
QPoint myPointerPos = mMapCanvas->mouseLastXY();

// Make sure there is an active layer before proceeding
QgsMapLayer *mypLayer = mMapCanvas->currentLayer();
if ( mypLayer )
if ( mypLayer && !mypLayer->mapTipTemplate().isEmpty() )
{
// only process vector layers
if ( mypLayer->type() == QgsMapLayerType::VectorLayer )
{
// Show the maptip if the maptips button is depressed
if ( mMapTipsVisible )
{
mpMaptip->showMapTip( mypLayer, mLastMapPosition, myPointerPos, mMapCanvas );
}
}
mpMaptip->showMapTip( mypLayer, mLastMapPosition, myPointerPos, mMapCanvas );
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/core/expression/qgsexpression.cpp
Expand Up @@ -826,6 +826,7 @@ void QgsExpression::initVariableHelp()

// map canvas item variables
sVariableHelpTexts()->insert( QStringLiteral( "canvas_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the project's geographical coordinates." ) );
sVariableHelpTexts()->insert( QStringLiteral( "layer_cursor_point" ), QCoreApplication::translate( "variable_help", "Last cursor position on the canvas in the current layers's geographical coordinates." ) );

// legend canvas item variables
sVariableHelpTexts()->insert( QStringLiteral( "legend_title" ), QCoreApplication::translate( "variable_help", "Title of the legend." ) );
Expand Down
7 changes: 7 additions & 0 deletions src/core/expression/qgsexpressioncontextutils.cpp
Expand Up @@ -535,6 +535,13 @@ QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const
return scope;
}

QgsExpressionContextScope *QgsExpressionContextUtils::mapLayerPositionScope( const QgsPointXY &position )
{
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Layer Position" ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_cursor_point" ), QVariant::fromValue( QgsGeometry::fromPointXY( position ) ) ) );
return scope;
}

QgsExpressionContextScope *QgsExpressionContextUtils::updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope )
{
if ( !symbolScope )
Expand Down
9 changes: 9 additions & 0 deletions src/core/expression/qgsexpressioncontextutils.h
Expand Up @@ -188,6 +188,15 @@ class CORE_EXPORT QgsExpressionContextUtils
*/
static QgsExpressionContextScope *mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches ) SIP_FACTORY;

/**
* Sets the expression context variables which are available for expressions triggered by moving the mouse over a feature
* of the currently selected layer.
* \param position map coordinates of the current pointer position in the CRS of the layer which triggered the action.
*
* \since QGIS 3.30
*/
static QgsExpressionContextScope *mapLayerPositionScope( const QgsPointXY &position ) SIP_FACTORY;

/**
* Updates a symbol scope related to a QgsSymbol to an expression context.
* \param symbol symbol to extract properties from
Expand Down
127 changes: 127 additions & 0 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -1697,6 +1697,56 @@ static QVariant fcnRasterValue( const QVariantList &values, const QgsExpressionC
return std::isnan( value ) ? QVariant() : value;
}

static QVariant fcnRasterAttributes( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsRasterLayer *layer = QgsExpressionUtils::getRasterLayer( values.at( 0 ), parent );
if ( !layer || !layer->dataProvider() )
{
parent->setEvalErrorString( QObject::tr( "Function `raster_attributes` requires a valid raster layer." ) );
return QVariant();
}

const int bandNb = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
if ( bandNb < 1 || bandNb > layer->bandCount() )
{
parent->setEvalErrorString( QObject::tr( "Function `raster_attributes` requires a valid raster band number." ) );
return QVariant();
}

const double value = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
if ( std::isnan( value ) )
{
parent->setEvalErrorString( QObject::tr( "Function `raster_attributes` requires a valid raster value." ) );
return QVariant();
}

if ( ! layer->dataProvider()->attributeTable( bandNb ) )
{
return QVariant();
}

const QVariantList data = layer->dataProvider()->attributeTable( bandNb )->row( value );
if ( data.isEmpty() )
{
return QVariant();
}

QVariantMap result;
const QList<QgsRasterAttributeTable::Field> fields { layer->dataProvider()->attributeTable( bandNb )->fields() };
for ( int idx = 0; idx < static_cast<int>( fields.count( ) ) && idx < static_cast<int>( data.count() ); ++idx )
{
const QgsRasterAttributeTable::Field field { fields.at( idx ) };
if ( field.isColor() || field.isRamp() )
{
continue;
}
result.insert( fields.at( idx ).name, data.at( idx ) );
}

return result;
}


static QVariant fcnFeature( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
{
if ( !context )
Expand Down Expand Up @@ -1728,6 +1778,78 @@ static QVariant fcnAttribute( const QVariantList &values, const QgsExpressionCon
return feature.attribute( attr );
}

static QVariant fcnMapToHtmlTable( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QString table { R"html(
<table>
<thead>
<th>%1</th>
</thead>
<tbody>
<tr><td>%2</td></tr>
</tbody>
</table>)html" };
QVariantMap dict;
if ( values.size() == 1 )
{
dict = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
}
else
{
parent->setEvalErrorString( QObject::tr( "Function `map_to_html_table` requires one parameter. %n given.", nullptr, values.length() ) );
return QVariant();
}

if ( dict.isEmpty() )
{
return QVariant();
}

QStringList headers;
QStringList cells;

for ( auto it = dict.cbegin(); it != dict.cend(); ++it )
{
headers.push_back( it.key().toHtmlEscaped() );
cells.push_back( it.value().toString( ).toHtmlEscaped() );
}

return table.arg( headers.join( QStringLiteral( "</th><th>" ) ), cells.join( QStringLiteral( "</td><td>" ) ) );
}

static QVariant fcnMapToHtmlDefinitionList( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QString table { R"html(
<dl>
%1
</dl>)html" };
QVariantMap dict;
if ( values.size() == 1 )
{
dict = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
}
else
{
parent->setEvalErrorString( QObject::tr( "Function `map_to_html_dl` requires one parameter. %n given.", nullptr, values.length() ) );
return QVariant();
}

if ( dict.isEmpty() )
{
return QVariant();
}

QString rows;

for ( auto it = dict.cbegin(); it != dict.cend(); ++it )
{
rows.append( QStringLiteral( "<dt>%1</dt><dd>%2</dd>" ).arg( it.key().toHtmlEscaped(), it.value().toString().toHtmlEscaped() ) );
}

return table.arg( rows );
}


static QVariant fcnAttributes( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
QgsFeature feature;
Expand Down Expand Up @@ -8470,6 +8592,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "env" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnEnvVar, QStringLiteral( "General" ), QString() )
<< new QgsWithVariableExpressionFunction()
<< new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "raster_attributes" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterAttributes, QStringLiteral( "Rasters" ) )

// functions for arrays
<< new QgsArrayForeachExpressionFunction()
Expand Down Expand Up @@ -8524,6 +8647,10 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "map_prefix_keys" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "prefix" ) ),
fcnMapPrefixKeys, QStringLiteral( "Maps" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "map_to_html_table" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ),
fcnMapToHtmlTable, QStringLiteral( "Maps" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "map_to_html_dl" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ),
fcnMapToHtmlDefinitionList, QStringLiteral( "Maps" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "url_encode" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ),
fcnToFormUrlEncode, QStringLiteral( "Maps" ) )

Expand Down

0 comments on commit 91e5130

Please sign in to comment.