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