QGIS API Documentation  2.17.0-Master (872e6d2)
qgslayertreemodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreemodel.cpp
3  --------------------------------------
4  Date : May 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 "qgslayertreemodel.h"
17 
18 #include "qgslayertree.h"
19 #include "qgslayertreeutils.h"
21 
22 #include <QMimeData>
23 #include <QTextStream>
24 
25 #include "qgsdataitem.h"
26 #include "qgsmaphittest.h"
27 #include "qgsmaplayerlegend.h"
29 #include "qgspluginlayer.h"
30 #include "qgsrasterlayer.h"
31 #include "qgsrendererv2.h"
32 #include "qgssymbollayerv2utils.h"
33 #include "qgsvectorlayer.h"
34 
36 
41 class EmbeddedWidgetLegendNode : public QgsLayerTreeModelLegendNode
42 {
43  public:
44  EmbeddedWidgetLegendNode( QgsLayerTreeLayer* nodeL )
46  {
47  }
48 
49  virtual QVariant data( int role ) const override
50  {
51  Q_UNUSED( role );
52  return QVariant();
53  }
54 };
55 
57 
59  : QAbstractItemModel( parent )
60  , mRootNode( rootNode )
61  , mFlags( ShowLegend | AllowLegendChangeState | DeferredLegendInvalidation )
62  , mAutoCollapseLegendNodesCount( -1 )
63  , mLegendFilterByScale( 0 )
64  , mLegendFilterUsesExtent( false )
65  , mLegendMapViewMupp( 0 )
66  , mLegendMapViewDpi( 0 )
67  , mLegendMapViewScale( 0 )
68 {
70 
71  mFontLayer.setBold( true );
72 
73  connect( &mDeferLegendInvalidationTimer, SIGNAL( timeout() ), this, SLOT( invalidateLegendMapBasedData() ) );
75 }
76 
78 {
79  legendCleanup();
80 }
81 
83 {
84  if ( !index.isValid() )
85  return mRootNode;
86 
87  QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
88  return qobject_cast<QgsLayerTreeNode*>( obj );
89 }
90 
91 
93 {
94  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
95  return legendNodeRowCount( nodeLegend );
96 
97  QgsLayerTreeNode* n = index2node( parent );
98  if ( !n )
99  return 0;
100 
101  if ( QgsLayerTree::isLayer( n ) )
102  {
103  if ( !testFlag( ShowLegend ) )
104  return 0;
105 
107  }
108 
109  return n->children().count();
110 }
111 
113 {
114  Q_UNUSED( parent );
115  return 1;
116 }
117 
118 QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
119 {
120  if ( column < 0 || column >= columnCount( parent ) ||
121  row < 0 || row >= rowCount( parent ) )
122  return QModelIndex();
123 
124  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
125  return legendNodeIndex( row, column, nodeLegend );
126 
127  QgsLayerTreeNode *n = index2node( parent );
128  if ( !n )
129  return QModelIndex(); // have no children
130 
131  if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
132  {
133  return legendRootIndex( row, column, QgsLayerTree::toLayer( n ) );
134  }
135 
136  return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
137 }
138 
139 
141 {
142  if ( !child.isValid() )
143  return QModelIndex();
144 
145  if ( QgsLayerTreeNode *n = index2node( child ) )
146  {
147  return indexOfParentLayerTreeNode( n->parent() ); // must not be null
148  }
149  else if ( QgsLayerTreeModelLegendNode* legendNode = index2legendNode( child ) )
150  {
151  return legendParent( legendNode );
152  }
153  else
154  {
155  Q_ASSERT( false ); // no other node types!
156  return QModelIndex();
157  }
158 
159 }
160 
161 
163 {
164  Q_ASSERT( parentNode );
165 
166  QgsLayerTreeNode* grandParentNode = parentNode->parent();
167  if ( !grandParentNode )
168  return QModelIndex(); // root node -> invalid index
169 
170  int row = grandParentNode->children().indexOf( parentNode );
171  Q_ASSERT( row >= 0 );
172 
173  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
174 }
175 
176 
178 {
179  if ( !index.isValid() || index.column() > 1 )
180  return QVariant();
181 
182  if ( QgsLayerTreeModelLegendNode* sym = index2legendNode( index ) )
183  return legendNodeData( sym, role );
184 
185  QgsLayerTreeNode* node = index2node( index );
186  if ( role == Qt::DisplayRole || role == Qt::EditRole )
187  {
188  if ( QgsLayerTree::isGroup( node ) )
189  return QgsLayerTree::toGroup( node )->name();
190 
191  if ( QgsLayerTree::isLayer( node ) )
192  {
193  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
194  QString name = nodeLayer->layerName();
195  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
196  {
197  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
198  if ( vlayer && vlayer->featureCount() >= 0 )
199  name += QString( " [%1]" ).arg( vlayer->featureCount() );
200  }
201  return name;
202  }
203  }
204  else if ( role == Qt::DecorationRole && index.column() == 0 )
205  {
206  if ( QgsLayerTree::isGroup( node ) )
207  return iconGroup();
208 
209  if ( QgsLayerTree::isLayer( node ) )
210  {
211  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
212 
213  QgsMapLayer *layer = nodeLayer->layer();
214  if ( !layer )
215  return QVariant();
216 
217  // icons possibly overriding default icon
218  if ( layer->type() == QgsMapLayer::RasterLayer )
219  {
221  {
222  QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
223  return QIcon( QPixmap::fromImage( rlayer->previewAsImage( QSize( 32, 32 ) ) ) );
224  }
225  else
226  {
227  return QgsLayerItem::iconRaster();
228  }
229  }
230 
231  QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer*>( layer );
232  QIcon icon;
233 
234  // if there's just on legend entry that should be embedded in layer - do that!
235  if ( testFlag( ShowLegend ) && legendEmbeddedInParent( nodeLayer ) )
236  {
237  icon = legendIconEmbeddedInParent( nodeLayer );
238  }
239  else if ( vlayer && layer->type() == QgsMapLayer::VectorLayer )
240  {
241  if ( vlayer->geometryType() == QGis::Point )
242  icon = QgsLayerItem::iconPoint();
243  else if ( vlayer->geometryType() == QGis::Line )
244  icon = QgsLayerItem::iconLine();
245  else if ( vlayer->geometryType() == QGis::Polygon )
246  icon = QgsLayerItem::iconPolygon();
247  else if ( vlayer->geometryType() == QGis::NoGeometry )
248  icon = QgsLayerItem::iconTable();
249  else
250  icon = QgsLayerItem::iconDefault();
251  }
252 
253  if ( vlayer && vlayer->isEditable() )
254  {
255  QPixmap pixmap( icon.pixmap( 16, 16 ) );
256 
257  QPainter painter( &pixmap );
258  painter.drawPixmap( 0, 0, 16, 16, QgsApplication::getThemePixmap( vlayer->isModified() ? "/mIconEditableEdits.png" : "/mIconEditable.png" ) );
259  painter.end();
260 
261  icon = QIcon( pixmap );
262  }
263 
264  return icon;
265  }
266  }
267  else if ( role == Qt::CheckStateRole )
268  {
270  return QVariant();
271 
272  if ( QgsLayerTree::isLayer( node ) )
273  {
274  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
275  if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
276  {
277  if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
278  return QVariant(); // do not show checkbox for non-spatial tables
279  }
280  return nodeLayer->isVisible();
281  }
282  else if ( QgsLayerTree::isGroup( node ) )
283  {
284  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
285  return nodeGroup->isVisible();
286  }
287  }
288  else if ( role == Qt::FontRole )
289  {
290  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
291  if ( node->customProperty( "embedded" ).toInt() )
292  f.setItalic( true );
293  if ( index == mCurrentIndex )
294  f.setUnderline( true );
295  return f;
296  }
297  else if ( role == Qt::ForegroundRole )
298  {
299  QBrush brush( Qt::black, Qt::SolidPattern );
300  if ( QgsLayerTree::isLayer( node ) )
301  {
302  const QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer();
303  if ( layer && !layer->isInScaleRange( mLegendMapViewScale ) )
304  {
305  brush.setColor( Qt::lightGray );
306  }
307  }
308  return brush;
309  }
310  else if ( role == Qt::ToolTipRole )
311  {
312  if ( QgsLayerTree::isLayer( node ) )
313  {
314  if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
315  {
316  QString tooltip = "<b>" +
317  ( layer->title().isEmpty() ? layer->shortName() : layer->title() ) + "</b>";
318  if ( !layer->abstract().isEmpty() )
319  tooltip += "<br/>" + layer->abstract().replace( "\n", "<br/>" );
320  tooltip += "<br/><i>" + layer->publicSource() + "</i>";
321  return tooltip;
322  }
323  }
324  }
325 
326  return QVariant();
327 }
328 
329 
331 {
332  if ( !index.isValid() )
333  {
334  Qt::ItemFlags rootFlags = Qt::ItemFlags();
335  if ( testFlag( AllowNodeReorder ) )
336  rootFlags |= Qt::ItemIsDropEnabled;
337  return rootFlags;
338  }
339 
340  if ( QgsLayerTreeModelLegendNode* symn = index2legendNode( index ) )
341  return legendNodeFlags( symn );
342 
343  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
344 
345  if ( testFlag( AllowNodeRename ) )
346  f |= Qt::ItemIsEditable;
347 
348  QgsLayerTreeNode* node = index2node( index );
349  bool isEmbedded = node->customProperty( "embedded" ).toInt();
350 
351  if ( testFlag( AllowNodeReorder ) )
352  {
353  // only root embedded nodes can be reordered
354  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
355  f |= Qt::ItemIsDragEnabled;
356  }
357 
359  f |= Qt::ItemIsUserCheckable;
360 
361  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
362  f |= Qt::ItemIsDropEnabled;
363 
364  return f;
365 }
366 
367 bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
368 {
370  if ( sym )
371  {
372  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
373  return false;
374  bool res = sym->setData( value, role );
375  if ( res )
376  emit dataChanged( index, index );
377  return res;
378  }
379 
380  QgsLayerTreeNode* node = index2node( index );
381  if ( !node )
382  return QgsLayerTreeModel::setData( index, value, role );
383 
384  if ( role == Qt::CheckStateRole )
385  {
387  return false;
388 
389  if ( QgsLayerTree::isLayer( node ) )
390  {
391  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
392  layer->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
393  return true;
394  }
395 
396  if ( QgsLayerTree::isGroup( node ) )
397  {
398  QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
399  group->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
400  return true;
401  }
402 
403  return true;
404  }
405  else if ( role == Qt::EditRole )
406  {
407  if ( !testFlag( AllowNodeRename ) )
408  return false;
409 
410  if ( QgsLayerTree::isLayer( node ) )
411  {
412  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
413  layer->setLayerName( value.toString() );
414  emit dataChanged( index, index );
415  }
416  else if ( QgsLayerTree::isGroup( node ) )
417  {
418  QgsLayerTree::toGroup( node )->setName( value.toString() );
419  emit dataChanged( index, index );
420  }
421  }
422 
423  return QAbstractItemModel::setData( index, value, role );
424 }
425 
427 {
428  if ( !node->parent() )
429  return QModelIndex(); // this is the only root item -> invalid index
430 
431  QModelIndex parentIndex = node2index( node->parent() );
432 
433  int row = node->parent()->children().indexOf( node );
434  Q_ASSERT( row >= 0 );
435  return index( row, 0, parentIndex );
436 }
437 
438 
440 {
441  if ( !child->parent() )
442  return false;
443 
444  if ( child->parent() == node )
445  return true;
446 
447  return _isChildOfNode( child->parent(), node );
448 }
449 
451 {
452  Q_FOREACH ( QgsLayerTreeNode* n, nodes )
453  {
454  if ( _isChildOfNode( child, n ) )
455  return true;
456  }
457 
458  return false;
459 }
460 
461 
462 QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
463 {
465  Q_FOREACH ( const QModelIndex& index, list )
466  {
467  QgsLayerTreeNode* node = index2node( index );
468  if ( !node )
469  continue;
470 
471  nodes << node;
472  }
473 
474  if ( !skipInternal )
475  return nodes;
476 
477  // remove any children of nodes if both parent node and children are selected
478  QList<QgsLayerTreeNode*> nodesFinal;
479  Q_FOREACH ( QgsLayerTreeNode* node, nodes )
480  {
481  if ( !_isChildOfNodes( node, nodes ) )
482  nodesFinal << node;
483  }
484 
485  return nodesFinal;
486 }
487 
489 {
490  return nullptr != index2legendNode( index );
491 }
492 
494 {
495  QgsLayerTreeModelLegendNode* symNode = index2legendNode( index );
496  return symNode ? symNode->layerNode() : nullptr;
497 }
498 
500 {
501  return mRootNode;
502 }
503 
505 {
506  beginResetModel();
507 
509 
510  Q_ASSERT( mLegend.isEmpty() );
511 
512  mRootNode = newRootGroup;
513 
514  endResetModel();
515 
517 }
518 
520 {
521  // update title
522  QModelIndex idx = node2index( nodeLayer );
523  emit dataChanged( idx, idx );
524 
525  // update children
526  int oldNodeCount = rowCount( idx );
527  beginRemoveRows( idx, 0, oldNodeCount - 1 );
528  removeLegendFromLayer( nodeLayer );
529  endRemoveRows();
530 
531  addLegendToLayer( nodeLayer );
532  int newNodeCount = rowCount( idx );
533 
534  // automatic collapse of legend nodes - useful if a layer has many legend nodes
535  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
536  nodeLayer->setExpanded( false );
537 }
538 
540 {
541  return mCurrentIndex;
542 }
543 
545 {
546  QModelIndex oldIndex = mCurrentIndex;
548 
549  if ( oldIndex.isValid() )
550  emit dataChanged( oldIndex, oldIndex );
551  if ( currentIndex.isValid() )
552  emit dataChanged( currentIndex, currentIndex );
553 }
554 
555 
556 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
557 {
558  if ( nodeType == QgsLayerTreeNode::NodeGroup )
559  {
560  if ( mFontGroup != font )
561  {
562  mFontGroup = font;
564  }
565  }
566  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
567  {
568  if ( mFontLayer != font )
569  {
570  mFontLayer = font;
572  }
573  }
574  else
575  {
576  QgsDebugMsg( "invalid node type" );
577  }
578 }
579 
580 
582 {
583  if ( nodeType == QgsLayerTreeNode::NodeGroup )
584  return mFontGroup;
585  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
586  return mFontLayer;
587  else
588  {
589  QgsDebugMsg( "invalid node type" );
590  return QFont();
591  }
592 }
593 
594 void QgsLayerTreeModel::setLegendFilterByScale( double scaleDenominator )
595 {
596  mLegendFilterByScale = scaleDenominator;
597 
598  // this could be later done in more efficient way
599  // by just updating active legend nodes, without refreshing original legend nodes
600  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
601  refreshLayerLegend( nodeLayer );
602 }
603 
605 {
606  setLegendFilter( settings, /* useExtent = */ true );
607 }
608 
609 void QgsLayerTreeModel::setLegendFilter( const QgsMapSettings* settings, bool useExtent, const QgsGeometry& polygon, bool useExpressions )
610 {
611  if ( settings && settings->hasValidSettings() )
612  {
613  mLegendFilterMapSettings.reset( new QgsMapSettings( *settings ) );
614  mLegendFilterMapSettings->setLayerStyleOverrides( mLayerStyleOverrides );
616  mLegendFilterUsesExtent = useExtent;
617  // collect expression filters
618  if ( useExpressions )
619  {
620  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
621  {
622  bool enabled;
623  QString expr = QgsLayerTreeUtils::legendFilterByExpression( *nodeLayer, &enabled );
624  if ( enabled && !expr.isEmpty() )
625  {
626  exprs[ nodeLayer->layerId()] = expr;
627  }
628  }
629  }
630  bool polygonValid = !polygon.isEmpty() && polygon.type() == QGis::Polygon;
631  if ( useExpressions && !useExtent && !polygonValid ) // only expressions
632  {
634  }
635  else
636  {
638  }
639  mLegendFilterHitTest->run();
640  }
641  else
642  {
644  return; // no change
645 
648  }
649 
650  // temporarily disable autocollapse so that legend nodes stay visible
651  int bkAutoCollapse = autoCollapseLegendNodes();
653 
654  // this could be later done in more efficient way
655  // by just updating active legend nodes, without refreshing original legend nodes
656  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
657  refreshLayerLegend( nodeLayer );
658 
659  setAutoCollapseLegendNodes( bkAutoCollapse );
660 }
661 
662 void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
663 {
664  if ( mLegendMapViewDpi == dpi && qgsDoubleNear( mLegendMapViewMupp, mapUnitsPerPixel ) && qgsDoubleNear( mLegendMapViewScale, scale ) )
665  return;
666 
667  mLegendMapViewMupp = mapUnitsPerPixel;
668  mLegendMapViewDpi = dpi;
669  mLegendMapViewScale = scale;
670 
671  // now invalidate legend nodes!
673 
675 }
676 
677 void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale )
678 {
679  if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
680  if ( dpi ) *dpi = mLegendMapViewDpi;
681  if ( scale ) *scale = mLegendMapViewScale;
682 }
683 
685 {
686  return mLayerStyleOverrides;
687 }
688 
690 {
691  mLayerStyleOverrides = overrides;
692 }
693 
694 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
695 {
696  Q_ASSERT( node );
697  beginInsertRows( node2index( node ), indexFrom, indexTo );
698 }
699 
700 static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
701 {
703  QList<QgsLayerTreeLayer*> newLayerNodes;
704  for ( int i = indexFrom; i <= indexTo; ++i )
705  {
706  QgsLayerTreeNode* child = children.at( i );
707  if ( QgsLayerTree::isLayer( child ) )
708  newLayerNodes << QgsLayerTree::toLayer( child );
709  else if ( QgsLayerTree::isGroup( child ) )
710  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
711  }
712  return newLayerNodes;
713 }
714 
715 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
716 {
717  Q_ASSERT( node );
718 
719  endInsertRows();
720 
721  Q_FOREACH ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
722  connectToLayer( newLayerNode );
723 }
724 
725 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
726 {
727  Q_ASSERT( node );
728 
729  beginRemoveRows( node2index( node ), indexFrom, indexTo );
730 
731  // disconnect from layers and remove their legend
732  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
733  disconnectFromLayer( nodeLayer );
734 }
735 
737 {
738  endRemoveRows();
739 }
740 
742 {
743  Q_ASSERT( node );
744 
745  QModelIndex index = node2index( node );
746  emit dataChanged( index, index );
747 }
748 
749 
751 {
752  if ( QgsLayerTree::isLayer( node ) && key == "showFeatureCount" )
754 }
755 
756 
758 {
759  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
760  if ( !nodeLayer )
761  return;
762 
763  // deferred connection to the layer
764  connectToLayer( nodeLayer );
765 }
766 
768 {
769  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
770  if ( !nodeLayer )
771  return;
772 
773  disconnectFromLayer( nodeLayer );
774 
775  // wait for the layer to appear again
776  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
777 }
778 
780 {
781  if ( !testFlag( ShowLegend ) )
782  return;
783 
784  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
785  if ( !layer )
786  return;
787 
788  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
789  if ( !nodeLayer )
790  return;
791 
792  refreshLayerLegend( nodeLayer );
793 }
794 
796 {
797  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
798  if ( !layer )
799  return;
800 
801  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
802  if ( !nodeLayer )
803  return;
804 
805  QModelIndex index = node2index( nodeLayer );
806  emit dataChanged( index, index );
807 
808  if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
809  refreshLayerLegend( nodeLayer );
810 }
811 
812 
814 {
815  QgsLayerTreeModelLegendNode* legendNode = qobject_cast<QgsLayerTreeModelLegendNode*>( sender() );
816  if ( !legendNode )
817  return;
818 
819  QModelIndex index = legendNode2index( legendNode );
820  if ( index.isValid() )
821  emit dataChanged( index, index );
822 }
823 
824 
826 {
827  if ( !nodeLayer->layer() )
828  {
829  // in order to connect to layer, we need to have it loaded.
830  // keep an eye on the layer ID: once loaded, we will use it
831  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
832  return;
833  }
834 
835  // watch if the layer is getting removed
836  connect( nodeLayer, SIGNAL( layerWillBeUnloaded() ), this, SLOT( nodeLayerWillBeUnloaded() ) );
837 
838  if ( testFlag( ShowLegend ) )
839  {
840  addLegendToLayer( nodeLayer );
841 
842  // automatic collapse of legend nodes - useful if a layer has many legend nodes
843  if ( !mRootNode->customProperty( "loading" ).toBool() )
844  {
846  nodeLayer->setExpanded( false );
847  }
848  }
849 
850  QgsMapLayer* layer = nodeLayer->layer();
851  connect( layer, SIGNAL( legendChanged() ), this, SLOT( layerLegendChanged() ), Qt::UniqueConnection );
852 
853  if ( layer->type() == QgsMapLayer::VectorLayer )
854  {
855  // using unique connection because there may be temporarily more nodes for a layer than just one
856  // which would create multiple connections, however disconnect() would disconnect all multiple connections
857  // even if we wanted to disconnect just one connection in each call.
858  connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
859  connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
860  connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
861  connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
862  }
863 }
864 
865 // try to find out if the layer ID is present in the tree multiple times
866 static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
867 {
868  int count = 0;
869  Q_FOREACH ( QgsLayerTreeNode* child, group->children() )
870  {
871  if ( QgsLayerTree::isLayer( child ) )
872  {
873  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
874  count++;
875  }
876  else if ( QgsLayerTree::isGroup( child ) )
877  {
878  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
879  }
880  }
881  return count;
882 }
883 
885 {
886  disconnect( nodeLayer, nullptr, this, nullptr ); // disconnect from delayed load of layer
887 
888  if ( !nodeLayer->layer() )
889  return; // we were never connected
890 
891  if ( testFlag( ShowLegend ) )
892  {
893  removeLegendFromLayer( nodeLayer );
894  }
895 
896  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
897  {
898  // last instance of the layer in the tree: disconnect from all signals from layer!
899  disconnect( nodeLayer->layer(), nullptr, this, nullptr );
900  }
901 }
902 
904 {
905  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
906  {
907  if ( QgsLayerTree::isGroup( node ) )
909  else if ( QgsLayerTree::isLayer( node ) )
911  }
912 }
913 
915 {
916  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
917  {
918  if ( QgsLayerTree::isGroup( node ) )
920  else if ( QgsLayerTree::isLayer( node ) )
922  }
923 }
924 
926 {
927  Q_ASSERT( mRootNode );
928 
929  connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
930  connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
931  connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
932  connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
933  connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
934 
935  connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
936 
938 }
939 
941 {
942  disconnect( mRootNode, nullptr, this, nullptr );
943 
945 }
946 
948 {
949  QgsLayerTreeNode* node = index2node( idx );
950  if ( !node )
951  return;
952 
953  int count = node->children().count();
954  if ( count == 0 )
955  return;
956  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
957  for ( int i = 0; i < count; ++i )
958  recursivelyEmitDataChanged( index( i, 0, idx ) );
959 }
960 
962 {
963  QgsLayerTreeNode* node = index2node( idx );
964  if ( !node )
965  return;
966 
967  if ( node->nodeType() == QgsLayerTreeNode::NodeLayer )
968  {
969  const QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer();
970  if ( layer && layer->hasScaleBasedVisibility() )
971  {
972  emit dataChanged( idx, idx );
973  }
974  }
975  int count = node->children().count();
976  for ( int i = 0; i < count; ++i )
977  refreshScaleBasedLayers( index( i, 0, idx ) );
978 }
979 
981 {
982  return Qt::CopyAction | Qt::MoveAction;
983 }
984 
986 {
987  QStringList types;
988  types << "application/qgis.layertreemodeldata";
989  return types;
990 }
991 
992 
993 QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
994 {
995  // Sort the indexes. Depending on how the user selected the items, the indexes may be unsorted.
996  QModelIndexList sortedIndexes = indexes;
997  qSort( sortedIndexes.begin(), sortedIndexes.end(), qLess<QModelIndex>() );
998 
999  QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( sortedIndexes, true );
1000 
1001  if ( nodesFinal.isEmpty() )
1002  return nullptr;
1003 
1004  QMimeData *mimeData = new QMimeData();
1005 
1006  QDomDocument doc;
1007  QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
1008  Q_FOREACH ( QgsLayerTreeNode* node, nodesFinal )
1009  node->writeXML( rootElem );
1010  doc.appendChild( rootElem );
1011  QString txt = doc.toString();
1012 
1013  mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
1014  return mimeData;
1015 }
1016 
1017 bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
1018 {
1019  if ( action == Qt::IgnoreAction )
1020  return true;
1021 
1022  if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
1023  return false;
1024 
1025  if ( column >= columnCount( parent ) )
1026  return false;
1027 
1028  QgsLayerTreeNode* nodeParent = index2node( parent );
1029  if ( !QgsLayerTree::isGroup( nodeParent ) )
1030  return false;
1031 
1032  QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
1033 
1034  QDomDocument doc;
1035  if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
1036  return false;
1037 
1038  QDomElement rootElem = doc.documentElement();
1039  if ( rootElem.tagName() != "layer_tree_model_data" )
1040  return false;
1041 
1043 
1044  QDomElement elem = rootElem.firstChildElement();
1045  while ( !elem.isNull() )
1046  {
1048  if ( node )
1049  nodes << node;
1050 
1051  elem = elem.nextSiblingElement();
1052  }
1053 
1054  if ( nodes.isEmpty() )
1055  return false;
1056 
1057  if ( parent.isValid() && row == -1 )
1058  row = 0; // if dropped directly onto group item, insert at first position
1059 
1060  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
1061 
1062  return true;
1063 }
1064 
1065 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
1066 {
1067  QgsLayerTreeNode* parentNode = index2node( parent );
1068  if ( QgsLayerTree::isGroup( parentNode ) )
1069  {
1070  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
1071  return true;
1072  }
1073  return false;
1074 }
1075 
1076 void QgsLayerTreeModel::setFlags( const QgsLayerTreeModel::Flags& f )
1077 {
1078  mFlags = f;
1079 }
1080 
1082 {
1083  if ( on )
1084  mFlags |= f;
1085  else
1086  mFlags &= ~f;
1087 }
1088 
1089 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
1090 {
1091  return mFlags;
1092 }
1093 
1095 {
1096  return mFlags.testFlag( f );
1097 }
1098 
1100 {
1101  static QIcon icon;
1102 
1103  if ( icon.isNull() )
1104  icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
1105 
1106  return icon;
1107 }
1108 
1110 {
1112 
1113  if ( mLegendFilterByScale > 0 )
1114  {
1115  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1116  {
1117  if ( node->isScaleOK( mLegendFilterByScale ) )
1118  filtered << node;
1119  }
1120  }
1121  else if ( mLegendFilterMapSettings )
1122  {
1123  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1124  {
1125  QgsSymbolV2* ruleKey = reinterpret_cast< QgsSymbolV2* >( node->data( QgsSymbolV2LegendNode::SymbolV2LegacyRuleKeyRole ).value<void*>() );
1126  bool checked = mLegendFilterUsesExtent || node->data( Qt::CheckStateRole ).toInt() == Qt::Checked;
1127  if ( ruleKey && checked )
1128  {
1130  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( node->layerNode()->layer() ) )
1131  {
1132  if ( mLegendFilterHitTest->legendKeyVisible( ruleKey, vl ) )
1133  filtered << node;
1134  }
1135  }
1136  else // unknown node type or unchecked
1137  filtered << node;
1138  }
1139  }
1140  else
1141  {
1142  return nodes;
1143  }
1144 
1145  return filtered;
1146 }
1147 
1148 
1149 
1151 // Legend nodes routines - start
1152 
1154 {
1155  Q_FOREACH ( const LayerLegendData& data, mLegend )
1156  {
1157  qDeleteAll( data.originalNodes );
1158  delete data.tree;
1159  }
1160  mLegend.clear();
1161 }
1162 
1163 
1165 {
1166  if ( mLegend.contains( nodeLayer ) )
1167  {
1168  qDeleteAll( mLegend[nodeLayer].originalNodes );
1169  delete mLegend[nodeLayer].tree;
1170  mLegend.remove( nodeLayer );
1171  }
1172 }
1173 
1174 
1176 {
1177  if ( !nodeL->layer() )
1178  return;
1179 
1180  QgsMapLayer* ml = nodeL->layer();
1181  QgsMapLayerLegend* layerLegend = ml->legend();
1182  if ( !layerLegend )
1183  return;
1184 
1185  bool hasStyleOverride = mLayerStyleOverrides.contains( ml->id() );
1186  if ( hasStyleOverride )
1188 
1190 
1191  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
1193 
1194  if ( testFlag( UseEmbeddedWidgets ) )
1195  {
1196  // generate placeholder legend nodes that will be replaced by widgets in QgsLayerTreeView
1197  int widgetsCount = ml->customProperty( "embeddedWidgets/count", 0 ).toInt();
1198  while ( widgetsCount > 0 )
1199  {
1200  lstNew.insert( 0, new EmbeddedWidgetLegendNode( nodeL ) );
1201  --widgetsCount;
1202  }
1203  }
1204 
1205  QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
1206 
1207  bool hasOnlyEmbedded = filteredLstNew.count() == 1 && filteredLstNew[0]->isEmbeddedInParent();
1208 
1209  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, lstNew )
1210  {
1211  n->setParent( this );
1212  connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
1213  }
1214 
1216  data.originalNodes = lstNew;
1217  data.activeNodes = filteredLstNew;
1218  data.tree = nullptr;
1219 
1220  // maybe the legend nodes form a tree - try to create a tree structure from the list
1221  if ( testFlag( ShowLegendAsTree ) )
1222  tryBuildLegendTree( data );
1223 
1224  int count = data.tree ? data.tree->children[nullptr].count() : filteredLstNew.count();
1225 
1226  if ( ! hasOnlyEmbedded ) beginInsertRows( node2index( nodeL ), 0, count - 1 );
1227 
1228  mLegend[nodeL] = data;
1229 
1230  if ( ! hasOnlyEmbedded ) endInsertRows();
1231 
1232  if ( hasStyleOverride )
1234 
1235  // invalidate map based data even if the data is not map-based to make sure
1236  // the symbol sizes are computed at least once
1238 }
1239 
1240 
1242 {
1243  // first check whether there are any legend nodes that are not top-level
1244  bool hasParentKeys = false;
1245  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1246  {
1248  {
1249  hasParentKeys = true;
1250  break;
1251  }
1252  }
1253  if ( !hasParentKeys )
1254  return; // all legend nodes are top-level => stick with list representation
1255 
1256  // make mapping from rules to nodes and do some sanity checks
1258  rule2node[QString()] = nullptr;
1259  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1260  {
1262  if ( ruleKey.isEmpty() ) // in tree all nodes must have key
1263  return;
1264  if ( rule2node.contains( ruleKey ) ) // and they must be unique
1265  return;
1266  rule2node[ruleKey] = n;
1267  }
1268 
1269  // create the tree structure
1270  data.tree = new LayerLegendTree;
1271  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1272  {
1274  QgsLayerTreeModelLegendNode* parent = rule2node.value( parentRuleKey, nullptr );
1275  data.tree->parents[n] = parent;
1276  data.tree->children[parent] << n;
1277  }
1278 }
1279 
1280 
1282 {
1283  return qobject_cast<QgsLayerTreeModelLegendNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
1284 }
1285 
1286 
1288 {
1289  const LayerLegendData& data = mLegend[legendNode->layerNode()];
1290  if ( data.tree )
1291  {
1292  if ( QgsLayerTreeModelLegendNode* parentLegendNode = data.tree->parents[legendNode] )
1293  {
1294  QModelIndex parentIndex = legendNode2index( parentLegendNode );
1295  int row = data.tree->children[parentLegendNode].indexOf( legendNode );
1296  return index( row, 0, parentIndex );
1297  }
1298  else
1299  {
1300  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1301  int row = data.tree->children[nullptr].indexOf( legendNode );
1302  return index( row, 0, parentIndex );
1303  }
1304  }
1305 
1306  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1307  Q_ASSERT( parentIndex.isValid() );
1308  int row = data.activeNodes.indexOf( legendNode );
1309  if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
1310  return QModelIndex();
1311  return index( row, 0, parentIndex );
1312 }
1313 
1314 
1316 {
1317  const LayerLegendData& data = mLegend[node->layerNode()];
1318  if ( data.tree )
1319  return data.tree->children[node].count();
1320 
1321  return 0; // they are leaves
1322 }
1323 
1324 
1326 {
1327  if ( !mLegend.contains( nL ) )
1328  return 0;
1329 
1330  const LayerLegendData& data = mLegend[nL];
1331  if ( data.tree )
1332  return data.tree->children[nullptr].count();
1333 
1334  int count = data.activeNodes.count();
1335 
1336  if ( legendEmbeddedInParent( nL ) )
1337  count--; // one item less -- it is embedded in parent
1338 
1339  return count;
1340 }
1341 
1342 
1344 {
1345  Q_ASSERT( mLegend.contains( nL ) );
1346  const LayerLegendData& data = mLegend[nL];
1347  if ( data.tree )
1348  return createIndex( row, column, static_cast<QObject*>( data.tree->children[nullptr].at( row ) ) );
1349 
1350  return createIndex( row, column, static_cast<QObject*>( data.activeNodes.at( row ) ) );
1351 }
1352 
1353 
1355 {
1356  const LayerLegendData& data = mLegend[node->layerNode()];
1357  if ( data.tree )
1358  return createIndex( row, column, static_cast<QObject*>( data.tree->children[node].at( row ) ) );
1359 
1360  return QModelIndex(); // have no children
1361 }
1362 
1363 
1365 {
1366  QgsLayerTreeLayer* layerNode = legendNode->layerNode();
1367  const LayerLegendData& data = mLegend[layerNode];
1368  if ( data.tree )
1369  {
1370  if ( QgsLayerTreeModelLegendNode* parentNode = data.tree->parents[legendNode] )
1371  {
1372  QgsLayerTreeModelLegendNode* grandParentNode = data.tree->parents[parentNode]; // may be null (not a problem)
1373  int row = data.tree->children[grandParentNode].indexOf( parentNode );
1374  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
1375  }
1376  else
1377  return indexOfParentLayerTreeNode( layerNode );
1378  }
1379 
1380  return indexOfParentLayerTreeNode( layerNode );
1381 }
1382 
1383 
1385 {
1386  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
1387  return QVariant();
1388  return node->data( role );
1389 }
1390 
1391 
1393 {
1394  Qt::ItemFlags f = node->flags();
1395  if ( !testFlag( AllowLegendChangeState ) )
1396  f &= ~Qt::ItemIsUserCheckable;
1397  return f;
1398 }
1399 
1400 
1402 {
1403  return legendNodeEmbeddedInParent( nodeLayer );
1404 }
1405 
1407 {
1408  // legend node embedded in parent does not have to be the first one...
1409  // there could be extra legend nodes generated for embedded widgets
1410  const LayerLegendData& data = mLegend[nodeLayer];
1411  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.activeNodes )
1412  {
1413  if ( legendNode->isEmbeddedInParent() )
1414  return legendNode;
1415  }
1416  return nullptr;
1417 }
1418 
1419 
1421 {
1422  QgsLayerTreeModelLegendNode* legendNode = legendNodeEmbeddedInParent( nodeLayer );
1423  if ( !legendNode )
1424  return QIcon();
1425  return QIcon( qvariant_cast<QPixmap>( legendNode->data( Qt::DecorationRole ) ) );
1426 }
1427 
1428 
1430 {
1431  return mLegend.value( nodeLayer ).activeNodes;
1432 }
1433 
1435 {
1436  return mLegend.value( nodeLayer ).originalNodes;
1437 }
1438 
1440 {
1442  for ( ; it != mLegend.constEnd(); ++it )
1443  {
1444  QgsLayerTreeLayer* layer = it.key();
1445  if ( layer->layerId() == layerId )
1446  {
1447  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, mLegend.value( layer ).activeNodes )
1448  {
1449  if ( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() == ruleKey )
1450  {
1451  //found it!
1452  return legendNode;
1453  }
1454  }
1455  }
1456  }
1457 
1458  return nullptr;
1459 }
1460 
1462 {
1465  else
1467 }
1468 
1470 {
1471  QgsDebugCall;
1472 
1473  // we have varying icon sizes, and we want icon to be centered and
1474  // text to be left aligned, so we have to compute the max width of icons
1475  //
1476  // we do that for nodes who share a common parent
1477  //
1478  // we do that here because for symbols with size defined in map units
1479  // the symbol sizes changes depends on the zoom level
1480 
1481  Q_FOREACH ( const LayerLegendData& data, mLegend )
1482  {
1483  QList<QgsSymbolV2LegendNode*> symbolNodes;
1484  QMap<QString, int> widthMax;
1485  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1486  {
1487  QgsSymbolV2LegendNode* n = dynamic_cast<QgsSymbolV2LegendNode*>( legendNode );
1488  if ( n )
1489  {
1490  const QSize sz( n->minimumIconSize() );
1492  widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
1493  n->setIconSize( sz );
1494  symbolNodes.append( n );
1495  }
1496  }
1497  Q_FOREACH ( QgsSymbolV2LegendNode* n, symbolNodes )
1498  {
1500  Q_ASSERT( widthMax[parentKey] > 0 );
1501  const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
1502  n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
1503  }
1504  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1505  legendNode->invalidateMapBasedData();
1506  }
1507 
1508 }
1509 
1510 // Legend nodes routines - end
bool restoreOverrideStyle()
Restore the original store after a call to setOverrideStyle()
int legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
Layer tree group node serves as a container for layers and further groups.
static const QIcon & iconGroup()
void removeChildren(int from, int count)
Remove child nodes from index "from". The nodes will be deleted.
void refreshScaleBasedLayers(const QModelIndex &index=QModelIndex())
Updates layer data for scale dependent layers, should be called when map scale changes.
QList< QgsLayerTreeModelLegendNode * > originalNodes
Data structure for storage of legend nodes.
QModelIndex legendParent(QgsLayerTreeModelLegendNode *legendNode) const
Base class for all map layer types.
Definition: qgsmaplayer.h:49
void setLayerName(const QString &n)
QModelIndex currentIndex() const
Get index of the item marked as current. Item marked as current is underlined.
QMimeData * mimeData(const QModelIndexList &indexes) const override
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer)
Return filtered list of active legend nodes attached to a particular layer node.
QIcon legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Q_DECL_DEPRECATED bool isIndexSymbologyNode(const QModelIndex &index) const
Return true if index represents a legend node (instead of layer node)
QByteArray data(const QString &mimeType) const
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:97
void removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)
void connectToLayer(QgsLayerTreeLayer *nodeLayer)
void setCurrentIndex(const QModelIndex &currentIndex)
Set index of the current item. May be used by view. Item marked as current is underlined.
bool contains(const Key &key) const
QList< QgsLayerTreeNode * > indexes2nodes(const QModelIndexList &list, bool skipInternal=false) const
Convert a list of indexes to a list of layer tree nodes.
LayerLegendTree * tree
Optional pointer to a tree structure - see LayerLegendTree for details.
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
QDomNode appendChild(const QDomNode &newChild)
static const QIcon & iconDefault()
QList< QgsLayerTreeModelLegendNode * > layerOriginalLegendNodes(QgsLayerTreeLayer *nodeLayer)
Return original (unfiltered) list of legend nodes attached to a particular layer node.
void nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)
void addLegendToLayer(QgsLayerTreeLayer *nodeL)
static const QIcon & iconPoint()
Definition: qgsdataitem.cpp:98
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsMapLayer * layer() const
Qt::ItemFlags legendNodeFlags(QgsLayerTreeModelLegendNode *node) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual bool setData(const QVariant &value, int role)
Set some data associated with the item.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
virtual bool hasFormat(const QString &mimeType) const
QString toString(int indent) const
QObject * sender() const
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
static int _numLayerCount(QgsLayerTreeGroup *group, const QString &layerId)
const T & at(int i) const
const QObjectList & children() const
NodeType nodeType()
Find out about type of the node. It is usually shorter to use convenience functions from QgsLayerTree...
bool legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Structure that stores tree representation of map layer&#39;s legend.
void setUnderline(bool enable)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
QDomElement nextSiblingElement(const QString &tagName) const
Flags flags() const
Return OR-ed combination of model flags.
QList< QgsLayerTreeModelLegendNode * > filterLegendNodes(const QList< QgsLayerTreeModelLegendNode * > &nodes)
Filter nodes from QgsMapLayerLegend according to the current filtering rules.
QSize minimumIconSize() const
Get the minimum icon size to prevent cropping.
T value() const
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void recursivelyEmitDataChanged(const QModelIndex &index=QModelIndex())
emit dataChanged() for layer tree node items
static bool _isChildOfNode(QgsLayerTreeNode *child, QgsLayerTreeNode *node)
virtual Qt::ItemFlags flags() const
Return item flags associated with the item.
QDomElement documentElement() const
static const QIcon & iconPolygon()
QVariant legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const
bool mLegendFilterUsesExtent
whether to use map filtering
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Flags mFlags
Set of flags for the model.
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
void tryBuildLegendTree(LayerLegendData &data)
static QPixmap getThemePixmap(const QString &theName)
Helper to get a theme icon as a pixmap.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
virtual void writeXML(QDomElement &parentElement)=0
Write layer tree to XML.
void nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group. No type checking is done - use isGroup() to find out whether this operation is ...
Definition: qgslayertree.h:46
void nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Allow check boxes for legend nodes (if supported by layer&#39;s legend)
QPixmap pixmap(const QSize &size, Mode mode, State state) const
void connectToLayers(QgsLayerTreeGroup *parentGroup)
int & rheight()
void reset(T *other)
The QgsMapSettings class contains configuration for rendering of the map.
int indexOf(const T &value, int from) const
void setBold(bool enable)
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Allow renaming of groups and layers.
const char * name() const
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2...
bool isValid() const
Qt::CheckState isVisible() const
int count(const T &value) const
void append(const T &value)
QString fromUtf8(const char *str, int size)
void disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
QMap< QgsLayerTreeModelLegendNode *, QgsLayerTreeModelLegendNode * > parents
Pointer to parent for each active node. Top-level nodes have null parent. Pointers are not owned...
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
QTimer mDeferLegendInvalidationTimer
int toInt(bool *ok) const
const Key & key() const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Return index for a given legend node.
static const QIcon & iconRaster()
void disconnectFromLayers(QgsLayerTreeGroup *parentGroup)
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
void setLegendFilterByMap(const QgsMapSettings *settings)
Force only display of legend nodes which are valid for given map settings.
int legendRootRowCount(QgsLayerTreeLayer *nL) const
virtual QVariant data(int role) const override
Return data associated with the item.
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
bool isEmpty() const
Qt::DropActions supportedDropActions() const override
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes. Searches recursively the whole sub-tree.
QgsLayerTreeNode * parent()
Get pointer to the parent. If parent is a null pointer, the node is a root node.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
bool isEmpty() const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int autoCollapseLegendNodes() const
Return at what number of legend nodes the layer node should be collapsed. -1 means no auto-collapse (...
void legendMapViewData(double *mapUnitsPerPixel, int *dpi, double *scale)
Get hints about map view - to be used in legend nodes.
void setName(const QString &n)
Set group&#39;s name.
QgsLayerTreeLayer * layerNode() const
Return pointer to the parent layer node.
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
void * internalPointer() const
This class is a base class for nodes in a layer tree.
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
QgsLayerTreeGroup * mRootNode
Pointer to the root node of the layer tree. Not owned by the model.
QString layerId() const
void setVisible(Qt::CheckState visible)
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QMap< QgsLayerTreeModelLegendNode *, QList< QgsLayerTreeModelLegendNode * > > children
List of children for each active node. Top-level nodes are under null pointer key. Pointers are not owned.
static QgsLayerTreeNode * readXML(QDomElement &element)
Read layer tree from XML. Returns new instance.
QString name() const
Get group&#39;s name.
QgsLayerTreeModelLegendNode * findLegendNode(const QString &layerId, const QString &ruleKey) const
Searches through the layer tree to find a legend node with a matching layer ID and rule key...
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
Class that runs a hit test with given map settings.
Definition: qgsmaphittest.h:34
void setLegendFilterByScale(double scaleDenominator)
Force only display of legend nodes which are valid for given scale denominator.
QList< QgsLayerTreeNode * > children()
Get list of children of the node. Children are owned by the parent.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
void setLayerTreeNodeFont(int nodeType, const QFont &font)
Set font for a particular type of layer tree node. nodeType should come from QgsLayerTreeNode::NodeTy...
Qt::CheckState isVisible() const
Return the check state of the group node.
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
void insertChildNodes(int index, const QList< QgsLayerTreeNode * > &nodes)
Insert existing nodes at specified position. The nodes must not have a parent yet. The nodes will be owned by this group.
static void applyLayerNodeProperties(QgsLayerTreeLayer *nodeLayer, QList< QgsLayerTreeModelLegendNode * > &nodes)
update according to layer node&#39;s custom properties (order of items, user labels for items) ...
QModelIndex createIndex(int row, int column, void *ptr) const
QPersistentModelIndex mCurrentIndex
Current index - will be underlined.
#define QgsDebugCall
Definition: qgslogger.h:32
void setRootGroup(QgsLayerTreeGroup *newRootGroup)
Reset the model and use a new root group node.
const T value(const Key &key) const
bool testFlag(Flag f) const
Check whether a flag is enabled.
double mLegendFilterByScale
scale denominator for filtering of legend nodes (<= 0 means no filtering)
void setParent(QObject *parent)
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
void setExpanded(bool expanded)
Set whether the node should be shown as expanded or collapsed in GUI.
void setLegendMapViewData(double mapUnitsPerPixel, int dpi, double scale)
Give the layer tree model hints about the currently associated map view so that legend nodes that use...
void setItalic(bool enable)
void beginInsertRows(const QModelIndex &parent, int first, int last)
QgsMapLayerLegend * legend() const
Can be null.
bool isNull() const
static const QIcon & iconTable()
QModelIndex node2index(QgsLayerTreeNode *node) const
Return index for a given node. If the node does not belong to the layer tree, the result is undefined...
void setAutoCollapseLegendNodes(int nodeCount)
Set at what number of legend nodes the layer node should be collapsed. Setting -1 disables the auto-c...
leaf node pointing to a layer
QImage previewAsImage(QSize size, const QColor &bgColor=Qt::white, QImage::Format format=QImage::Format_ARGB32_Premultiplied)
Draws a preview of the rasterlayer into a QImage.
QString & replace(int position, int n, QChar after)
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
int mAutoCollapseLegendNodesCount
Minimal number of nodes when legend should be automatically collapsed. -1 = disabled.
QModelIndex indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const
QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is ...
Definition: qgslayertree.h:52
typedef DropActions
void insert(int i, const T &value)
Layer nodes may optionally include extra embedded widgets (if used in QgsLayerTreeView). Added in 2.16.
bool isNull() const
QDomElement firstChildElement(const QString &tagName) const
virtual bool isScaleOK(double scale) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QStringList mimeTypes() const override
virtual QVariant data(int role) const =0
Return data associated with the item.
QgsLayerTreeModelLegendNode * legendNodeEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Return legend node that may be embbeded in parent (i.e.
int column() const
static const QIcon & iconLine()
bool toBool() const
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
for QgsSymbolV2LegendNode only - legacy rule key (void ptr, to be cast to QgsSymbolV2 ptr) ...
Allow user to set node visibility with a check box.
void start(int msec)
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
QFont layerTreeNodeFont(int nodeType) const
Get font for a particular type of layer tree node. nodeType should come from QgsLayerTreeNode::NodeTy...
static bool _isChildOfNodes(QgsLayerTreeNode *child, const QList< QgsLayerTreeNode * > &nodes)
bool contains(const Key &key) const
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
QString tagName() const
bool setOverrideStyle(const QString &styleDef)
Temporarily apply a different style to the layer.
void setData(const QString &mimeType, const QByteArray &data)
QScopedPointer< QgsMapHitTest > mLegendFilterHitTest
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Set map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
QDomElement createElement(const QString &tagName)
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Return layer tree node for given index.
container of other groups and layers
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QList< QgsLayerTreeModelLegendNode * > activeNodes
Active legend nodes.
For legends that support it, will show them in a tree instead of a list (needs also ShowLegend)...
QMap< QString, QString > mLayerStyleOverrides
Overrides of map layers&#39; styles: key = layer ID, value = style XML.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString layerName() const
Q_DECL_DEPRECATED QgsLayerTreeLayer * layerNodeForSymbologyNode(const QModelIndex &index) const
Return layer node to which a legend node belongs to.
void setLegendFilter(const QgsMapSettings *settings, bool useExtent=true, const QgsGeometry &polygon=QgsGeometry(), bool useExpressions=true)
Filter display of legend nodes for given map settings.
QObject * parent() const
Represents a vector layer which manages a vector based data sets.
Will use real preview of raster layer as icon (may be slow)
void setVisible(Qt::CheckState state)
Set check state of the group node - will also update children.
void setColor(const QColor &color)
void setFlags(const QgsLayerTreeModel::Flags &f)
Set OR-ed combination of model flags.
QScopedPointer< QgsMapSettings > mLegendFilterMapSettings
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
int count(const Key &key) const
void setIconSize(QSize sz)
Set the icon size.
QModelIndex legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const
static QList< QgsLayerTreeLayer * > _layerNodesInSubtree(QgsLayerTreeNode *node, int indexFrom, int indexTo)
static QString legendFilterByExpression(const QgsLayerTreeLayer &layer, bool *enabled=nullptr)
Return the expression filter of a legend layer.
Allow reordering with drag&#39;n&#39;drop.
Add legend nodes for layer nodes.
virtual void invalidateMapBasedData()
Notification from model that information from associated map view has changed.
void nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
QgsLayerTreeModel(QgsLayerTreeGroup *rootNode, QObject *parent=nullptr)
Construct a new tree model with given layer tree (root node must not be null pointer).
virtual QList< QgsLayerTreeModelLegendNode * > createLayerTreeModelLegendNodes(QgsLayerTreeLayer *nodeLayer)=0
Return list of legend nodes to be used for a particular layer tree layer node.
QMap< QgsLayerTreeLayer *, LayerLegendData > mLegend
Per layer data about layer&#39;s legend nodes.
QModelIndex legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Layer tree node points to a map layer.
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
const T value(const Key &key) const
void setSingleShot(bool singleShot)
void nodeVisibilityChanged(QgsLayerTreeNode *node)
Structure that stores all data associated with one map layer.
typedef ItemFlags
QByteArray toUtf8() const