QGIS API Documentation  2.99.0-Master (f867b65)
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 
43 // -------------------------------------------------------------------------
44 
45 
46 void QgsMapLayerLegendUtils::setLegendNodeOrder( QgsLayerTreeLayer *nodeLayer, const QList<int> &order )
47 {
48  QStringList orderStr;
49  Q_FOREACH ( int id, order )
50  orderStr << QString::number( id );
51  QString str = orderStr.isEmpty() ? QStringLiteral( "empty" ) : orderStr.join( QStringLiteral( "," ) );
52 
53  nodeLayer->setCustomProperty( QStringLiteral( "legend/node-order" ), str );
54 }
55 
56 static int _originalLegendNodeCount( QgsLayerTreeLayer *nodeLayer )
57 {
58  // this is not particularly efficient way of finding out number of legend nodes
59  QList<QgsLayerTreeModelLegendNode *> lst = nodeLayer->layer()->legend()->createLayerTreeModelLegendNodes( nodeLayer );
60  int numNodes = lst.count();
61  qDeleteAll( lst );
62  return numNodes;
63 }
64 
65 static QList<int> _makeNodeOrder( QgsLayerTreeLayer *nodeLayer )
66 {
67  if ( !nodeLayer->layer() || !nodeLayer->layer()->legend() )
68  {
69  QgsDebugMsg( "Legend node order manipulation is invalid without existing legend" );
70  return QList<int>();
71  }
72 
73  int numNodes = _originalLegendNodeCount( nodeLayer );
74 
75  QList<int> order;
76  order.reserve( numNodes );
77  for ( int i = 0; i < numNodes; ++i )
78  order << i;
79  return order;
80 }
81 
83 {
84  QString orderStr = nodeLayer->customProperty( QStringLiteral( "legend/node-order" ) ).toString();
85 
86  if ( orderStr.isEmpty() )
87  return _makeNodeOrder( nodeLayer );
88 
89  if ( orderStr == QLatin1String( "empty" ) )
90  return QList<int>();
91 
92  int numNodes = _originalLegendNodeCount( nodeLayer );
93 
94  QList<int> lst;
95  Q_FOREACH ( const QString &item, orderStr.split( ',' ) )
96  {
97  bool ok;
98  int id = item.toInt( &ok );
99  if ( !ok || id < 0 || id >= numNodes )
100  return _makeNodeOrder( nodeLayer );
101 
102  lst << id;
103  }
104 
105  return lst;
106 }
107 
109 {
110  return nodeLayer->customProperties().contains( QStringLiteral( "legend/node-order" ) );
111 }
112 
113 void QgsMapLayerLegendUtils::setLegendNodeUserLabel( QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel )
114 {
115  nodeLayer->setCustomProperty( "legend/label-" + QString::number( originalIndex ), newLabel );
116 }
117 
118 QString QgsMapLayerLegendUtils::legendNodeUserLabel( QgsLayerTreeLayer *nodeLayer, int originalIndex )
119 {
120  return nodeLayer->customProperty( "legend/label-" + QString::number( originalIndex ) ).toString();
121 }
122 
124 {
125  return nodeLayer->customProperties().contains( "legend/label-" + QString::number( originalIndex ) );
126 }
127 
128 
129 void QgsMapLayerLegendUtils::applyLayerNodeProperties( QgsLayerTreeLayer *nodeLayer, QList<QgsLayerTreeModelLegendNode *> &nodes )
130 {
131  // handle user labels
132  int i = 0;
133  Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, nodes )
134  {
135  QString userLabel = QgsMapLayerLegendUtils::legendNodeUserLabel( nodeLayer, i++ );
136  if ( !userLabel.isNull() )
137  legendNode->setUserLabel( userLabel );
138  }
139 
140  // handle user order of nodes
142  {
143  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( nodeLayer );
144 
145  QList<QgsLayerTreeModelLegendNode *> newOrder;
146  QSet<int> usedIndices;
147  Q_FOREACH ( int idx, order )
148  {
149  if ( usedIndices.contains( idx ) )
150  {
151  QgsDebugMsg( "invalid node order. ignoring." );
152  return;
153  }
154 
155  newOrder << nodes[idx];
156  usedIndices << idx;
157  }
158 
159  // delete unused nodes
160  for ( int i = 0; i < nodes.count(); ++i )
161  {
162  if ( !usedIndices.contains( i ) )
163  delete nodes[i];
164  }
165 
166  nodes = newOrder;
167  }
168 
169 }
170 
171 // -------------------------------------------------------------------------
172 
173 
175  : mLayer( vl )
176 {
178 }
179 
180 QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer )
181 {
182  QList<QgsLayerTreeModelLegendNode *> nodes;
183 
184  QgsFeatureRenderer *r = mLayer->renderer();
185  if ( !r )
186  return nodes;
187 
188  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toBool() )
189  mLayer->countSymbolFeatures();
190 
191  QgsSettings settings;
192  if ( settings.value( QStringLiteral( "qgis/showLegendClassifiers" ), false ).toBool() && !r->legendClassificationAttribute().isEmpty() )
193  {
194  nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) );
195  }
196 
197  Q_FOREACH ( const QgsLegendSymbolItem &i, r->legendSymbolItems() )
198  {
200  nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *i.dataDefinedSizeLegendSettings() );
201  else
202  nodes << new QgsSymbolLegendNode( nodeLayer, i );
203  }
204 
205  if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
206  nodes[0]->setEmbeddedInParent( true );
207 
208 
209  if ( mLayer->diagramsEnabled() )
210  {
211  Q_FOREACH ( QgsLayerTreeModelLegendNode *i, mLayer->diagramRenderer()->legendItems( nodeLayer ) )
212  {
213  nodes.append( i );
214  }
215  }
216 
217 
218  return nodes;
219 }
220 
221 
222 
223 // -------------------------------------------------------------------------
224 
225 
227  : mLayer( rl )
228 {
230 }
231 
232 QList<QgsLayerTreeModelLegendNode *> QgsDefaultRasterLayerLegend::createLayerTreeModelLegendNodes( QgsLayerTreeLayer *nodeLayer )
233 {
234  QList<QgsLayerTreeModelLegendNode *> nodes;
235 
236  // temporary solution for WMS. Ideally should be done with a delegate.
237  if ( mLayer->dataProvider()->supportsLegendGraphic() )
238  {
239  nodes << new QgsWmsLegendNode( nodeLayer );
240  }
241 
242  QgsLegendColorList rasterItemList = mLayer->legendSymbologyItems();
243  if ( rasterItemList.isEmpty() )
244  return nodes;
245 
246  // Paletted raster may have many colors, for example UInt16 may have 65536 colors
247  // and it is very slow, so we limit max count
248  int count = 0;
249  int max_count = 1000;
250 
251  for ( QgsLegendColorList::const_iterator itemIt = rasterItemList.constBegin();
252  itemIt != rasterItemList.constEnd(); ++itemIt, ++count )
253  {
254  nodes << new QgsRasterSymbolLegendNode( nodeLayer, itemIt->second, itemIt->first );
255 
256  if ( count == max_count )
257  {
258  QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count );
259  nodes << new QgsSimpleLegendNode( nodeLayer, label );
260  break;
261  }
262  }
263 
264  return nodes;
265 }
virtual QgsLegendSymbolList legendSymbolItems() const
Returns a list of symbology items for the legend.
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:306
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:37
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
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.
Produces legend node with a marker symbol.
static QList< int > legendNodeOrder(QgsLayerTreeLayer *nodeLayer)
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
bool countSymbolFeatures()
Count features for symbols.
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)
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.
const QgsDiagramRenderer * diagramRenderer() const
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
QgsMapLayer * layer() const
QList< QPair< QString, QColor > > QgsLegendColorList
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) ...
QgsDataDefinedSizeLegend * dataDefinedSizeLegendSettings() const
Returns extra information for data-defined size legend rendering.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QgsDefaultRasterLayerLegend(QgsRasterLayer *rl)
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...
QgsMapLayerLegend(QObject *parent=0)
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.
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.