mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-22 00:06:12 -05:00
Merge pull request #43927 from mhugent/raster_legend_placeholder_icon
Feature: possibility to use placeholder icon in legend for raster layer. funded by [Canton of Glarus] [https://www.gl.ch/verwaltung/bau-und-umwelt/hochbau/raumentwicklung-und-geoinformation/geoportal-kanton-glarus.html/808]
This commit is contained in:
commit
ec374d5ad2
@ -1429,6 +1429,24 @@ Returns the layer's temporal properties. This may be ``None``, depending on the
|
||||
Returns the layer's elevation properties. This may be ``None``, depending on the layer type.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
QString legendPlaceholderImage() const;
|
||||
%Docstring
|
||||
Returns path to the placeholder image or an empty string if a generated legend is shown
|
||||
|
||||
:return: placholder image path
|
||||
|
||||
.. versionadded:: 3.22
|
||||
%End
|
||||
|
||||
void setLegendPlaceholderImage( const QString &imgPath );
|
||||
%Docstring
|
||||
Set placeholder image for legend. If the string is empty, a generated legend will be shown.
|
||||
|
||||
:param imgPath: file path to the placeholder image
|
||||
|
||||
.. versionadded:: 3.22
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
@ -946,19 +946,23 @@ QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCo
|
||||
{
|
||||
Q_UNUSED( itemHeight )
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
if ( ctx && ctx->painter && ctx->context )
|
||||
{
|
||||
QgsScopedRenderContextScaleToPixels scopedScaleToPixels( *( ctx->context ) );
|
||||
double scaleFactor = ctx->context->scaleFactor();
|
||||
double imgWidth = settings.wmsLegendSize().width() * scaleFactor;
|
||||
double imgHeight = settings.wmsLegendSize().height() * scaleFactor;
|
||||
|
||||
QImage scaledImg = mImage.scaled( QSizeF( imgWidth, imgHeight ).toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnLeft, ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
|
||||
mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
|
||||
ctx->painter->drawImage( QPointF( ctx->columnLeft * scaleFactor, ctx->top * scaleFactor ), scaledImg );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
|
||||
mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
|
||||
ctx->painter->drawImage( QPointF( ctx->columnRight * scaleFactor - imgWidth, ctx->top * scaleFactor ), scaledImg );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -406,6 +406,8 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteCon
|
||||
mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
|
||||
}
|
||||
|
||||
mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) );
|
||||
|
||||
return ! layerError;
|
||||
} // bool QgsMapLayer::readLayerXML
|
||||
|
||||
@ -576,6 +578,8 @@ bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &docume
|
||||
mMetadata.writeMetadataXml( myMetadataElem, document );
|
||||
layerElement.appendChild( myMetadataElem );
|
||||
|
||||
layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage );
|
||||
|
||||
// now append layer node to map layer node
|
||||
return writeXml( layerElement, document, context );
|
||||
}
|
||||
|
@ -1279,6 +1279,20 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
virtual QgsMapLayerElevationProperties *elevationProperties() { return nullptr; }
|
||||
|
||||
/**
|
||||
* Returns path to the placeholder image or an empty string if a generated legend is shown
|
||||
* \return placholder image path
|
||||
* \since QGIS 3.22
|
||||
*/
|
||||
QString legendPlaceholderImage() const { return mLegendPlaceholderImage;}
|
||||
|
||||
/**
|
||||
* Set placeholder image for legend. If the string is empty, a generated legend will be shown.
|
||||
* \param imgPath file path to the placeholder image
|
||||
* \since QGIS 3.22
|
||||
*/
|
||||
void setLegendPlaceholderImage( const QString &imgPath ) { mLegendPlaceholderImage = imgPath; }
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -1867,6 +1881,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
//! To avoid firing multiple time repaintRequested signal on circular layer circular dependencies
|
||||
bool mRepaintRequestedFired = false;
|
||||
|
||||
//! Path to placeholder image for layer legend. If the string is empty, a generated legend is shown
|
||||
QString mLegendPlaceholderImage;
|
||||
|
||||
friend class QgsVectorLayer;
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmaplayerlegend.h"
|
||||
|
||||
#include "qgsiconutils.h"
|
||||
#include "qgsimagecache.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
@ -359,6 +360,18 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTre
|
||||
{
|
||||
QList<QgsLayerTreeModelLegendNode *> nodes;
|
||||
|
||||
if ( mLayer )
|
||||
{
|
||||
QString placeholderImage = mLayer->legendPlaceholderImage();
|
||||
if ( !placeholderImage.isEmpty() )
|
||||
{
|
||||
bool fitsInCache;
|
||||
QImage img = QgsApplication::imageCache()->pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache );
|
||||
nodes << new QgsImageLegendNode( nodeLayer, img );
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
QgsFeatureRenderer *r = mLayer->renderer();
|
||||
if ( !r )
|
||||
return nodes;
|
||||
@ -502,7 +515,14 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultRasterLayerLegend::createLayerTre
|
||||
nodes << new QgsWmsLegendNode( nodeLayer );
|
||||
}
|
||||
|
||||
if ( mLayer->renderer() )
|
||||
QString placeholderImage = mLayer->legendPlaceholderImage();
|
||||
if ( !placeholderImage.isEmpty() )
|
||||
{
|
||||
bool fitsInCache;
|
||||
QImage img = QgsApplication::imageCache()->pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache );
|
||||
nodes << new QgsImageLegendNode( nodeLayer, img );
|
||||
}
|
||||
else if ( mLayer->renderer() )
|
||||
nodes.append( mLayer->renderer()->createLegendNodes( nodeLayer ) );
|
||||
return nodes;
|
||||
}
|
||||
|
@ -914,6 +914,8 @@ void QgsRasterLayerProperties::sync()
|
||||
QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false );
|
||||
mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() );
|
||||
|
||||
mLegendPlaceholderWidget->setLastPathSettingsKey( QStringLiteral( "lastLegendPlaceholderDir" ) );
|
||||
mLegendPlaceholderWidget->setSource( mRasterLayer->legendPlaceholderImage() );
|
||||
mLegendConfigEmbeddedWidget->setLayer( mRasterLayer );
|
||||
|
||||
mTemporalWidget->syncToLayer();
|
||||
@ -946,6 +948,7 @@ void QgsRasterLayerProperties::apply()
|
||||
/*
|
||||
* Legend Tab
|
||||
*/
|
||||
mRasterLayer->setLegendPlaceholderImage( mLegendPlaceholderWidget->source() );
|
||||
mLegendConfigEmbeddedWidget->applyToLayer();
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 );
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "qgsexpressionbuilderdialog.h"
|
||||
#include "qgsfilecontentsourcelineedit.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsmaplayerlegend.h"
|
||||
#include "qgsrenderer.h"
|
||||
@ -71,10 +72,19 @@ QgsVectorLayerLegendWidget::QgsVectorLayerLegendWidget( QWidget *parent )
|
||||
labelLegendLayout->addWidget( mLabelLegendTreeWidget );
|
||||
mLabelLegendGroupBox->setLayout( labelLegendLayout );
|
||||
|
||||
mPlaceholderImageLabel = new QLabel( tr( "Legend placeholder image" ) );
|
||||
mImageSourceLineEdit = new QgsImageSourceLineEdit();
|
||||
mImageSourceLineEdit->setLastPathSettingsKey( QStringLiteral( "lastLegendPlaceholderDir" ) );
|
||||
if ( mLayer )
|
||||
{
|
||||
mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() );
|
||||
}
|
||||
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->setContentsMargins( 0, 0, 0, 0 );
|
||||
layout->addWidget( mPlaceholderImageLabel );
|
||||
layout->addWidget( mImageSourceLineEdit );
|
||||
layout->addWidget( mShowLabelLegendCheckBox );
|
||||
layout->addWidget( mLabelLegendGroupBox );
|
||||
layout->addWidget( mTextOnSymbolGroupBox );
|
||||
@ -122,7 +132,10 @@ void QgsVectorLayerLegendWidget::setLayer( QgsVectorLayer *layer )
|
||||
mTextOnSymbolGroupBox->setChecked( legend->textOnSymbolEnabled() );
|
||||
mTextOnSymbolFormatButton->setTextFormat( legend->textOnSymbolTextFormat() );
|
||||
populateLegendTreeView( legend->textOnSymbolContent() );
|
||||
|
||||
if ( mLayer )
|
||||
{
|
||||
mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerLegendWidget::populateLabelLegendTreeWidget()
|
||||
@ -221,6 +234,8 @@ void QgsVectorLayerLegendWidget::applyToLayer()
|
||||
applyLabelLegend();
|
||||
}
|
||||
|
||||
mLayer->setLegendPlaceholderImage( mImageSourceLineEdit->source() );
|
||||
|
||||
mLayer->setLegend( legend );
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QgsImageSourceLineEdit;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QTreeView;
|
||||
@ -76,6 +77,8 @@ class GUI_EXPORT QgsVectorLayerLegendWidget : public QWidget
|
||||
QCheckBox *mShowLabelLegendCheckBox = nullptr;
|
||||
QgsCollapsibleGroupBox *mLabelLegendGroupBox = nullptr;
|
||||
QTreeWidget *mLabelLegendTreeWidget = nullptr;
|
||||
QLabel *mPlaceholderImageLabel = nullptr;
|
||||
QgsImageSourceLineEdit *mImageSourceLineEdit = nullptr;
|
||||
|
||||
QgsMapCanvas *mCanvas = nullptr;
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
|
@ -254,7 +254,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mOptsPage_Information">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
@ -299,8 +299,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>643</width>
|
||||
<height>679</height>
|
||||
<width>650</width>
|
||||
<height>673</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
@ -1563,8 +1563,8 @@ border-radius: 2px;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>577</width>
|
||||
<height>190</height>
|
||||
<width>650</width>
|
||||
<height>673</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
@ -1633,8 +1633,8 @@ border-radius: 2px;</string>
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Fira Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:11pt;"><br /></span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1739,21 +1739,15 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="mOptsPage_Legend">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_15">
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Embedded Widgets in Legend</string>
|
||||
</property>
|
||||
@ -1764,6 +1758,16 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QgsImageSourceLineEdit" name="mLegendPlaceholderWidget" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mLegendPlaceholderLabel">
|
||||
<property name="text">
|
||||
<string>Legend placeholder image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="mOptsPage_Server">
|
||||
@ -1793,8 +1797,8 @@ p, li { white-space: pre-wrap; }
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>343</width>
|
||||
<height>684</height>
|
||||
<width>629</width>
|
||||
<height>793</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_12">
|
||||
@ -2315,6 +2319,23 @@ p, li { white-space: pre-wrap; }
|
||||
<extends>QComboBox</extends>
|
||||
<header>qgsblendmodecombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsOpacityWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgsopacitywidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsRasterBandComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>qgsrasterbandcombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsImageSourceLineEdit</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgsfilecontentsourcelineedit.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mSearchLineEdit</tabstop>
|
||||
|
@ -1045,6 +1045,19 @@ class TestQgsServerWMSGetLegendGraphic(TestQgsServerWMSTestBase):
|
||||
self.assertEqual(node['scaleMaxDenom'], 1000)
|
||||
self.assertEqual(node['scaleMinDenom'], 10000)
|
||||
|
||||
def testLegendPlaceholderIcon(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": self.testdata_path + 'test_project_legend_placeholder_image.qgs',
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.3",
|
||||
"REQUEST": "GetLegendGraphic",
|
||||
"LAYER": "landsat",
|
||||
"FORMAT": "image/png",
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetLegendGraphic_Legend_Placeholder_Icon")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
3257
tests/testdata/qgis_server/test_project_legend_placeholder_image.qgs
vendored
Normal file
3257
tests/testdata/qgis_server/test_project_legend_placeholder_image.qgs
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user