QGIS API Documentation  2.17.0-Master (3a3b9ab7)
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  Q_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  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( "legend/node-order" ).toString();
91 
92  if ( orderStr.isEmpty() )
93  return _makeNodeOrder( nodeLayer );
94 
95  if ( orderStr == "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( "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 
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 
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  {
150 
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 {
189 
190  QgsFeatureRendererV2* r = mLayer->rendererV2();
191  if ( !r )
192  return nodes;
193 
194  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toBool() )
195  mLayer->countSymbolFeatures();
196 
197  QSettings settings;
198  if ( settings.value( "/qgis/showLegendClassifiers", false ).toBool() && !r->legendClassificationAttribute().isEmpty() )
199  {
200  nodes.append( new QgsSimpleLegendNode( nodeLayer, r->legendClassificationAttribute() ) );
201  }
202 
203  Q_FOREACH ( const QgsLegendSymbolItemV2& i, r->legendSymbolItemsV2() )
204  {
205  QgsSymbolV2LegendNode * n = new QgsSymbolV2LegendNode( 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 {
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 {
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 
virtual bool supportsLegendGraphic() const
Returns whether the provider supplies a legend graphic.
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)
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
void reserve(int alloc)
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.
static bool hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)
QString join(const QString &separator) const
QgsDefaultVectorLayerLegend(QgsVectorLayer *vl)
QString tr(const char *sourceText, const char *disambiguation, int n)
int size() const
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.
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
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)
QgsMapLayerLegend(QObject *parent=nullptr)
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&#39;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...
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
QgsRasterDataProvider * dataProvider()
Returns the data provider.
const_iterator constEnd() const
const_iterator constBegin() const
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 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.
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.