QGIS API Documentation  2.99.0-Master (6a61179)
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 <QSettings>
19 
20 #include "qgslayertree.h"
22 #include "qgspluginlayer.h"
23 #include "qgsrasterlayer.h"
24 #include "qgsrenderer.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsdiagramrenderer.h"
27 
28 
30  : QObject( parent )
31 {
32 }
33 
35 {
36  return new QgsDefaultVectorLayerLegend( vl );
37 }
38 
40 {
41  return new QgsDefaultRasterLayerLegend( rl );
42 }
43 
45 {
46  return new QgsDefaultPluginLayerLegend( pl );
47 }
48 
49 // -------------------------------------------------------------------------
50 
51 
52 void QgsMapLayerLegendUtils::setLegendNodeOrder( QgsLayerTreeLayer* nodeLayer, const QList<int>& order )
53 {
54  QStringList orderStr;
55  Q_FOREACH ( int id, order )
56  orderStr << QString::number( id );
57  QString str = orderStr.isEmpty() ? QStringLiteral( "empty" ) : orderStr.join( QStringLiteral( "," ) );
58 
59  nodeLayer->setCustomProperty( QStringLiteral( "legend/node-order" ), str );
60 }
61 
63 {
64  // this is not particularly efficient way of finding out number of legend nodes
65  QList<QgsLayerTreeModelLegendNode*> lst = nodeLayer->layer()->legend()->createLayerTreeModelLegendNodes( nodeLayer );
66  int numNodes = lst.count();
67  qDeleteAll( lst );
68  return numNodes;
69 }
70 
71 static QList<int> _makeNodeOrder( QgsLayerTreeLayer* nodeLayer )
72 {
73  if ( !nodeLayer->layer() || !nodeLayer->layer()->legend() )
74  {
75  QgsDebugMsg( "Legend node order manipulation is invalid without existing legend" );
76  return QList<int>();
77  }
78 
79  int numNodes = _originalLegendNodeCount( nodeLayer );
80 
81  QList<int> order;
82  order.reserve( numNodes );
83  for ( int i = 0; i < numNodes; ++i )
84  order << i;
85  return order;
86 }
87 
89 {
90  QString orderStr = nodeLayer->customProperty( QStringLiteral( "legend/node-order" ) ).toString();
91 
92  if ( orderStr.isEmpty() )
93  return _makeNodeOrder( nodeLayer );
94 
95  if ( orderStr == QLatin1String( "empty" ) )
96  return QList<int>();
97 
98  int numNodes = _originalLegendNodeCount( nodeLayer );
99 
100  QList<int> lst;
101  Q_FOREACH ( const QString& item, orderStr.split( ',' ) )
102  {
103  bool ok;
104  int id = item.toInt( &ok );
105  if ( !ok || id < 0 || id >= numNodes )
106  return _makeNodeOrder( nodeLayer );
107 
108  lst << id;
109  }
110 
111  return lst;
112 }
113 
115 {
116  return nodeLayer->customProperties().contains( QStringLiteral( "legend/node-order" ) );
117 }
118 
119 void QgsMapLayerLegendUtils::setLegendNodeUserLabel( QgsLayerTreeLayer* nodeLayer, int originalIndex, const QString& newLabel )
120 {
121  nodeLayer->setCustomProperty( "legend/label-" + QString::number( originalIndex ), newLabel );
122 }
123 
124 QString QgsMapLayerLegendUtils::legendNodeUserLabel( QgsLayerTreeLayer* nodeLayer, int originalIndex )
125 {
126  return nodeLayer->customProperty( "legend/label-" + QString::number( originalIndex ) ).toString();
127 }
128 
130 {
131  return nodeLayer->customProperties().contains( "legend/label-" + QString::number( originalIndex ) );
132 }
133 
134 
135 void QgsMapLayerLegendUtils::applyLayerNodeProperties( QgsLayerTreeLayer* nodeLayer, QList<QgsLayerTreeModelLegendNode*>& nodes )
136 {
137  // handle user labels
138  int i = 0;
139  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, nodes )
140  {
141  QString userLabel = QgsMapLayerLegendUtils::legendNodeUserLabel( nodeLayer, i++ );
142  if ( !userLabel.isNull() )
143  legendNode->setUserLabel( userLabel );
144  }
145 
146  // handle user order of nodes
148  {
149  QList<int> order = QgsMapLayerLegendUtils::legendNodeOrder( nodeLayer );
150 
151  QList<QgsLayerTreeModelLegendNode*> newOrder;
152  QSet<int> usedIndices;
153  Q_FOREACH ( int idx, order )
154  {
155  if ( usedIndices.contains( idx ) )
156  {
157  QgsDebugMsg( "invalid node order. ignoring." );
158  return;
159  }
160 
161  newOrder << nodes[idx];
162  usedIndices << idx;
163  }
164 
165  // delete unused nodes
166  for ( int i = 0; i < nodes.count(); ++i )
167  {
168  if ( !usedIndices.contains( i ) )
169  delete nodes[i];
170  }
171 
172  nodes = newOrder;
173  }
174 
175 }
176 
177 // -------------------------------------------------------------------------
178 
179 
181  : mLayer( vl )
182 {
183  connect( mLayer, SIGNAL( rendererChanged() ), this, SIGNAL( itemsChanged() ) );
184 }
185 
187 {
188  QList<QgsLayerTreeModelLegendNode*> nodes;
189 
190  QgsFeatureRenderer* r = mLayer->renderer();
191  if ( !r )
192  return nodes;
193 
194  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toBool() )
195  mLayer->countSymbolFeatures();
196 
197  QSettings settings;
198  if ( settings.value( QStringLiteral( "/qgis/showLegendClassifiers" ), false ).toBool() && !r->legendClassificationAttribute().isEmpty() )
199  {
200  nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) );
201  }
202 
203  Q_FOREACH ( const QgsLegendSymbolItem& i, r->legendSymbolItemsV2() )
204  {
205  QgsSymbolLegendNode * n = new QgsSymbolLegendNode( nodeLayer, i );
206  nodes.append( n );
207  }
208 
209  if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
210  nodes[0]->setEmbeddedInParent( true );
211 
212 
213  if ( mLayer->diagramsEnabled() )
214  {
215  Q_FOREACH ( QgsLayerTreeModelLegendNode * i, mLayer->diagramRenderer()->legendItems( nodeLayer ) )
216  {
217  nodes.append( i );
218  }
219  }
220 
221 
222  return nodes;
223 }
224 
225 
226 
227 // -------------------------------------------------------------------------
228 
229 
231  : mLayer( rl )
232 {
233  connect( mLayer, SIGNAL( rendererChanged() ), this, SIGNAL( itemsChanged() ) );
234 }
235 
237 {
238  QList<QgsLayerTreeModelLegendNode*> nodes;
239 
240  // temporary solution for WMS. Ideally should be done with a delegate.
241  if ( mLayer->dataProvider()->supportsLegendGraphic() )
242  {
243  nodes << new QgsWmsLegendNode( nodeLayer );
244  }
245 
246  QgsLegendColorList rasterItemList = mLayer->legendSymbologyItems();
247  if ( rasterItemList.isEmpty() )
248  return nodes;
249 
250  // Paletted raster may have many colors, for example UInt16 may have 65536 colors
251  // and it is very slow, so we limit max count
252  int count = 0;
253  int max_count = 1000;
254 
255  for ( QgsLegendColorList::const_iterator itemIt = rasterItemList.constBegin();
256  itemIt != rasterItemList.constEnd(); ++itemIt, ++count )
257  {
258  nodes << new QgsRasterSymbolLegendNode( nodeLayer, itemIt->second, itemIt->first );
259 
260  if ( count == max_count )
261  {
262  QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count );
263  nodes << new QgsSimpleLegendNode( nodeLayer, label );
264  break;
265  }
266  }
267 
268  return nodes;
269 }
270 
271 
272 // -------------------------------------------------------------------------
273 
274 
276  : mLayer( pl )
277 {
278 }
279 
281 {
282  QList<QgsLayerTreeModelLegendNode*> nodes;
283 
284  QSize iconSize( 16, 16 );
285  QgsLegendSymbologyList symbologyList = mLayer->legendSymbologyItems( iconSize );
286 
287  if ( symbologyList.isEmpty() )
288  return nodes;
289 
290  typedef QPair<QString, QPixmap> XY;
291  Q_FOREACH ( const XY& item, symbologyList )
292  {
293  nodes << new QgsSimpleLegendNode( nodeLayer, item.first, QIcon( item.second ) );
294  }
295 
296  return nodes;
297 }
298 
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:282
static QgsMapLayerLegend * defaultPluginLegend(QgsPluginLayer *pl)
Create new legend implementation for raster layer.
QgsMapLayerLegend * legend() const
Can be null.
static void setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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.
static int _originalLegendNodeCount(QgsLayerTreeLayer *nodeLayer)
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. ...
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) ...
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.
static QList< int > _makeNodeOrder(QgsLayerTreeLayer *nodeLayer)
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsRasterDataProvider * dataProvider()
Returns the data provider.
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 (defult implementation returns nothing) ...
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer)=0
Return list of legend nodes to be used for a particular layer tree layer node.
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.