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