Skip to content
Permalink
Browse files

[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.
  • Loading branch information
wonder-sk committed Apr 18, 2018
1 parent 15bf357 commit 49b02bf5628dceeebbaaf16dc665db88911a436f
@@ -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
@@ -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();
}
@@ -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

0 comments on commit 49b02bf

Please sign in to comment.
You can’t perform that action at this time.