QGIS API Documentation
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 
35 
37  : QAbstractItemModel( parent )
38  , mRootNode( rootNode )
39  , mFlags( ShowLegend | AllowLegendChangeState | DeferredLegendInvalidation )
40  , mAutoCollapseLegendNodesCount( -1 )
41  , mLegendFilterByScale( 0 )
42  , mLegendFilterUsesExtent( false )
43  , mLegendMapViewMupp( 0 )
44  , mLegendMapViewDpi( 0 )
45  , mLegendMapViewScale( 0 )
46 {
48 
49  mFontLayer.setBold( true );
50 
51  connect( &mDeferLegendInvalidationTimer, SIGNAL( timeout() ), this, SLOT( invalidateLegendMapBasedData() ) );
53 }
54 
56 {
57  legendCleanup();
58 }
59 
61 {
62  if ( !index.isValid() )
63  return mRootNode;
64 
65  QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
66  return qobject_cast<QgsLayerTreeNode*>( obj );
67 }
68 
69 
71 {
72  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
73  return legendNodeRowCount( nodeLegend );
74 
75  QgsLayerTreeNode* n = index2node( parent );
76  if ( !n )
77  return 0;
78 
79  if ( QgsLayerTree::isLayer( n ) )
80  {
81  if ( !testFlag( ShowLegend ) )
82  return 0;
83 
85  }
86 
87  return n->children().count();
88 }
89 
91 {
92  Q_UNUSED( parent );
93  return 1;
94 }
95 
96 QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
97 {
98  if ( column < 0 || column >= columnCount( parent ) ||
99  row < 0 || row >= rowCount( parent ) )
100  return QModelIndex();
101 
102  if ( QgsLayerTreeModelLegendNode* nodeLegend = index2legendNode( parent ) )
103  return legendNodeIndex( row, column, nodeLegend );
104 
105  QgsLayerTreeNode *n = index2node( parent );
106  if ( !n )
107  return QModelIndex(); // have no children
108 
109  if ( testFlag( ShowLegend ) && QgsLayerTree::isLayer( n ) )
110  {
111  return legendRootIndex( row, column, QgsLayerTree::toLayer( n ) );
112  }
113 
114  return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
115 }
116 
117 
119 {
120  if ( !child.isValid() )
121  return QModelIndex();
122 
123  if ( QgsLayerTreeNode *n = index2node( child ) )
124  {
125  return indexOfParentLayerTreeNode( n->parent() ); // must not be null
126  }
127  else if ( QgsLayerTreeModelLegendNode* legendNode = index2legendNode( child ) )
128  {
129  return legendParent( legendNode );
130  }
131  else
132  {
133  Q_ASSERT( false ); // no other node types!
134  return QModelIndex();
135  }
136 
137 }
138 
139 
141 {
142  Q_ASSERT( parentNode );
143 
144  QgsLayerTreeNode* grandParentNode = parentNode->parent();
145  if ( !grandParentNode )
146  return QModelIndex(); // root node -> invalid index
147 
148  int row = grandParentNode->children().indexOf( parentNode );
149  Q_ASSERT( row >= 0 );
150 
151  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
152 }
153 
154 
156 {
157  if ( !index.isValid() || index.column() > 1 )
158  return QVariant();
159 
160  if ( QgsLayerTreeModelLegendNode* sym = index2legendNode( index ) )
161  return legendNodeData( sym, role );
162 
163  QgsLayerTreeNode* node = index2node( index );
164  if ( role == Qt::DisplayRole || role == Qt::EditRole )
165  {
166  if ( QgsLayerTree::isGroup( node ) )
167  return QgsLayerTree::toGroup( node )->name();
168 
169  if ( QgsLayerTree::isLayer( node ) )
170  {
171  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
172  QString name = nodeLayer->layerName();
173  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
174  {
175  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
176  if ( vlayer && vlayer->featureCount() >= 0 )
177  name += QString( " [%1]" ).arg( vlayer->featureCount() );
178  }
179  return name;
180  }
181  }
182  else if ( role == Qt::DecorationRole && index.column() == 0 )
183  {
184  if ( QgsLayerTree::isGroup( node ) )
185  return iconGroup();
186 
187  if ( QgsLayerTree::isLayer( node ) )
188  {
189  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
190 
191  QgsMapLayer *layer = nodeLayer->layer();
192  if ( !layer )
193  return QVariant();
194 
195  // icons possibly overriding default icon
196  if ( layer->type() == QgsMapLayer::RasterLayer )
197  {
199  {
200  QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
201  return QIcon( QPixmap::fromImage( rlayer->previewAsImage( QSize( 32, 32 ) ) ) );
202  }
203  else
204  {
205  return QgsLayerItem::iconRaster();
206  }
207  }
208 
209  QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer*>( layer );
210  QIcon icon;
211 
212  // if there's just on legend entry that should be embedded in layer - do that!
213  if ( testFlag( ShowLegend ) && legendEmbeddedInParent( nodeLayer ) )
214  {
215  icon = legendIconEmbeddedInParent( nodeLayer );
216  }
217  else if ( vlayer && layer->type() == QgsMapLayer::VectorLayer )
218  {
219  if ( vlayer->geometryType() == QGis::Point )
220  icon = QgsLayerItem::iconPoint();
221  else if ( vlayer->geometryType() == QGis::Line )
222  icon = QgsLayerItem::iconLine();
223  else if ( vlayer->geometryType() == QGis::Polygon )
224  icon = QgsLayerItem::iconPolygon();
225  else if ( vlayer->geometryType() == QGis::NoGeometry )
226  icon = QgsLayerItem::iconTable();
227  else
228  icon = QgsLayerItem::iconDefault();
229  }
230 
231  if ( vlayer && vlayer->isEditable() )
232  {
233  QPixmap pixmap( icon.pixmap( 16, 16 ) );
234 
235  QPainter painter( &pixmap );
236  painter.drawPixmap( 0, 0, 16, 16, QgsApplication::getThemePixmap( vlayer->isModified() ? "/mIconEditableEdits.png" : "/mIconEditable.png" ) );
237  painter.end();
238 
239  icon = QIcon( pixmap );
240  }
241 
242  return icon;
243  }
244  }
245  else if ( role == Qt::CheckStateRole )
246  {
248  return QVariant();
249 
250  if ( QgsLayerTree::isLayer( node ) )
251  {
252  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
253  if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
254  {
255  if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
256  return QVariant(); // do not show checkbox for non-spatial tables
257  }
258  return nodeLayer->isVisible();
259  }
260  else if ( QgsLayerTree::isGroup( node ) )
261  {
262  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
263  return nodeGroup->isVisible();
264  }
265  }
266  else if ( role == Qt::FontRole )
267  {
268  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
269  if ( node->customProperty( "embedded" ).toInt() )
270  f.setItalic( true );
271  if ( index == mCurrentIndex )
272  f.setUnderline( true );
273  return f;
274  }
275  else if ( role == Qt::ForegroundRole )
276  {
277  QBrush brush( Qt::black, Qt::SolidPattern );
278  if ( QgsLayerTree::isLayer( node ) )
279  {
280  const QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer();
281  if ( layer && !layer->isInScaleRange( mLegendMapViewScale ) )
282  {
283  brush.setColor( Qt::lightGray );
284  }
285  }
286  return brush;
287  }
288  else if ( role == Qt::ToolTipRole )
289  {
290  if ( QgsLayerTree::isLayer( node ) )
291  {
292  if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
293  {
294  QString tooltip = "<b>" +
295  ( layer->title().isEmpty() ? layer->shortName() : layer->title() ) + "</b>";
296  if ( !layer->abstract().isEmpty() )
297  tooltip += "<br/>" + layer->abstract().replace( "\n", "<br/>" );
298  tooltip += "<br/><i>" + layer->publicSource() + "</i>";
299  return tooltip;
300  }
301  }
302  }
303 
304  return QVariant();
305 }
306 
307 
309 {
310  if ( !index.isValid() )
311  {
312  Qt::ItemFlags rootFlags = nullptr;
313  if ( testFlag( AllowNodeReorder ) )
314  rootFlags |= Qt::ItemIsDropEnabled;
315  return rootFlags;
316  }
317 
318  if ( QgsLayerTreeModelLegendNode* symn = index2legendNode( index ) )
319  return legendNodeFlags( symn );
320 
321  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
322 
323  if ( testFlag( AllowNodeRename ) )
324  f |= Qt::ItemIsEditable;
325 
326  QgsLayerTreeNode* node = index2node( index );
327  bool isEmbedded = node->customProperty( "embedded" ).toInt();
328 
329  if ( testFlag( AllowNodeReorder ) )
330  {
331  // only root embedded nodes can be reordered
332  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
333  f |= Qt::ItemIsDragEnabled;
334  }
335 
337  f |= Qt::ItemIsUserCheckable;
338 
339  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
340  f |= Qt::ItemIsDropEnabled;
341 
342  return f;
343 }
344 
345 bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
346 {
348  if ( sym )
349  {
350  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
351  return false;
352  bool res = sym->setData( value, role );
353  if ( res )
354  emit dataChanged( index, index );
355  return res;
356  }
357 
358  QgsLayerTreeNode* node = index2node( index );
359  if ( !node )
360  return QgsLayerTreeModel::setData( index, value, role );
361 
362  if ( role == Qt::CheckStateRole )
363  {
365  return false;
366 
367  if ( QgsLayerTree::isLayer( node ) )
368  {
369  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
370  layer->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
371  return true;
372  }
373 
374  if ( QgsLayerTree::isGroup( node ) )
375  {
376  QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
377  group->setVisible( static_cast< Qt::CheckState >( value.toInt() ) );
378  return true;
379  }
380 
381  return true;
382  }
383  else if ( role == Qt::EditRole )
384  {
385  if ( !testFlag( AllowNodeRename ) )
386  return false;
387 
388  if ( QgsLayerTree::isLayer( node ) )
389  {
390  QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
391  layer->setLayerName( value.toString() );
392  emit dataChanged( index, index );
393  }
394  else if ( QgsLayerTree::isGroup( node ) )
395  {
396  QgsLayerTree::toGroup( node )->setName( value.toString() );
397  emit dataChanged( index, index );
398  }
399  }
400 
401  return QAbstractItemModel::setData( index, value, role );
402 }
403 
405 {
406  if ( !node->parent() )
407  return QModelIndex(); // this is the only root item -> invalid index
408 
409  QModelIndex parentIndex = node2index( node->parent() );
410 
411  int row = node->parent()->children().indexOf( node );
412  Q_ASSERT( row >= 0 );
413  return index( row, 0, parentIndex );
414 }
415 
416 
418 {
419  if ( !child->parent() )
420  return false;
421 
422  if ( child->parent() == node )
423  return true;
424 
425  return _isChildOfNode( child->parent(), node );
426 }
427 
429 {
430  Q_FOREACH ( QgsLayerTreeNode* n, nodes )
431  {
432  if ( _isChildOfNode( child, n ) )
433  return true;
434  }
435 
436  return false;
437 }
438 
439 
440 QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
441 {
443  Q_FOREACH ( const QModelIndex& index, list )
444  {
445  QgsLayerTreeNode* node = index2node( index );
446  if ( !node )
447  continue;
448 
449  nodes << node;
450  }
451 
452  if ( !skipInternal )
453  return nodes;
454 
455  // remove any children of nodes if both parent node and children are selected
456  QList<QgsLayerTreeNode*> nodesFinal;
457  Q_FOREACH ( QgsLayerTreeNode* node, nodes )
458  {
459  if ( !_isChildOfNodes( node, nodes ) )
460  nodesFinal << node;
461  }
462 
463  return nodesFinal;
464 }
465 
467 {
468  return nullptr != index2legendNode( index );
469 }
470 
472 {
473  QgsLayerTreeModelLegendNode* symNode = index2legendNode( index );
474  return symNode ? symNode->layerNode() : nullptr;
475 }
476 
478 {
479  return mRootNode;
480 }
481 
483 {
484  beginResetModel();
485 
487 
488  Q_ASSERT( mLegend.isEmpty() );
489 
490  mRootNode = newRootGroup;
491 
492  endResetModel();
493 
495 }
496 
498 {
499  // update title
500  QModelIndex idx = node2index( nodeLayer );
501  emit dataChanged( idx, idx );
502 
503  // update children
504  int oldNodeCount = rowCount( idx );
505  beginRemoveRows( idx, 0, oldNodeCount - 1 );
506  removeLegendFromLayer( nodeLayer );
507  endRemoveRows();
508 
509  addLegendToLayer( nodeLayer );
510  int newNodeCount = rowCount( idx );
511 
512  // automatic collapse of legend nodes - useful if a layer has many legend nodes
513  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
514  nodeLayer->setExpanded( false );
515 }
516 
518 {
519  return mCurrentIndex;
520 }
521 
523 {
524  QModelIndex oldIndex = mCurrentIndex;
526 
527  if ( oldIndex.isValid() )
528  emit dataChanged( oldIndex, oldIndex );
529  if ( currentIndex.isValid() )
530  emit dataChanged( currentIndex, currentIndex );
531 }
532 
533 
534 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
535 {
536  if ( nodeType == QgsLayerTreeNode::NodeGroup )
537  {
538  if ( mFontGroup != font )
539  {
540  mFontGroup = font;
542  }
543  }
544  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
545  {
546  if ( mFontLayer != font )
547  {
548  mFontLayer = font;
550  }
551  }
552  else
553  {
554  QgsDebugMsg( "invalid node type" );
555  }
556 }
557 
558 
560 {
561  if ( nodeType == QgsLayerTreeNode::NodeGroup )
562  return mFontGroup;
563  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
564  return mFontLayer;
565  else
566  {
567  QgsDebugMsg( "invalid node type" );
568  return QFont();
569  }
570 }
571 
572 void QgsLayerTreeModel::setLegendFilterByScale( double scaleDenominator )
573 {
574  mLegendFilterByScale = scaleDenominator;
575 
576  // this could be later done in more efficient way
577  // by just updating active legend nodes, without refreshing original legend nodes
578  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
579  refreshLayerLegend( nodeLayer );
580 }
581 
583 {
584  setLegendFilter( settings, /* useExtent = */ true );
585 }
586 
587 void QgsLayerTreeModel::setLegendFilter( const QgsMapSettings* settings, bool useExtent, const QgsGeometry& polygon, bool useExpressions )
588 {
589  if ( settings && settings->hasValidSettings() )
590  {
591  mLegendFilterMapSettings.reset( new QgsMapSettings( *settings ) );
592  mLegendFilterMapSettings->setLayerStyleOverrides( mLayerStyleOverrides );
594  mLegendFilterUsesExtent = useExtent;
595  // collect expression filters
596  if ( useExpressions )
597  {
598  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
599  {
600  bool enabled;
601  QString expr = QgsLayerTreeUtils::legendFilterByExpression( *nodeLayer, &enabled );
602  if ( enabled && !expr.isEmpty() )
603  {
604  exprs[ nodeLayer->layerId()] = expr;
605  }
606  }
607  }
608  bool polygonValid = !polygon.isEmpty() && polygon.type() == QGis::Polygon;
609  if ( useExpressions && !useExtent && !polygonValid ) // only expressions
610  {
612  }
613  else
614  {
616  }
617  mLegendFilterHitTest->run();
618  }
619  else
620  {
622  return; // no change
623 
626  }
627 
628  // temporarily disable autocollapse so that legend nodes stay visible
629  int bkAutoCollapse = autoCollapseLegendNodes();
631 
632  // this could be later done in more efficient way
633  // by just updating active legend nodes, without refreshing original legend nodes
634  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mRootNode->findLayers() )
635  refreshLayerLegend( nodeLayer );
636 
637  setAutoCollapseLegendNodes( bkAutoCollapse );
638 }
639 
640 void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
641 {
642  if ( mLegendMapViewDpi == dpi && qgsDoubleNear( mLegendMapViewMupp, mapUnitsPerPixel ) && qgsDoubleNear( mLegendMapViewScale, scale ) )
643  return;
644 
645  mLegendMapViewMupp = mapUnitsPerPixel;
646  mLegendMapViewDpi = dpi;
647  mLegendMapViewScale = scale;
648 
649  // now invalidate legend nodes!
651 
653 }
654 
655 void QgsLayerTreeModel::legendMapViewData( double* mapUnitsPerPixel, int* dpi, double* scale )
656 {
657  if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
658  if ( dpi ) *dpi = mLegendMapViewDpi;
659  if ( scale ) *scale = mLegendMapViewScale;
660 }
661 
663 {
664  return mLayerStyleOverrides;
665 }
666 
668 {
669  mLayerStyleOverrides = overrides;
670 }
671 
672 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
673 {
674  Q_ASSERT( node );
675  beginInsertRows( node2index( node ), indexFrom, indexTo );
676 }
677 
678 static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
679 {
681  QList<QgsLayerTreeLayer*> newLayerNodes;
682  for ( int i = indexFrom; i <= indexTo; ++i )
683  {
684  QgsLayerTreeNode* child = children.at( i );
685  if ( QgsLayerTree::isLayer( child ) )
686  newLayerNodes << QgsLayerTree::toLayer( child );
687  else if ( QgsLayerTree::isGroup( child ) )
688  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
689  }
690  return newLayerNodes;
691 }
692 
693 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
694 {
695  Q_ASSERT( node );
696 
697  endInsertRows();
698 
699  Q_FOREACH ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
700  connectToLayer( newLayerNode );
701 }
702 
703 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
704 {
705  Q_ASSERT( node );
706 
707  beginRemoveRows( node2index( node ), indexFrom, indexTo );
708 
709  // disconnect from layers and remove their legend
710  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
711  disconnectFromLayer( nodeLayer );
712 }
713 
715 {
716  endRemoveRows();
717 }
718 
720 {
721  Q_ASSERT( node );
722 
723  QModelIndex index = node2index( node );
724  emit dataChanged( index, index );
725 }
726 
727 
729 {
730  if ( QgsLayerTree::isLayer( node ) && key == "showFeatureCount" )
732 }
733 
734 
736 {
737  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
738  if ( !nodeLayer )
739  return;
740 
741  // deferred connection to the layer
742  connectToLayer( nodeLayer );
743 }
744 
746 {
747  QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
748  if ( !nodeLayer )
749  return;
750 
751  disconnectFromLayer( nodeLayer );
752 
753  // wait for the layer to appear again
754  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
755 }
756 
758 {
759  if ( !testFlag( ShowLegend ) )
760  return;
761 
762  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
763  if ( !layer )
764  return;
765 
766  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
767  if ( !nodeLayer )
768  return;
769 
770  refreshLayerLegend( nodeLayer );
771 }
772 
774 {
775  QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
776  if ( !layer )
777  return;
778 
779  QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
780  if ( !nodeLayer )
781  return;
782 
783  QModelIndex index = node2index( nodeLayer );
784  emit dataChanged( index, index );
785 
786  if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
787  refreshLayerLegend( nodeLayer );
788 }
789 
790 
792 {
793  QgsLayerTreeModelLegendNode* legendNode = qobject_cast<QgsLayerTreeModelLegendNode*>( sender() );
794  if ( !legendNode )
795  return;
796 
797  QModelIndex index = legendNode2index( legendNode );
798  if ( index.isValid() )
799  emit dataChanged( index, index );
800 }
801 
802 
804 {
805  if ( !nodeLayer->layer() )
806  {
807  // in order to connect to layer, we need to have it loaded.
808  // keep an eye on the layer ID: once loaded, we will use it
809  connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
810  return;
811  }
812 
813  // watch if the layer is getting removed
814  connect( nodeLayer, SIGNAL( layerWillBeUnloaded() ), this, SLOT( nodeLayerWillBeUnloaded() ) );
815 
816  if ( testFlag( ShowLegend ) )
817  {
818  addLegendToLayer( nodeLayer );
819 
820  // automatic collapse of legend nodes - useful if a layer has many legend nodes
821  if ( !mRootNode->customProperty( "loading" ).toBool() )
822  {
824  nodeLayer->setExpanded( false );
825  }
826  }
827 
828  QgsMapLayer* layer = nodeLayer->layer();
829  connect( layer, SIGNAL( legendChanged() ), this, SLOT( layerLegendChanged() ), Qt::UniqueConnection );
830 
831  if ( layer->type() == QgsMapLayer::VectorLayer )
832  {
833  // using unique connection because there may be temporarily more nodes for a layer than just one
834  // which would create multiple connections, however disconnect() would disconnect all multiple connections
835  // even if we wanted to disconnect just one connection in each call.
836  connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
837  connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
838  connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
839  connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
840  }
841 }
842 
843 // try to find out if the layer ID is present in the tree multiple times
844 static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
845 {
846  int count = 0;
847  Q_FOREACH ( QgsLayerTreeNode* child, group->children() )
848  {
849  if ( QgsLayerTree::isLayer( child ) )
850  {
851  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
852  count++;
853  }
854  else if ( QgsLayerTree::isGroup( child ) )
855  {
856  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
857  }
858  }
859  return count;
860 }
861 
863 {
864  disconnect( nodeLayer, nullptr, this, nullptr ); // disconnect from delayed load of layer
865 
866  if ( !nodeLayer->layer() )
867  return; // we were never connected
868 
869  if ( testFlag( ShowLegend ) )
870  {
871  removeLegendFromLayer( nodeLayer );
872  }
873 
874  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
875  {
876  // last instance of the layer in the tree: disconnect from all signals from layer!
877  disconnect( nodeLayer->layer(), nullptr, this, nullptr );
878  }
879 }
880 
882 {
883  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
884  {
885  if ( QgsLayerTree::isGroup( node ) )
887  else if ( QgsLayerTree::isLayer( node ) )
889  }
890 }
891 
893 {
894  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
895  {
896  if ( QgsLayerTree::isGroup( node ) )
898  else if ( QgsLayerTree::isLayer( node ) )
900  }
901 }
902 
904 {
905  Q_ASSERT( mRootNode );
906 
907  connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
908  connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
909  connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
910  connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
911  connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
912 
913  connect( mRootNode, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
914 
916 }
917 
919 {
920  disconnect( mRootNode, nullptr, this, nullptr );
921 
923 }
924 
926 {
927  QgsLayerTreeNode* node = index2node( idx );
928  if ( !node )
929  return;
930 
931  int count = node->children().count();
932  if ( count == 0 )
933  return;
934  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
935  for ( int i = 0; i < count; ++i )
936  recursivelyEmitDataChanged( index( i, 0, idx ) );
937 }
938 
940 {
941  QgsLayerTreeNode* node = index2node( idx );
942  if ( !node )
943  return;
944 
945  if ( node->nodeType() == QgsLayerTreeNode::NodeLayer )
946  {
947  const QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer();
948  if ( layer && layer->hasScaleBasedVisibility() )
949  {
950  emit dataChanged( idx, idx );
951  }
952  }
953  int count = node->children().count();
954  for ( int i = 0; i < count; ++i )
955  refreshScaleBasedLayers( index( i, 0, idx ) );
956 }
957 
959 {
960  return Qt::CopyAction | Qt::MoveAction;
961 }
962 
964 {
965  QStringList types;
966  types << "application/qgis.layertreemodeldata";
967  return types;
968 }
969 
970 
971 QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
972 {
973  // Sort the indexes. Depending on how the user selected the items, the indexes may be unsorted.
974  QModelIndexList sortedIndexes = indexes;
975  qSort( sortedIndexes.begin(), sortedIndexes.end(), qLess<QModelIndex>() );
976 
977  QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( sortedIndexes, true );
978 
979  if ( nodesFinal.isEmpty() )
980  return nullptr;
981 
982  QMimeData *mimeData = new QMimeData();
983 
984  QDomDocument doc;
985  QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
986  Q_FOREACH ( QgsLayerTreeNode* node, nodesFinal )
987  node->writeXML( rootElem );
988  doc.appendChild( rootElem );
989  QString txt = doc.toString();
990 
991  mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
992  return mimeData;
993 }
994 
995 bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
996 {
997  if ( action == Qt::IgnoreAction )
998  return true;
999 
1000  if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
1001  return false;
1002 
1003  if ( column >= columnCount( parent ) )
1004  return false;
1005 
1006  QgsLayerTreeNode* nodeParent = index2node( parent );
1007  if ( !QgsLayerTree::isGroup( nodeParent ) )
1008  return false;
1009 
1010  QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
1011 
1012  QDomDocument doc;
1013  if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
1014  return false;
1015 
1016  QDomElement rootElem = doc.documentElement();
1017  if ( rootElem.tagName() != "layer_tree_model_data" )
1018  return false;
1019 
1021 
1022  QDomElement elem = rootElem.firstChildElement();
1023  while ( !elem.isNull() )
1024  {
1026  if ( node )
1027  nodes << node;
1028 
1029  elem = elem.nextSiblingElement();
1030  }
1031 
1032  if ( nodes.isEmpty() )
1033  return false;
1034 
1035  if ( parent.isValid() && row == -1 )
1036  row = 0; // if dropped directly onto group item, insert at first position
1037 
1038  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
1039 
1040  return true;
1041 }
1042 
1043 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
1044 {
1045  QgsLayerTreeNode* parentNode = index2node( parent );
1046  if ( QgsLayerTree::isGroup( parentNode ) )
1047  {
1048  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
1049  return true;
1050  }
1051  return false;
1052 }
1053 
1054 void QgsLayerTreeModel::setFlags( const QgsLayerTreeModel::Flags& f )
1055 {
1056  mFlags = f;
1057 }
1058 
1060 {
1061  if ( on )
1062  mFlags |= f;
1063  else
1064  mFlags &= ~f;
1065 }
1066 
1067 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
1068 {
1069  return mFlags;
1070 }
1071 
1073 {
1074  return mFlags.testFlag( f );
1075 }
1076 
1078 {
1079  static QIcon icon;
1080 
1081  if ( icon.isNull() )
1082  icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
1083 
1084  return icon;
1085 }
1086 
1088 {
1090 
1091  if ( mLegendFilterByScale > 0 )
1092  {
1093  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1094  {
1095  if ( node->isScaleOK( mLegendFilterByScale ) )
1096  filtered << node;
1097  }
1098  }
1099  else if ( mLegendFilterMapSettings )
1100  {
1101  Q_FOREACH ( QgsLayerTreeModelLegendNode* node, nodes )
1102  {
1103  QgsSymbolV2* ruleKey = reinterpret_cast< QgsSymbolV2* >( node->data( QgsSymbolV2LegendNode::SymbolV2LegacyRuleKeyRole ).value<void*>() );
1104  bool checked = mLegendFilterUsesExtent || node->data( Qt::CheckStateRole ).toInt() == Qt::Checked;
1105  if ( ruleKey && checked )
1106  {
1108  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( node->layerNode()->layer() ) )
1109  {
1110  if ( mLegendFilterHitTest->legendKeyVisible( ruleKey, vl ) )
1111  filtered << node;
1112  }
1113  }
1114  else // unknown node type or unchecked
1115  filtered << node;
1116  }
1117  }
1118  else
1119  {
1120  return nodes;
1121  }
1122 
1123  return filtered;
1124 }
1125 
1126 
1127 
1129 // Legend nodes routines - start
1130 
1132 {
1133  Q_FOREACH ( const LayerLegendData& data, mLegend )
1134  {
1135  qDeleteAll( data.originalNodes );
1136  delete data.tree;
1137  }
1138  mLegend.clear();
1139 }
1140 
1141 
1143 {
1144  if ( mLegend.contains( nodeLayer ) )
1145  {
1146  qDeleteAll( mLegend[nodeLayer].originalNodes );
1147  delete mLegend[nodeLayer].tree;
1148  mLegend.remove( nodeLayer );
1149  }
1150 }
1151 
1152 
1154 {
1155  if ( !nodeL->layer() )
1156  return;
1157 
1158  QgsMapLayer* ml = nodeL->layer();
1159  QgsMapLayerLegend* layerLegend = ml->legend();
1160  if ( !layerLegend )
1161  return;
1162 
1163  bool hasStyleOverride = mLayerStyleOverrides.contains( ml->id() );
1164  if ( hasStyleOverride )
1166 
1168 
1169  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
1171 
1172  QList<QgsLayerTreeModelLegendNode*> filteredLstNew = filterLegendNodes( lstNew );
1173 
1174  bool isEmbedded = filteredLstNew.count() == 1 && filteredLstNew[0]->isEmbeddedInParent();
1175 
1176  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, lstNew )
1177  {
1178  n->setParent( this );
1179  connect( n, SIGNAL( dataChanged() ), this, SLOT( legendNodeDataChanged() ) );
1180  }
1181 
1183  data.originalNodes = lstNew;
1184  data.activeNodes = filteredLstNew;
1185  data.tree = nullptr;
1186 
1187  // maybe the legend nodes form a tree - try to create a tree structure from the list
1188  if ( testFlag( ShowLegendAsTree ) )
1189  tryBuildLegendTree( data );
1190 
1191  int count = data.tree ? data.tree->children[nullptr].count() : filteredLstNew.count();
1192 
1193  if ( ! isEmbedded ) beginInsertRows( node2index( nodeL ), 0, count - 1 );
1194 
1195  mLegend[nodeL] = data;
1196 
1197  if ( ! isEmbedded ) endInsertRows();
1198 
1199  if ( hasStyleOverride )
1201 
1202  // invalidate map based data even if the data is not map-based to make sure
1203  // the symbol sizes are computed at least once
1205 }
1206 
1207 
1209 {
1210  // first check whether there are any legend nodes that are not top-level
1211  bool hasParentKeys = false;
1212  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1213  {
1215  {
1216  hasParentKeys = true;
1217  break;
1218  }
1219  }
1220  if ( !hasParentKeys )
1221  return; // all legend nodes are top-level => stick with list representation
1222 
1223  // make mapping from rules to nodes and do some sanity checks
1225  rule2node[QString()] = nullptr;
1226  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1227  {
1229  if ( ruleKey.isEmpty() ) // in tree all nodes must have key
1230  return;
1231  if ( rule2node.contains( ruleKey ) ) // and they must be unique
1232  return;
1233  rule2node[ruleKey] = n;
1234  }
1235 
1236  // create the tree structure
1237  data.tree = new LayerLegendTree;
1238  Q_FOREACH ( QgsLayerTreeModelLegendNode* n, data.activeNodes )
1239  {
1241  QgsLayerTreeModelLegendNode* parent = rule2node.value( parentRuleKey, nullptr );
1242  data.tree->parents[n] = parent;
1243  data.tree->children[parent] << n;
1244  }
1245 }
1246 
1247 
1249 {
1250  return qobject_cast<QgsLayerTreeModelLegendNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
1251 }
1252 
1253 
1255 {
1256  const LayerLegendData& data = mLegend[legendNode->layerNode()];
1257  if ( data.tree )
1258  {
1259  if ( QgsLayerTreeModelLegendNode* parentLegendNode = data.tree->parents[legendNode] )
1260  {
1261  QModelIndex parentIndex = legendNode2index( parentLegendNode );
1262  int row = data.tree->children[parentLegendNode].indexOf( legendNode );
1263  return index( row, 0, parentIndex );
1264  }
1265  else
1266  {
1267  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1268  int row = data.tree->children[nullptr].indexOf( legendNode );
1269  return index( row, 0, parentIndex );
1270  }
1271  }
1272 
1273  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1274  Q_ASSERT( parentIndex.isValid() );
1275  int row = data.activeNodes.indexOf( legendNode );
1276  if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
1277  return QModelIndex();
1278  return index( row, 0, parentIndex );
1279 }
1280 
1281 
1283 {
1284  const LayerLegendData& data = mLegend[node->layerNode()];
1285  if ( data.tree )
1286  return data.tree->children[node].count();
1287 
1288  return 0; // they are leaves
1289 }
1290 
1291 
1293 {
1294  if ( legendEmbeddedInParent( nL ) )
1295  return 0;
1296 
1297  if ( !mLegend.contains( nL ) )
1298  return 0;
1299 
1300  const LayerLegendData& data = mLegend[nL];
1301  if ( data.tree )
1302  return data.tree->children[nullptr].count();
1303 
1304  return data.activeNodes.count();
1305 }
1306 
1307 
1309 {
1310  Q_ASSERT( mLegend.contains( nL ) );
1311  const LayerLegendData& data = mLegend[nL];
1312  if ( data.tree )
1313  return createIndex( row, column, static_cast<QObject*>( data.tree->children[nullptr].at( row ) ) );
1314 
1315  return createIndex( row, column, static_cast<QObject*>( data.activeNodes.at( row ) ) );
1316 }
1317 
1318 
1320 {
1321  const LayerLegendData& data = mLegend[node->layerNode()];
1322  if ( data.tree )
1323  return createIndex( row, column, static_cast<QObject*>( data.tree->children[node].at( row ) ) );
1324 
1325  return QModelIndex(); // have no children
1326 }
1327 
1328 
1330 {
1331  QgsLayerTreeLayer* layerNode = legendNode->layerNode();
1332  const LayerLegendData& data = mLegend[layerNode];
1333  if ( data.tree )
1334  {
1335  if ( QgsLayerTreeModelLegendNode* parentNode = data.tree->parents[legendNode] )
1336  {
1337  QgsLayerTreeModelLegendNode* grandParentNode = data.tree->parents[parentNode]; // may be null (not a problem)
1338  int row = data.tree->children[grandParentNode].indexOf( parentNode );
1339  return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
1340  }
1341  else
1342  return indexOfParentLayerTreeNode( layerNode );
1343  }
1344 
1345  return indexOfParentLayerTreeNode( layerNode );
1346 }
1347 
1348 
1350 {
1351  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
1352  return QVariant();
1353  return node->data( role );
1354 }
1355 
1356 
1358 {
1359  Qt::ItemFlags f = node->flags();
1360  if ( !testFlag( AllowLegendChangeState ) )
1361  f &= ~Qt::ItemIsUserCheckable;
1362  return f;
1363 }
1364 
1365 
1367 {
1368  const LayerLegendData& data = mLegend[nodeLayer];
1369  return data.activeNodes.count() == 1 && data.activeNodes[0]->isEmbeddedInParent();
1370 }
1371 
1372 
1374 {
1375  return QIcon( qvariant_cast<QPixmap>( mLegend[nodeLayer].activeNodes[0]->data( Qt::DecorationRole ) ) );
1376 }
1377 
1378 
1380 {
1381  return mLegend.value( nodeLayer ).activeNodes;
1382 }
1383 
1385 {
1386  return mLegend.value( nodeLayer ).originalNodes;
1387 }
1388 
1390 {
1392  for ( ; it != mLegend.constEnd(); ++it )
1393  {
1394  QgsLayerTreeLayer* layer = it.key();
1395  if ( layer->layerId() == layerId )
1396  {
1397  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, mLegend.value( layer ).activeNodes )
1398  {
1399  if ( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() == ruleKey )
1400  {
1401  //found it!
1402  return legendNode;
1403  }
1404  }
1405  }
1406  }
1407 
1408  return nullptr;
1409 }
1410 
1412 {
1415  else
1417 }
1418 
1420 {
1421  QgsDebugCall;
1422 
1423  // we have varying icon sizes, and we want icon to be centered and
1424  // text to be left aligned, so we have to compute the max width of icons
1425  //
1426  // we do that for nodes who share a common parent
1427  //
1428  // we do that here because for symbols with size defined in map units
1429  // the symbol sizes changes depends on the zoom level
1430 
1431  Q_FOREACH ( const LayerLegendData& data, mLegend )
1432  {
1433  QList<QgsSymbolV2LegendNode*> symbolNodes;
1434  QMap<QString, int> widthMax;
1435  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1436  {
1437  QgsSymbolV2LegendNode* n = dynamic_cast<QgsSymbolV2LegendNode*>( legendNode );
1438  if ( n )
1439  {
1440  const QSize sz( n->minimumIconSize() );
1442  widthMax[parentKey] = qMax( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
1443  n->setIconSize( sz );
1444  symbolNodes.append( n );
1445  }
1446  }
1447  Q_FOREACH ( QgsSymbolV2LegendNode* n, symbolNodes )
1448  {
1450  Q_ASSERT( widthMax[parentKey] > 0 );
1451  const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
1452  n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
1453  }
1454  Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, data.originalNodes )
1455  legendNode->invalidateMapBasedData();
1456  }
1457 
1458 }
1459 
1460 // 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.
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:348
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...
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
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.
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