mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[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:
parent
15bf357f6a
commit
49b02bf562
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
140
src/app/qgsvectorlayerlegendwidget.cpp
Normal file
140
src/app/qgsvectorlayerlegendwidget.cpp
Normal 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();
|
||||
}
|
58
src/app/qgsvectorlayerlegendwidget.h
Normal file
58
src/app/qgsvectorlayerlegendwidget.h
Normal 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
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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:
|
||||
|
||||
/**
|
||||
|
@ -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>
|
||||
|
@ -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 |
Loading…
x
Reference in New Issue
Block a user