QGIS API Documentation  2.11.0-Master
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 "qgsrendererv2.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsdiagramrendererv2.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 
53 {
54  QStringList orderStr;
55  foreach ( int id, order )
56  orderStr << QString::number( id );
57  QString str = orderStr.isEmpty() ? "empty" : orderStr.join( "," );
58 
59  nodeLayer->setCustomProperty( "legend/node-order", str );
60 }
61 
63 {
64  // this is not particularly efficient way of finding out number of legend nodes
66  int numNodes = lst.count();
67  qDeleteAll( lst );
68  return numNodes;
69 }
70 
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  for ( int i = 0; i < numNodes; ++i )
83  order << i;
84  return order;
85 }
86 
88 {
89  QString orderStr = nodeLayer->customProperty( "legend/node-order" ).toString();
90 
91  if ( orderStr.isEmpty() )
92  return _makeNodeOrder( nodeLayer );
93 
94  if ( orderStr == "empty" )
95  return QList<int>();
96 
97  int numNodes = _originalLegendNodeCount( nodeLayer );
98 
99  QList<int> lst;
100  foreach ( 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( "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 
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 
135 {
136  // handle user labels
137  int i = 0;
138  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  {
149 
151  QSet<int> usedIndices;
152  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 {
182  connect( mLayer, SIGNAL( rendererChanged() ), this, SIGNAL( itemsChanged() ) );
183 }
184 
186 {
188 
189  QgsFeatureRendererV2* r = mLayer->rendererV2();
190  if ( !r )
191  return nodes;
192 
193  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toBool() )
194  mLayer->countSymbolFeatures();
195 
196  QSettings settings;
197  if ( settings.value( "/qgis/showLegendClassifiers", false ).toBool() && !r->legendClassificationAttribute().isEmpty() )
198  {
199  nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) );
200  }
201 
202  // we have varying icon sizes, and we want icon to be centered and
203  // text to be left aligned, so we have to compute the max width of icons
204  //
205  // we do that for nodes who share a common parent
206 
207  QList<QgsSymbolV2LegendNode*> symbolNodes;
208  QMap<QString, int> widthMax;
209  foreach ( const QgsLegendSymbolItemV2& i, r->legendSymbolItemsV2() )
210  {
211  QgsSymbolV2LegendNode * n = new QgsSymbolV2LegendNode( nodeLayer, i );
212  nodes.append( n );
213  if ( i.symbol() )
214  {
215  const QSize sz( n->minimumIconSize() );
217  widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
218  n->setIconSize( sz );
219  symbolNodes.append( n );
220  }
221  }
222 
223  foreach ( QgsSymbolV2LegendNode* n, symbolNodes )
224  {
226  Q_ASSERT( widthMax[parentKey] > 0 );
227  const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
228  n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
229  }
230 
231  if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
232  nodes[0]->setEmbeddedInParent( true );
233 
234 
235  if ( mLayer->diagramsEnabled() )
236  {
237  foreach ( QgsLayerTreeModelLegendNode * i, mLayer->diagramRenderer()->legendItems( nodeLayer ) )
238  {
239  nodes.append( i );
240  }
241  }
242 
243 
244  return nodes;
245 }
246 
247 
248 
249 // -------------------------------------------------------------------------
250 
251 
253  : mLayer( rl )
254 {
255  connect( mLayer, SIGNAL( rendererChanged() ), this, SIGNAL( itemsChanged() ) );
256 }
257 
259 {
261 
262  // temporary solution for WMS. Ideally should be done with a delegate.
263  if ( mLayer->providerType() == "wms" )
264  {
265  nodes << new QgsWMSLegendNode( nodeLayer );
266  }
267 
268  QgsLegendColorList rasterItemList = mLayer->legendSymbologyItems();
269  if ( rasterItemList.count() == 0 )
270  return nodes;
271 
272  // Paletted raster may have many colors, for example UInt16 may have 65536 colors
273  // and it is very slow, so we limit max count
274  int count = 0;
275  int max_count = 1000;
276 
277  for ( QgsLegendColorList::const_iterator itemIt = rasterItemList.constBegin();
278  itemIt != rasterItemList.constEnd(); ++itemIt, ++count )
279  {
280  nodes << new QgsRasterSymbolLegendNode( nodeLayer, itemIt->second, itemIt->first );
281 
282  if ( count == max_count )
283  {
284  QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count );
285  nodes << new QgsSimpleLegendNode( nodeLayer, label );
286  break;
287  }
288  }
289 
290  return nodes;
291 }
292 
293 
294 // -------------------------------------------------------------------------
295 
296 
298  : mLayer( pl )
299 {
300 }
301 
303 {
305 
306  QSize iconSize( 16, 16 );
307  QgsLegendSymbologyList symbologyList = mLayer->legendSymbologyItems( iconSize );
308 
309  if ( symbologyList.count() == 0 )
310  return nodes;
311 
312  typedef QPair<QString, QPixmap> XY;
313  foreach ( XY item, symbologyList )
314  {
315  nodes << new QgsSimpleLegendNode( nodeLayer, item.first, QIcon( item.second ) );
316  }
317 
318  return nodes;
319 }
320 
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
static void setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
static QgsMapLayerLegend * defaultPluginLegend(QgsPluginLayer *pl)
Create new legend implementation for raster layer.
virtual QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
static void setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)
virtual QgsLegendSymbologyList legendSymbologyItems(const QSize &iconSize)
return a list of symbology items for the legend (defult implementation returns nothing) ...
QgsMapLayer * layer() const
#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.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Return list of legend nodes to be used for a particular layer tree layer node.
QStringList customProperties() const
Return list of keys stored in custom properties.
Implementation of legend node interface for displaying raster legend entries.
static QList< int > legendNodeOrder(QgsLayerTreeLayer *nodeLayer)
QgsDefaultPluginLayerLegend(QgsPluginLayer *pl)
bool contains(const QString &str, Qt::CaseSensitivity cs) const
Default legend implementation for raster layers.
QSize minimumIconSize() const
Get the minimum icon size to prevent cropping.
static bool hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)
QString join(const QString &separator) const
QgsDefaultVectorLayerLegend(QgsVectorLayer *vl)
QString tr(const char *sourceText, const char *disambiguation, int n)
QgsSymbolV2 * symbol() const
Return associated symbol. May be null.
int size() const
int & rheight()
bool isNull() const
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Return list of legend nodes to be used for a particular layer tree layer node.
rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2...
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
static int _originalLegendNodeCount(QgsLayerTreeLayer *nodeLayer)
virtual QString legendClassificationAttribute() const
If supported by the renderer, return classification attribute for the use in legend.
static QString legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)
virtual QVariant data(int role) const override
Return data associated with the item.
int toInt(bool *ok, int base) const
bool isEmpty() const
bool isEmpty() const
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
static bool hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)
Implementation of legend node interface for displaying arbitrary label with icon. ...
const QgsDiagramRendererV2 * diagramRenderer() const
static void applyLayerNodeProperties(QgsLayerTreeLayer *nodeLayer, QList< QgsLayerTreeModelLegendNode * > &nodes)
update according to layer node's custom properties (order of items, user labels for items) ...
bool countSymbolFeatures(bool showProgress=true)
Count features for symbols.
static QgsMapLayerLegend * defaultVectorLegend(QgsVectorLayer *vl)
Create new legend implementation for vector layer.
bool contains(const T &value) const
QgsMapLayerLegend * legend() const
Can be null.
Implementation of legend node interface for displaying WMS legend entries.
QVariant value(const QString &key, const QVariant &defaultValue) const
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.
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
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)
bool toBool() const
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsMapLayerLegend(QObject *parent=0)
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
const_iterator constEnd() const
const_iterator constBegin() const
void setIconSize(const QSize &sz)
Set the icon size.
Default legend implementation for vector layers.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color)
Represents a vector layer which manages a vector based data sets.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer)=0
Return list of legend nodes to be used for a particular layer tree layer node.
virtual void setUserLabel(const QString &userLabel)
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the node.
Layer tree node points to a map layer.