[FEATURE] Legend: optional text on top of symbols for vector layers

In some cases it is useful to add extra information to the symbols in the legend.
This work allows definition of additional labels in vector layer properties > Legend tab.
This commit is contained in:
Martin Dobias 2018-04-18 21:52:56 +02:00
parent 15bf357f6a
commit 49b02bf562
17 changed files with 570 additions and 3 deletions

View File

@ -231,6 +231,34 @@ to the associated vector layer's renderer.
.. seealso:: :py:func:`symbol`
.. versionadded:: 2.14
%End
QString textOnSymbolLabel() const;
%Docstring
Returns label of text to be shown on top of the symbol.
.. versionadded:: 3.2
%End
void setTextOnSymbolLabel( const QString &label );
%Docstring
Sets label of text to be shown on top of the symbol.
.. versionadded:: 3.2
%End
QgsTextFormat textOnSymbolTextFormat() const;
%Docstring
Returns text format of the label to be shown on top of the symbol.
.. versionadded:: 3.2
%End
void setTextOnSymbolTextFormat( const QgsTextFormat &format );
%Docstring
Sets format of text to be shown on top of the symbol.
.. versionadded:: 3.2
%End
public slots:

View File

@ -11,6 +11,7 @@
class QgsMapLayerLegend : QObject
{
%Docstring
@ -31,6 +32,20 @@ Constructor for QgsMapLayerLegend
%End
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );
%Docstring
Reads configuration from a DOM element previously written by writeXml()
.. versionadded:: 3.2
%End
virtual QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const;
%Docstring
Writes configuration to a DOM element, to be used later with readXml()
.. versionadded:: 3.2
%End
virtual QList<QgsLayerTreeModelLegendNode *> createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer ) = 0 /Factory/;
%Docstring
Return list of legend nodes to be used for a particular layer tree layer node.
@ -84,6 +99,7 @@ update according to layer node's custom properties (order of items, user labels
class QgsDefaultVectorLayerLegend : QgsMapLayerLegend
{
%Docstring
@ -98,8 +114,58 @@ Default legend implementation for vector layers
public:
explicit QgsDefaultVectorLayerLegend( QgsVectorLayer *vl );
bool textOnSymbolEnabled() const;
%Docstring
Returns whether the "text on symbol" functionality is enabled. When enabled, legend symbols
may have extra text rendered on top. The content of labels and their style is controlled
by textOnSymbolContent() and textOnSymbolTextFormat().
.. versionadded:: 3.2
%End
void setTextOnSymbolEnabled( bool enabled );
%Docstring
Sets whether the "text on symbol" functionality is enabled. When enabled, legend symbols
may have extra text rendered on top. The content of labels and their style is controlled
by textOnSymbolContent() and textOnSymbolTextFormat().
.. versionadded:: 3.2
%End
QgsTextFormat textOnSymbolTextFormat() const;
%Docstring
Returns text format of symbol labels for "text on symbol" functionality.
.. versionadded:: 3.2
%End
void setTextOnSymbolTextFormat( const QgsTextFormat &format );
%Docstring
Sets text format of symbol labels for "text on symbol" functionality.
.. versionadded:: 3.2
%End
QHash<QString, QString> textOnSymbolContent() const;
%Docstring
Returns per-symbol content of labels for "text on symbol" functionality. In the passed dictionary
the keys are rule keys of legend items, the values are labels to be shown.
.. versionadded:: 3.2
%End
void setTextOnSymbolContent( const QHash<QString, QString> &content );
%Docstring
Sets per-symbol content of labels for "text on symbol" functionality. In the passed dictionary
the keys are rule keys of legend items, the values are labels to be shown.
.. versionadded:: 3.2
%End
virtual QList<QgsLayerTreeModelLegendNode *> createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer ) /Factory/;
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );
virtual QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const;
};

View File

@ -48,6 +48,13 @@ Constructor for QgsTextFormatWidget.
QgsTextFormat format() const;
%Docstring
Returns the current formatting settings defined by the widget.
%End
void setFormat( const QgsTextFormat &format );
%Docstring
Sets the current formatting settings
.. versionadded:: 3.2
%End
public slots:

View File

@ -133,6 +133,7 @@ SET(QGIS_APP_SRCS
qgstextannotationdialog.cpp
qgssvgannotationdialog.cpp
qgsundowidget.cpp
qgsvectorlayerlegendwidget.cpp
qgsvectorlayerproperties.cpp
qgsmapthemes.cpp
qgshandlebadlayers.cpp
@ -361,6 +362,7 @@ SET (QGIS_APP_MOC_HDRS
qgssvgannotationdialog.h
qgstextannotationdialog.h
qgsundowidget.h
qgsvectorlayerlegendwidget.h
qgsvectorlayerproperties.h
qgsmapthemes.h
qgshandlebadlayers.h

View File

@ -0,0 +1,140 @@
/***************************************************************************
qgsvectorlayerlegendwidget.cpp
---------------------
Date : April 2018
Copyright : (C) 2018 by Martin Dobias
Email : wonder dot sk at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsvectorlayerlegendwidget.h"
#include <QBoxLayout>
#include <QStandardItemModel>
#include <QTreeView>
#include "qgsmaplayerlegend.h"
#include "qgsrenderer.h"
#include "qgssymbollayerutils.h"
#include "qgstextformatwidget.h"
#include "qgsvectorlayer.h"
QgsVectorLayerLegendWidget::QgsVectorLayerLegendWidget( QWidget *parent )
: QWidget( parent )
{
mLegendTreeView = new QTreeView;
mLegendTreeView->setRootIsDecorated( false );
mTextOnSymbolFormatButton = new QPushButton( tr( "Set Text Format..." ) );
connect( mTextOnSymbolFormatButton, &QPushButton::clicked, this, &QgsVectorLayerLegendWidget::openTextFormatWidget );
mTextOnSymbolGroupBox = new QgsCollapsibleGroupBox;
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->addWidget( mLegendTreeView );
groupLayout->addWidget( mTextOnSymbolFormatButton );
mTextOnSymbolGroupBox->setTitle( tr( "Text on Symbols" ) );
mTextOnSymbolGroupBox->setCheckable( true );
mTextOnSymbolGroupBox->setLayout( groupLayout );
mTextOnSymbolGroupBox->setCollapsed( true );
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget( mTextOnSymbolGroupBox );
setLayout( layout );
}
void QgsVectorLayerLegendWidget::setLayer( QgsVectorLayer *layer )
{
mLayer = layer;
QgsDefaultVectorLayerLegend *legend = qobject_cast<QgsDefaultVectorLayerLegend *>( layer->legend() );
if ( !legend )
return;
mTextOnSymbolGroupBox->setChecked( legend->textOnSymbolEnabled() );
mTextOnSymbolTextFormat = legend->textOnSymbolTextFormat();
QHash<QString, QString> content = legend->textOnSymbolContent();
QStandardItemModel *model = new QStandardItemModel;
model->setColumnCount( 2 );
model->setHorizontalHeaderLabels( QStringList() << tr( "Symbol" ) << tr( "Text" ) );
const QgsLegendSymbolList lst = layer->renderer()->legendSymbolItems();
for ( const QgsLegendSymbolItem &symbolItem : lst )
{
if ( !symbolItem.symbol() )
continue;
QgsRenderContext context;
QSize iconSize( 16, 16 );
QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbolItem.symbol(), iconSize, 0, &context );
QStandardItem *item1 = new QStandardItem( icon, symbolItem.label() );
item1->setEditable( false );
QStandardItem *item2 = new QStandardItem;
if ( symbolItem.ruleKey().isEmpty() )
{
item1->setEnabled( false );
item2->setEnabled( true );
}
else
{
item1->setData( symbolItem.ruleKey() );
if ( content.contains( symbolItem.ruleKey() ) )
item2->setText( content.value( symbolItem.ruleKey() ) );
}
model->appendRow( QList<QStandardItem *>() << item1 << item2 );
}
mLegendTreeView->setModel( model );
mLegendTreeView->resizeColumnToContents( 0 );
}
void QgsVectorLayerLegendWidget::applyToLayer()
{
QgsDefaultVectorLayerLegend *legend = new QgsDefaultVectorLayerLegend( mLayer );
legend->setTextOnSymbolEnabled( mTextOnSymbolGroupBox->isChecked() );
legend->setTextOnSymbolTextFormat( mTextOnSymbolTextFormat );
QHash<QString, QString> content;
if ( QStandardItemModel *model = qobject_cast<QStandardItemModel *>( mLegendTreeView->model() ) )
{
for ( int i = 0; i < model->rowCount(); ++i )
{
QString ruleKey = model->item( i, 0 )->data().toString();
QString label = model->item( i, 1 )->text();
if ( !label.isEmpty() )
content[ruleKey] = label;
}
}
legend->setTextOnSymbolContent( content );
mLayer->setLegend( legend );
}
void QgsVectorLayerLegendWidget::openTextFormatWidget()
{
QgsTextFormatWidget *textOnSymbolFormatWidget = new QgsTextFormatWidget( mTextOnSymbolTextFormat );
QDialogButtonBox *dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget( textOnSymbolFormatWidget );
layout->addWidget( dialogButtonBox );
QDialog dlg;
connect( dialogButtonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
connect( dialogButtonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
dlg.setLayout( layout );
if ( !dlg.exec() )
return;
mTextOnSymbolTextFormat = textOnSymbolFormatWidget->format();
}

View File

@ -0,0 +1,58 @@
/***************************************************************************
qgsvectorlayerlegendwidget.h
---------------------
Date : April 2018
Copyright : (C) 2018 by Martin Dobias
Email : wonder dot sk at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSVECTORLAYERLEGENDWIDGET_H
#define QGSVECTORLAYERLEGENDWIDGET_H
#include <QWidget>
#include "qgstextrenderer.h"
class QLabel;
class QPushButton;
class QTreeView;
class QgsCollapsibleGroupBox;
class QgsVectorLayer;
/**
* A widget for configuration of options specific to vector layer's legend.
*/
class QgsVectorLayerLegendWidget : public QWidget
{
Q_OBJECT
public:
explicit QgsVectorLayerLegendWidget( QWidget *parent = nullptr );
//! Initialize widget with a map layer
void setLayer( QgsVectorLayer *layer );
//! Store changes made in the widget to the layer
void applyToLayer();
private slots:
void openTextFormatWidget();
private:
QTreeView *mLegendTreeView = nullptr;
QPushButton *mTextOnSymbolFormatButton = nullptr;
QgsCollapsibleGroupBox *mTextOnSymbolGroupBox = nullptr;
QLabel *mTextOnSymbolLabel = nullptr;
QgsVectorLayer *mLayer = nullptr;
QgsTextFormat mTextOnSymbolTextFormat;
};
#endif // QGSVECTORLAYERLEGENDWIDGET_H

View File

@ -302,6 +302,7 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
mDiagramFrame->setLayout( diagLayout );
// Legend tab
mLegendWidget->setLayer( mLayer );
mLegendConfigEmbeddedWidget->setLayer( mLayer );
// WMS Name as layer short name
@ -572,6 +573,7 @@ void QgsVectorLayerProperties::apply()
}
// apply legend settings
mLegendWidget->applyToLayer();
mLegendConfigEmbeddedWidget->applyToLayer();
// save metadata

View File

@ -178,6 +178,15 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const
true ).size();
}
if ( !mTextOnSymbolLabel.isEmpty() && context )
{
double w = QgsTextRenderer::textWidth( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel );
double h = QgsTextRenderer::textHeight( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel, QgsTextRenderer::Point );
int wInt = ceil( w ), hInt = ceil( h );
if ( wInt > minSz.width() ) minSz.setWidth( wInt );
if ( hInt > minSz.height() ) minSz.setHeight( hInt );
}
if ( mItem.level() != 0 && !( model() && model()->testFlag( QgsLayerTreeModel::ShowLegendAsTree ) ) )
minSz.setWidth( mItem.level() * INDENT_SIZE + minSz.width() );
@ -271,6 +280,17 @@ QVariant QgsSymbolLegendNode::data( int role ) const
{
std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), mIconSize, 0, context.get() );
if ( !mTextOnSymbolLabel.isEmpty() && context )
{
QPainter painter( &pix );
painter.setRenderHint( QPainter::Antialiasing );
context->setPainter( &painter );
QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context.get() ) );
qreal yBaselineVCenter = ( mIconSize.height() + fm.ascent() - fm.descent() ) / 2;
QgsTextRenderer::drawText( QPointF( mIconSize.width() / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
QStringList() << mTextOnSymbolLabel, *context.get(), mTextOnSymbolTextFormat );
}
}
else
{
@ -418,6 +438,15 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
{
s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
}
if ( !mTextOnSymbolLabel.isEmpty() )
{
QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( context ) );
qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
QStringList() << mTextOnSymbolLabel, context, mTextOnSymbolTextFormat );
}
p->restore();
}

View File

@ -144,6 +144,7 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
};
#include "qgslegendsymbolitem.h"
#include "qgstextrenderer.h"
/**
* \ingroup core
@ -221,6 +222,30 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode
*/
void setSymbol( QgsSymbol *symbol );
/**
* Returns label of text to be shown on top of the symbol.
* \since QGIS 3.2
*/
QString textOnSymbolLabel() const { return mTextOnSymbolLabel; }
/**
* Sets label of text to be shown on top of the symbol.
* \since QGIS 3.2
*/
void setTextOnSymbolLabel( const QString &label ) { mTextOnSymbolLabel = label; }
/**
* Returns text format of the label to be shown on top of the symbol.
* \since QGIS 3.2
*/
QgsTextFormat textOnSymbolTextFormat() const { return mTextOnSymbolTextFormat; }
/**
* Sets format of text to be shown on top of the symbol.
* \since QGIS 3.2
*/
void setTextOnSymbolTextFormat( const QgsTextFormat &format ) { mTextOnSymbolTextFormat = format; }
public slots:
/**
@ -247,6 +272,9 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode
bool mSymbolUsesMapUnits;
QSize mIconSize;
QString mTextOnSymbolLabel;
QgsTextFormat mTextOnSymbolTextFormat;
// ident the symbol icon to make it look like a tree structure
static const int INDENT_SIZE = 20;

View File

@ -30,6 +30,19 @@ QgsMapLayerLegend::QgsMapLayerLegend( QObject *parent )
{
}
void QgsMapLayerLegend::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
Q_UNUSED( elem );
Q_UNUSED( context );
}
QDomElement QgsMapLayerLegend::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
{
Q_UNUSED( doc );
Q_UNUSED( context );
return QDomElement();
}
QgsMapLayerLegend *QgsMapLayerLegend::defaultVectorLegend( QgsVectorLayer *vl )
{
return new QgsDefaultVectorLayerLegend( vl );
@ -199,7 +212,15 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTre
if ( i.dataDefinedSizeLegendSettings() )
nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *i.dataDefinedSizeLegendSettings() );
else
nodes << new QgsSymbolLegendNode( nodeLayer, i );
{
QgsSymbolLegendNode *legendNode = new QgsSymbolLegendNode( nodeLayer, i );
if ( mTextOnSymbolEnabled && mTextOnSymbolContent.contains( i.ruleKey() ) )
{
legendNode->setTextOnSymbolLabel( mTextOnSymbolContent.value( i.ruleKey() ) );
legendNode->setTextOnSymbolTextFormat( mTextOnSymbolTextFormat );
}
nodes << legendNode;
}
}
if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
@ -218,6 +239,52 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTre
return nodes;
}
void QgsDefaultVectorLayerLegend::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
mTextOnSymbolEnabled = false;
mTextOnSymbolTextFormat = QgsTextFormat();
mTextOnSymbolContent.clear();
QDomElement tosElem = elem.firstChildElement( QStringLiteral( "text-on-symbol" ) );
if ( !tosElem.isNull() )
{
mTextOnSymbolEnabled = true;
QDomElement tosFormatElem = tosElem.firstChildElement( QStringLiteral( "text-style" ) );
mTextOnSymbolTextFormat.readXml( tosFormatElem, context );
QDomElement tosContentElem = tosElem.firstChildElement( QStringLiteral( "content" ) );
QDomElement tosContentItemElem = tosContentElem.firstChildElement( QStringLiteral( "item" ) );
while ( !tosContentItemElem.isNull() )
{
mTextOnSymbolContent.insert( tosContentItemElem.attribute( QStringLiteral( "key" ) ), tosContentItemElem.attribute( QStringLiteral( "value" ) ) );
tosContentItemElem = tosContentItemElem.nextSiblingElement( QStringLiteral( "item" ) );
}
}
}
QDomElement QgsDefaultVectorLayerLegend::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
{
QDomElement elem = doc.createElement( QStringLiteral( "legend" ) );
elem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "default-vector" ) );
if ( mTextOnSymbolEnabled )
{
QDomElement tosElem = doc.createElement( QStringLiteral( "text-on-symbol" ) );
QDomElement tosFormatElem = mTextOnSymbolTextFormat.writeXml( doc, context );
tosElem.appendChild( tosFormatElem );
QDomElement tosContentElem = doc.createElement( QStringLiteral( "content" ) );
for ( auto it = mTextOnSymbolContent.constBegin(); it != mTextOnSymbolContent.constEnd(); ++it )
{
QDomElement tosContentItemElem = doc.createElement( QStringLiteral( "item" ) );
tosContentItemElem.setAttribute( QStringLiteral( "key" ), it.key() );
tosContentItemElem.setAttribute( QStringLiteral( "value" ), it.value() );
tosContentElem.appendChild( tosContentItemElem );
}
tosElem.appendChild( tosContentElem );
elem.appendChild( tosElem );
}
return elem;
}
// -------------------------------------------------------------------------

View File

@ -19,10 +19,14 @@
#include <QObject>
#include "qgis.h"
class QDomDocument;
class QDomElement;
class QgsLayerTreeLayer;
class QgsLayerTreeModelLegendNode;
class QgsPluginLayer;
class QgsRasterLayer;
class QgsReadWriteContext;
class QgsVectorLayer;
#include "qgis_core.h"
@ -43,7 +47,19 @@ class CORE_EXPORT QgsMapLayerLegend : public QObject
//! Constructor for QgsMapLayerLegend
explicit QgsMapLayerLegend( QObject *parent SIP_TRANSFERTHIS = nullptr );
// TODO: type, load/save settings
// TODO: type
/**
* Reads configuration from a DOM element previously written by writeXml()
* \since QGIS 3.2
*/
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );
/**
* Writes configuration to a DOM element, to be used later with readXml()
* \since QGIS 3.2
*/
virtual QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const;
/**
* Return list of legend nodes to be used for a particular layer tree layer node.
@ -89,6 +105,8 @@ class CORE_EXPORT QgsMapLayerLegendUtils
#include <QHash>
#include "qgstextrenderer.h"
/**
* \ingroup core
* Default legend implementation for vector layers
@ -101,10 +119,59 @@ class CORE_EXPORT QgsDefaultVectorLayerLegend : public QgsMapLayerLegend
public:
explicit QgsDefaultVectorLayerLegend( QgsVectorLayer *vl );
/**
* Returns whether the "text on symbol" functionality is enabled. When enabled, legend symbols
* may have extra text rendered on top. The content of labels and their style is controlled
* by textOnSymbolContent() and textOnSymbolTextFormat().
* \since QGIS 3.2
*/
bool textOnSymbolEnabled() const { return mTextOnSymbolEnabled; }
/**
* Sets whether the "text on symbol" functionality is enabled. When enabled, legend symbols
* may have extra text rendered on top. The content of labels and their style is controlled
* by textOnSymbolContent() and textOnSymbolTextFormat().
* \since QGIS 3.2
*/
void setTextOnSymbolEnabled( bool enabled ) { mTextOnSymbolEnabled = enabled; }
/**
* Returns text format of symbol labels for "text on symbol" functionality.
* \since QGIS 3.2
*/
QgsTextFormat textOnSymbolTextFormat() const { return mTextOnSymbolTextFormat; }
/**
* Sets text format of symbol labels for "text on symbol" functionality.
* \since QGIS 3.2
*/
void setTextOnSymbolTextFormat( const QgsTextFormat &format ) { mTextOnSymbolTextFormat = format; }
/**
* Returns per-symbol content of labels for "text on symbol" functionality. In the passed dictionary
* the keys are rule keys of legend items, the values are labels to be shown.
* \since QGIS 3.2
*/
QHash<QString, QString> textOnSymbolContent() const { return mTextOnSymbolContent; }
/**
* Sets per-symbol content of labels for "text on symbol" functionality. In the passed dictionary
* the keys are rule keys of legend items, the values are labels to be shown.
* \since QGIS 3.2
*/
void setTextOnSymbolContent( const QHash<QString, QString> &content ) { mTextOnSymbolContent = content; }
QList<QgsLayerTreeModelLegendNode *> createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer ) SIP_FACTORY override;
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override;
virtual QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const override;
private:
QgsVectorLayer *mLayer = nullptr;
// text on symbol
bool mTextOnSymbolEnabled = false;
QgsTextFormat mTextOnSymbolTextFormat;
QHash<QString, QString> mTextOnSymbolContent;
};

View File

@ -1423,7 +1423,11 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
}
setDependencies( sources );
setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
QgsMapLayerLegend *legend = QgsMapLayerLegend::defaultVectorLegend( this );
QDomElement legendElem = layer_node.firstChildElement( QStringLiteral( "legend" ) );
if ( !legendElem.isNull() )
legend->readXml( legendElem, context );
setLegend( legend );
// read extent
if ( mReadExtentFromXml )
@ -1688,6 +1692,14 @@ bool QgsVectorLayer::writeXml( QDomNode &layer_node,
}
layer_node.appendChild( dataDependenciesElement );
// legend
if ( legend() )
{
QDomElement legendElement = legend()->writeXml( document, context );
if ( !legendElement.isNull() )
layer_node.appendChild( legendElement );
}
// save expression fields
mExpressionFieldBuffer->writeXml( layer_node, document );

View File

@ -828,6 +828,11 @@ QgsTextFormat QgsTextFormatWidget::format() const
return format;
}
void QgsTextFormatWidget::setFormat( const QgsTextFormat &format )
{
updateWidgetForFormat( format );
}
void QgsTextFormatWidget::optionsStackedWidget_CurrentChanged( int indx )
{
mLabelingOptionsListWidget->blockSignals( true );

View File

@ -68,6 +68,12 @@ class GUI_EXPORT QgsTextFormatWidget : public QWidget, protected Ui::QgsTextForm
*/
QgsTextFormat format() const;
/**
* Sets the current formatting settings
* \since QGIS 3.2
*/
void setFormat( const QgsTextFormat &format );
public slots:
/**

View File

@ -1878,6 +1878,9 @@ border-radius: 2px;</string>
<number>0</number>
</property>
<item>
<widget class="QgsVectorLayerLegendWidget" name="mLegendWidget" native="true"/>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Embedded widgets in legend</string>
@ -2416,6 +2419,12 @@ border-radius: 2px;</string>
<extends>QWidget</extends>
<header>qgscodeeditorhtml.h</header>
</customwidget>
<customwidget>
<class>QgsVectorLayerLegendWidget</class>
<extends>QWidget</extends>
<header>qgsvectorlayerlegendwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mSearchLineEdit</tabstop>

View File

@ -122,6 +122,7 @@ class TestQgsLegendRenderer : public QObject
void testDiagramAttributeLegend();
void testDiagramSizeLegend();
void testDataDefinedSizeCollapsed();
void testTextOnSymbol();
private:
QgsLayerTree *mRoot = nullptr;
@ -783,6 +784,46 @@ void TestQgsLegendRenderer::testDataDefinedSizeCollapsed()
delete root;
}
void TestQgsLegendRenderer::testTextOnSymbol()
{
QString testName = QStringLiteral( "legend_text_on_symbol" );
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "Polygon Layer" ), QStringLiteral( "memory" ) );
QgsCategoryList cats;
QgsFillSymbol *sym_1 = new QgsFillSymbol();
sym_1->setColor( Qt::red );
cats << QgsRendererCategory( 1, sym_1, QStringLiteral( "Red" ) );
QgsFillSymbol *sym_2 = new QgsFillSymbol();
sym_2->setColor( Qt::green );
cats << QgsRendererCategory( 2, sym_2, QStringLiteral( "Green" ) );
QgsFillSymbol *sym_3 = new QgsFillSymbol();
sym_3->setColor( Qt::blue );
cats << QgsRendererCategory( 3, sym_3, QStringLiteral( "Blue" ) );
QgsCategorizedSymbolRenderer *r = new QgsCategorizedSymbolRenderer( QStringLiteral( "test_attr" ), cats );
vl->setRenderer( r );
QgsDefaultVectorLayerLegend *legend = new QgsDefaultVectorLayerLegend( vl );
legend->setTextOnSymbolEnabled( true );
QHash<QString, QString> content;
content["0"] = "Rd";
content["2"] = "Bl";
legend->setTextOnSymbolContent( content );
vl->setLegend( legend );
QgsLayerTree *root = new QgsLayerTree();
root->addLayer( vl );
QgsLayerTreeModel legendModel( root );
QgsLegendSettings settings;
_setStandardTestFont( settings );
_renderLegend( testName, &legendModel, settings );
QVERIFY( _verifyImage( testName, mReport ) );
delete root;
}
QGSTEST_MAIN( TestQgsLegendRenderer )
#include "testqgslegendrenderer.moc"

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB