QGIS API Documentation  2.99.0-Master (cb63e82)
qgsmaplayerlegend.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayerlegend.cpp
3  --------------------------------------
4  Date : July 2014
5  Copyright : (C) 2014 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsmaplayerlegend.h"
17 
18 #include "qgssettings.h"
19 #include "qgslayertree.h"
21 #include "qgspluginlayer.h"
22 #include "qgsrasterlayer.h"
23 #include "qgsrenderer.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsdiagramrenderer.h"
26 
27 
29  : QObject( parent )
30 {
31 }
32 
34 {
35  return new QgsDefaultVectorLayerLegend( vl );
36 }
37 
39 {
40  return new QgsDefaultRasterLayerLegend( rl );
41 }
42 
44 {
45  return new QgsDefaultPluginLayerLegend( pl );
46 }
47 
48 // -------------------------------------------------------------------------
49 
50 
51 void QgsMapLayerLegendUtils::setLegendNodeOrder( QgsLayerTreeLayer *nodeLayer, const QList<int> &order )
52 {
53  QStringList orderStr;
54  Q_FOREACH ( int id, order )
55  orderStr << QString::number( id );
56  QString str = orderStr.isEmpty() ? QStringLiteral( "empty" ) : orderStr.join( QStringLiteral( "," ) );
57 
58  nodeLayer->setCustomProperty( QStringLiteral( "legend/node-order" ), str );
59 }
60 
61 static int _originalLegendNodeCount( QgsLayerTreeLayer *nodeLayer )
62 {
63  // this is not particularly efficient way of finding out number of legend nodes
64  QList<QgsLayerTreeModelLegendNode *> lst = nodeLayer->layer()->legend()->createLayerTreeModelLegendNodes( nodeLayer );
65  int numNodes = lst.count();
66  qDeleteAll( lst );
67  return numNodes;
68 }
69 
70 static QList<int> _makeNodeOrder( QgsLayerTreeLayer *nodeLayer )
71 {
72  if ( !nodeLayer->layer() || !nodeLayer->layer()->legend() )
73  {
74  QgsDebugMsg( "Legend node order manipulation is invalid without existing legend" );
75  return QList<int>();
76  }
77 
78  int numNodes = _originalLegendNodeCount( nodeLayer );
79 
80  QList<int> order;
81  order.reserve( numNodes );
82  for ( int i = 0; i < numNodes; ++i )
83  order << i;
84  return order;
85 }
86 
88 {
89  QString orderStr = nodeLayer->customProperty( QStringLiteral( "legend/node-order" ) ).toString();
90 
91  if ( orderStr.isEmpty() )
92  return _makeNodeOrder( nodeLayer );
93 
94  if ( orderStr == QLatin1String( "empty" ) )
95  return QList<int>();
96 
97  int numNodes = _originalLegendNodeCount( nodeLayer );
98 
99  QList<int> lst;
100  Q_FOREACH ( const QString &item, orderStr.split( ',' ) )
101  {
102  bool ok;
103  int id = item.toInt( &ok );
104  if ( !ok || id < 0 || id >= numNodes )
105  return _makeNodeOrder( nodeLayer );
106 
107  lst << id;
108  }
109 
110  return lst;
111 }
112 
114 {
115  return nodeLayer->customProperties().contains( QStringLiteral( "legend/node-order" ) );
116 }
117 
118 void QgsMapLayerLegendUtils::setLegendNodeUserLabel( QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel )
119 {
120  nodeLayer->setCustomProperty( "legend/label-" + QString::number( originalIndex ), newLabel );
121 }
122 
123 QString QgsMapLayerLegendUtils::legendNodeUserLabel( QgsLayerTreeLayer *nodeLayer, int originalIndex )
124 {
125  return nodeLayer->customProperty( "legend/label-" + QString::number( originalIndex ) ).toString();
126 }
127 
129 {
130  return nodeLayer->customProperties().contains( "legend/label-" + QString::number( originalIndex ) );
131 }
132 
133 
134 void QgsMapLayerLegendUtils::applyLayerNodeProperties( QgsLayerTreeLayer *nodeLayer, QList<QgsLayerTreeModelLegendNode *> &nodes )
135 {
136  // handle user labels
137  int i = 0;
138  Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, nodes )
139  {
140  QString userLabel = QgsMapLayerLegendUtils::legendNodeUserLabel( nodeLayer, i++ );
141  if ( !userLabel.isNull() )
142  legendNode->setUserLabel( userLabel );
143  }
144 
145  // handle user order of nodes
147  {
148  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( nodeLayer );
149 
150  QList<QgsLayerTreeModelLegendNode *> newOrder;
151  QSet<int> usedIndices;
152  Q_FOREACH ( int idx, order )
153  {
154  if ( usedIndices.contains( idx ) )
155  {
156  QgsDebugMsg( "invalid node order. ignoring." );
157  return;
158  }
159 
160  newOrder << nodes[idx];
161  usedIndices << idx;
162  }
163 
164  // delete unused nodes
165  for ( int i = 0; i < nodes.count(); ++i )
166  {
167  if ( !usedIndices.contains( i ) )
168  delete nodes[i];
169  }
170 
171  nodes = newOrder;
172  }
173 
174 }
175 
176 // -------------------------------------------------------------------------
177 
178 
180  : mLayer( vl )
181 {
183 }
184 
185 QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer )
186 {
187  QList<QgsLayerTreeModelLegendNode *> nodes;
188 
189  QgsFeatureRenderer *r = mLayer->renderer();
190  if ( !r )
191  return nodes;
192 
193  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toBool() )
194  mLayer->countSymbolFeatures();
195 
196  QgsSettings settings;
197  if ( settings.value( QStringLiteral( "qgis/showLegendClassifiers" ), false ).toBool() && !r->legendClassificationAttribute().isEmpty() )
198  {
199  nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) );
200  }
201 
202  Q_FOREACH ( const QgsLegendSymbolItem &i, r->legendSymbolItemsV2() )
203  {
204  QgsSymbolLegendNode *n = new QgsSymbolLegendNode( nodeLayer, i );
205  nodes.append( n );
206  }
207 
208  if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
209  nodes[0]->setEmbeddedInParent( true );
210 
211 
212  if ( mLayer->diagramsEnabled() )
213  {
214  Q_FOREACH ( QgsLayerTreeModelLegendNode *i, mLayer->diagramRenderer()->legendItems( nodeLayer ) )
215  {
216  nodes.append( i );
217  }
218  }
219 
220 
221  return nodes;
222 }
223 
224 
225 
226 // -------------------------------------------------------------------------
227 
228 
230  : mLayer( rl )
231 {
233 }
234 
235 QList<QgsLayerTreeModelLegendNode *> QgsDefaultRasterLayerLegend::createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer )
236 {
237  QList<QgsLayerTreeModelLegendNode *> nodes;
238 
239  // temporary solution for WMS. Ideally should be done with a delegate.
240  if ( mLayer->dataProvider()->supportsLegendGraphic() )
241  {
242  nodes << new QgsWmsLegendNode( nodeLayer );
243  }
244 
245  QgsLegendColorList rasterItemList = mLayer->legendSymbologyItems();
246  if ( rasterItemList.isEmpty() )
247  return nodes;
248 
249  // Paletted raster may have many colors, for example UInt16 may have 65536 colors
250  // and it is very slow, so we limit max count
251  int count = 0;
252  int max_count = 1000;
253 
254  for ( QgsLegendColorList::const_iterator itemIt = rasterItemList.constBegin();
255  itemIt != rasterItemList.constEnd(); ++itemIt, ++count )
256  {
257  nodes << new QgsRasterSymbolLegendNode( nodeLayer, itemIt->second, itemIt->first );
258 
259  if ( count == max_count )
260  {
261  QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count );
262  nodes << new QgsSimpleLegendNode( nodeLayer, label );
263  break;
264  }
265  }
266 
267  return nodes;
268 }
269 
270 
271 // -------------------------------------------------------------------------
272 
273 
275  : mLayer( pl )
276 {
277 }
278 
279 QList<QgsLayerTreeModelLegendNode *> QgsDefaultPluginLayerLegend::createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer )
280 {
281  QList<QgsLayerTreeModelLegendNode *> nodes;
282 
283  QSize iconSize( 16, 16 );
284  QgsLegendSymbologyList symbologyList = mLayer->legendSymbologyItems( iconSize );
285 
286  if ( symbologyList.isEmpty() )
287  return nodes;
288 
289  typedef QPair<QString, QPixmap> XY;
290  Q_FOREACH ( const XY &item, symbologyList )
291  {
292  nodes << new QgsSimpleLegendNode( nodeLayer, item.first, QIcon( item.second ) );
293  }
294 
295  return nodes;
296 }
297 
static void setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)
virtual QString legendClassificationAttribute() const
If supported by the renderer, return classification attribute for the use in legend.
Definition: qgsrenderer.h:283
static QgsMapLayerLegend * defaultPluginLegend(QgsPluginLayer *pl)
Create new legend implementation for raster layer.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:54
QgsMapLayerLegend * legend() const
Can be null.
static void setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
Base class for plugin layers.
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Return list of legend nodes to be used for a particular layer tree layer node.
virtual QList< QgsLayerTreeModelLegendNode *> legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
Implementation of legend node interface for displaying raster legend entries.
static QList< int > legendNodeOrder(QgsLayerTreeLayer *nodeLayer)
QgsDefaultPluginLayerLegend(QgsPluginLayer *pl)
Default legend implementation for raster layers.
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
virtual bool supportsLegendGraphic() const
Returns whether the provider supplies a legend graphic.
static bool hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)
QgsDefaultVectorLayerLegend(QgsVectorLayer *vl)
Implementation of legend node interface for displaying WMS legend entries.
QStringList customProperties() const
Return list of keys stored in custom properties.
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Return list of legend nodes to be used for a particular layer tree layer node.
QgsRasterDataProvider * dataProvider() override
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer)=0
Return list of legend nodes to be used for a particular layer tree layer node.
static QString legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)
QgsMapLayerLegend(QObject *parent=nullptr)
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file...
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
QgsFeatureRenderer * renderer()
Return renderer.
static bool hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)
Implementation of legend node interface for displaying arbitrary label with icon. ...
void rendererChanged()
Signal emitted when renderer is changed.
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
const QgsDiagramRenderer * diagramRenderer() const
bool countSymbolFeatures(bool showProgress=true)
Count features for symbols.
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
QgsMapLayer * layer() const
QList< QPair< QString, QColor > > QgsLegendColorList
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
void itemsChanged()
Emitted when existing items/nodes got invalid and should be replaced by new ones. ...
static QgsMapLayerLegend * defaultRasterLegend(QgsRasterLayer *rl)
Create new legend implementation for raster layer.
static void applyLayerNodeProperties(QgsLayerTreeLayer *nodeLayer, QList< QgsLayerTreeModelLegendNode *> &nodes)
update according to layer node&#39;s custom properties (order of items, user labels for items) ...
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QgsDefaultRasterLayerLegend(QgsRasterLayer *rl)
Default legend implementation for plugin layers.
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Return list of legend nodes to be used for a particular layer tree layer node.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
Default legend implementation for vector layers.
QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color)
Represents a vector layer which manages a vector based data sets.
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend (default implementation returns nothing) ...
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
virtual void setUserLabel(const QString &userLabel)
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the node. Properties are stored in a map and saved in project file...
Layer tree node points to a map layer.