QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 "qgsapplication.h"
22 #include "qgslayertree.h"
23 #include "qgslayertreeutils.h"
25 #include "qgsproject.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 
213  break;
214  }
215 
216  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
217  QIcon icon;
218 
219  // if there's just on legend entry that should be embedded in layer - do that!
220  if ( testFlag( ShowLegend ) && legendEmbeddedInParent( nodeLayer ) )
221  {
222  icon = legendIconEmbeddedInParent( nodeLayer );
223  }
224  else if ( vlayer && layer->type() == QgsMapLayerType::VectorLayer )
225  {
226  if ( vlayer->geometryType() == QgsWkbTypes::PointGeometry )
227  icon = QgsLayerItem::iconPoint();
228  else if ( vlayer->geometryType() == QgsWkbTypes::LineGeometry )
229  icon = QgsLayerItem::iconLine();
230  else if ( vlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
231  icon = QgsLayerItem::iconPolygon();
232  else if ( vlayer->geometryType() == QgsWkbTypes::NullGeometry )
233  icon = QgsLayerItem::iconTable();
234  else
235  icon = QgsLayerItem::iconDefault();
236  }
237 
238  if ( vlayer && vlayer->isEditable() && testFlag( UseTextFormatting ) )
239  {
240  const int iconSize = scaleIconSize( 16 );
241  QPixmap pixmap( icon.pixmap( iconSize, iconSize ) );
242 
243  QPainter painter( &pixmap );
244  painter.drawPixmap( 0, 0, iconSize, iconSize, QgsApplication::getThemePixmap( vlayer->isModified() ? QStringLiteral( "/mIconEditableEdits.svg" ) : QStringLiteral( "/mActionToggleEditing.svg" ) ) );
245  painter.end();
246 
247  icon = QIcon( pixmap );
248  }
249 
250  return icon;
251  }
252  }
253  else if ( role == Qt::CheckStateRole )
254  {
256  return QVariant();
257 
258  if ( QgsLayerTree::isLayer( node ) )
259  {
260  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
261 
262  if ( nodeLayer->layer() && !nodeLayer->layer()->isSpatial() )
263  return QVariant(); // do not show checkbox for non-spatial tables
264 
265  return nodeLayer->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked;
266  }
267  else if ( QgsLayerTree::isGroup( node ) )
268  {
269  QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
270  return nodeGroup->itemVisibilityChecked() ? Qt::Checked : Qt::Unchecked;
271  }
272  }
273  else if ( role == Qt::FontRole && testFlag( UseTextFormatting ) )
274  {
275  QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
276  if ( index == mCurrentIndex )
277  f.setUnderline( true );
278  if ( QgsLayerTree::isLayer( node ) )
279  {
280  const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
281  if ( ( !node->isVisible() && ( !layer || layer->isSpatial() ) ) || ( layer && !layer->isInScaleRange( mLegendMapViewScale ) ) )
282  {
283  f.setItalic( !f.italic() );
284  }
285  }
286  return f;
287  }
288  else if ( role == Qt::ForegroundRole && testFlag( UseTextFormatting ) )
289  {
290  QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
291  if ( QgsLayerTree::isLayer( node ) )
292  {
293  const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
294  if ( ( !node->isVisible() && ( !layer || layer->isSpatial() ) ) || ( layer && !layer->isInScaleRange( mLegendMapViewScale ) ) )
295  {
296  QColor fadedTextColor = brush.color();
297  fadedTextColor.setAlpha( 128 );
298  brush.setColor( fadedTextColor );
299  }
300  }
301  return brush;
302  }
303  else if ( role == Qt::ToolTipRole )
304  {
305  if ( QgsLayerTree::isLayer( node ) )
306  {
307  if ( QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer() )
308  {
309  QString title =
310  !layer->title().isEmpty() ? layer->title() :
311  !layer->shortName().isEmpty() ? layer->shortName() :
312  layer->name();
313 
314  title = "<b>" + title.toHtmlEscaped() + "</b>";
315 
316  if ( layer->isSpatial() && layer->crs().isValid() )
317  {
318  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
319  title += tr( " (%1 - %2)" ).arg( QgsWkbTypes::displayString( vl->wkbType() ), layer->crs().authid() ).toHtmlEscaped();
320  else
321  title += tr( " (%1)" ).arg( layer->crs().authid() ).toHtmlEscaped();
322  }
323 
324  QStringList parts;
325  parts << title;
326 
327  if ( !layer->abstract().isEmpty() )
328  {
329  parts << QString();
330  const QStringList abstractLines = layer->abstract().split( '\n' );
331  for ( const auto &l : abstractLines )
332  {
333  parts << l.toHtmlEscaped();
334  }
335  parts << QString();
336  }
337 
338  QString source( layer->publicSource() );
339  if ( source.size() > 1024 )
340  {
341  source = source.left( 1023 ) + QString( QChar( 0x2026 ) );
342  }
343 
344  parts << "<i>" + source.toHtmlEscaped() + "</i>";
345 
346  return parts.join( QLatin1String( "<br/>" ) );
347  }
348  }
349  }
350 
351  return QVariant();
352 }
353 
354 
355 Qt::ItemFlags QgsLayerTreeModel::flags( const QModelIndex &index ) const
356 {
357  if ( !index.isValid() )
358  {
359  Qt::ItemFlags rootFlags = Qt::ItemFlags();
360  if ( testFlag( AllowNodeReorder ) )
361  rootFlags |= Qt::ItemIsDropEnabled;
362  return rootFlags;
363  }
364 
366  return legendNodeFlags( symn );
367 
368  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
369 
370  if ( testFlag( AllowNodeRename ) )
371  f |= Qt::ItemIsEditable;
372 
373  QgsLayerTreeNode *node = index2node( index );
374  bool isEmbedded = node->customProperty( QStringLiteral( "embedded" ) ).toInt();
375 
376  if ( testFlag( AllowNodeReorder ) )
377  {
378  // only root embedded nodes can be reordered
379  if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( QStringLiteral( "embedded" ) ).toInt() ) )
380  f |= Qt::ItemIsDragEnabled;
381  }
382 
384  f |= Qt::ItemIsUserCheckable;
385 
386  if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
387  f |= Qt::ItemIsDropEnabled;
388 
389  return f;
390 }
391 
392 bool QgsLayerTreeModel::setData( const QModelIndex &index, const QVariant &value, int role )
393 {
395  if ( sym )
396  {
397  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
398  return false;
399  bool res = sym->setData( value, role );
400  if ( res )
401  emit dataChanged( index, index );
402  return res;
403  }
404 
405  QgsLayerTreeNode *node = index2node( index );
406  if ( !node )
407  return QAbstractItemModel::setData( index, value, role );
408 
409  if ( role == Qt::CheckStateRole )
410  {
412  return false;
413 
414  bool checked = static_cast< Qt::CheckState >( value.toInt() ) == Qt::Checked;
415  if ( checked && node->children().isEmpty() )
416  {
418  }
419  else if ( testFlag( ActionHierarchical ) )
420  {
421  if ( node->children().isEmpty() )
423  else
424  node->setItemVisibilityCheckedRecursive( checked );
425  }
426  else
427  {
428  node->setItemVisibilityChecked( checked );
429  }
430 
432 
433  return true;
434  }
435  else if ( role == Qt::EditRole )
436  {
437  if ( !testFlag( AllowNodeRename ) )
438  return false;
439 
440  if ( QgsLayerTree::isLayer( node ) )
441  {
442  QgsLayerTreeLayer *layer = QgsLayerTree::toLayer( node );
443  layer->setName( value.toString() );
444  emit dataChanged( index, index );
445  }
446  else if ( QgsLayerTree::isGroup( node ) )
447  {
448  QgsLayerTree::toGroup( node )->setName( value.toString() );
449  emit dataChanged( index, index );
450  }
451  }
452 
453  return QAbstractItemModel::setData( index, value, role );
454 }
455 
457 {
458  if ( !node || !node->parent() )
459  return QModelIndex(); // this is the only root item -> invalid index
460 
461  QModelIndex parentIndex = node2index( node->parent() );
462 
463  int row = node->parent()->children().indexOf( node );
464  Q_ASSERT( row >= 0 );
465  return index( row, 0, parentIndex );
466 }
467 
468 
469 static bool _isChildOfNode( QgsLayerTreeNode *child, QgsLayerTreeNode *node )
470 {
471  if ( !child->parent() )
472  return false;
473 
474  if ( child->parent() == node )
475  return true;
476 
477  return _isChildOfNode( child->parent(), node );
478 }
479 
480 static bool _isChildOfNodes( QgsLayerTreeNode *child, const QList<QgsLayerTreeNode *> &nodes )
481 {
482  for ( QgsLayerTreeNode *n : nodes )
483  {
484  if ( _isChildOfNode( child, n ) )
485  return true;
486  }
487 
488  return false;
489 }
490 
491 
492 QList<QgsLayerTreeNode *> QgsLayerTreeModel::indexes2nodes( const QModelIndexList &list, bool skipInternal ) const
493 {
494  QList<QgsLayerTreeNode *> nodes;
495  const auto constList = list;
496  for ( const QModelIndex &index : constList )
497  {
498  QgsLayerTreeNode *node = index2node( index );
499  if ( !node )
500  continue;
501 
502  nodes << node;
503  }
504 
505  if ( !skipInternal )
506  return nodes;
507 
508  // remove any children of nodes if both parent node and children are selected
509  QList<QgsLayerTreeNode *> nodesFinal;
510  for ( QgsLayerTreeNode *node : qgis::as_const( nodes ) )
511  {
512  if ( !_isChildOfNodes( node, nodes ) )
513  nodesFinal << node;
514  }
515 
516  return nodesFinal;
517 }
518 
520 {
521  return mRootNode;
522 }
523 
525 {
526  beginResetModel();
527 
529 
530  Q_ASSERT( mLegend.isEmpty() );
531 
532  mRootNode = newRootGroup;
533 
534  endResetModel();
535 
537 }
538 
540 {
541  // update title
542  QModelIndex idx = node2index( nodeLayer );
543  emit dataChanged( idx, idx );
544 
545  // update children
546  int oldNodeCount = rowCount( idx );
547  if ( oldNodeCount > 0 )
548  {
549  beginRemoveRows( idx, 0, oldNodeCount - 1 );
550  removeLegendFromLayer( nodeLayer );
551  endRemoveRows();
552  }
553 
554  addLegendToLayer( nodeLayer );
555  int newNodeCount = rowCount( idx );
556 
557  // automatic collapse of legend nodes - useful if a layer has many legend nodes
558  if ( mAutoCollapseLegendNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseLegendNodesCount )
559  nodeLayer->setExpanded( false );
560 }
561 
563 {
564  return mCurrentIndex;
565 }
566 
567 void QgsLayerTreeModel::setCurrentIndex( const QModelIndex &currentIndex )
568 {
569  QModelIndex oldIndex = mCurrentIndex;
571 
572  if ( oldIndex.isValid() )
573  emit dataChanged( oldIndex, oldIndex );
574  if ( currentIndex.isValid() )
575  emit dataChanged( currentIndex, currentIndex );
576 }
577 
578 
579 void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont &font )
580 {
581  if ( nodeType == QgsLayerTreeNode::NodeGroup )
582  {
583  if ( mFontGroup != font )
584  {
585  mFontGroup = font;
587  }
588  }
589  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
590  {
591  if ( mFontLayer != font )
592  {
593  mFontLayer = font;
595  }
596  }
597  else
598  {
599  QgsDebugMsgLevel( QStringLiteral( "invalid node type" ), 4 );
600  }
601 }
602 
603 
604 QFont QgsLayerTreeModel::layerTreeNodeFont( int nodeType ) const
605 {
606  if ( nodeType == QgsLayerTreeNode::NodeGroup )
607  return mFontGroup;
608  else if ( nodeType == QgsLayerTreeNode::NodeLayer )
609  return mFontLayer;
610  else
611  {
612  QgsDebugMsgLevel( QStringLiteral( "invalid node type" ), 4 );
613  return QFont();
614  }
615 }
616 
618 {
619  mLegendFilterByScale = scale;
620 
621  // this could be later done in more efficient way
622  // by just updating active legend nodes, without refreshing original legend nodes
623  const auto layers = mRootNode->findLayers();
624  for ( QgsLayerTreeLayer *nodeLayer : layers )
625  refreshLayerLegend( nodeLayer );
626 }
627 
629 {
630  setLegendFilter( settings, /* useExtent = */ true );
631 }
632 
633 void QgsLayerTreeModel::setLegendFilter( const QgsMapSettings *settings, bool useExtent, const QgsGeometry &polygon, bool useExpressions )
634 {
635  if ( settings && settings->hasValidSettings() )
636  {
637  mLegendFilterMapSettings.reset( new QgsMapSettings( *settings ) );
638  mLegendFilterMapSettings->setLayerStyleOverrides( mLayerStyleOverrides );
640  mLegendFilterUsesExtent = useExtent;
641  // collect expression filters
642  if ( useExpressions )
643  {
644  const auto layers = mRootNode->findLayers();
645  for ( QgsLayerTreeLayer *nodeLayer : layers )
646  {
647  bool enabled;
648  QString expr = QgsLayerTreeUtils::legendFilterByExpression( *nodeLayer, &enabled );
649  if ( enabled && !expr.isEmpty() )
650  {
651  exprs[ nodeLayer->layerId()] = expr;
652  }
653  }
654  }
655  bool polygonValid = !polygon.isNull() && polygon.type() == QgsWkbTypes::PolygonGeometry;
656  if ( useExpressions && !useExtent && !polygonValid ) // only expressions
657  {
659  }
660  else
661  {
662  mLegendFilterHitTest.reset( new QgsMapHitTest( *mLegendFilterMapSettings, polygon, exprs ) );
663  }
664  mLegendFilterHitTest->run();
665  }
666  else
667  {
669  return; // no change
670 
671  mLegendFilterMapSettings.reset();
672  mLegendFilterHitTest.reset();
673  }
674 
675  // temporarily disable autocollapse so that legend nodes stay visible
676  int bkAutoCollapse = autoCollapseLegendNodes();
678 
679  // this could be later done in more efficient way
680  // by just updating active legend nodes, without refreshing original legend nodes
681  const auto layers = mRootNode->findLayers();
682  for ( QgsLayerTreeLayer *nodeLayer : layers )
683  refreshLayerLegend( nodeLayer );
684 
685  setAutoCollapseLegendNodes( bkAutoCollapse );
686 }
687 
688 void QgsLayerTreeModel::setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale )
689 {
690  if ( mLegendMapViewDpi == dpi && qgsDoubleNear( mLegendMapViewMupp, mapUnitsPerPixel ) && qgsDoubleNear( mLegendMapViewScale, scale ) )
691  return;
692 
693  double previousScale = mLegendMapViewScale;
694  mLegendMapViewScale = scale;
695  mLegendMapViewMupp = mapUnitsPerPixel;
696  mLegendMapViewDpi = dpi;
697 
698  // now invalidate legend nodes!
700 
701  if ( scale != previousScale )
702  refreshScaleBasedLayers( QModelIndex(), previousScale );
703 }
704 
705 void QgsLayerTreeModel::legendMapViewData( double *mapUnitsPerPixel, int *dpi, double *scale ) const
706 {
707  if ( mapUnitsPerPixel ) *mapUnitsPerPixel = mLegendMapViewMupp;
708  if ( dpi ) *dpi = mLegendMapViewDpi;
709  if ( scale ) *scale = mLegendMapViewScale;
710 }
711 
712 QMap<QString, QString> QgsLayerTreeModel::layerStyleOverrides() const
713 {
714  return mLayerStyleOverrides;
715 }
716 
717 void QgsLayerTreeModel::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
718 {
719  mLayerStyleOverrides = overrides;
720 }
721 
722 int QgsLayerTreeModel::scaleIconSize( int standardSize )
723 {
724  return QgsApplication::scaleIconSize( standardSize, true );
725 }
726 
727 void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
728 {
729  Q_ASSERT( node );
730  beginInsertRows( node2index( node ), indexFrom, indexTo );
731 }
732 
733 static QList<QgsLayerTreeLayer *> _layerNodesInSubtree( QgsLayerTreeNode *node, int indexFrom, int indexTo )
734 {
735  QList<QgsLayerTreeNode *> children = node->children();
736  QList<QgsLayerTreeLayer *> newLayerNodes;
737  for ( int i = indexFrom; i <= indexTo; ++i )
738  {
739  QgsLayerTreeNode *child = children.at( i );
740  if ( QgsLayerTree::isLayer( child ) )
741  newLayerNodes << QgsLayerTree::toLayer( child );
742  else if ( QgsLayerTree::isGroup( child ) )
743  newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
744  }
745  return newLayerNodes;
746 }
747 
748 void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
749 {
750  Q_ASSERT( node );
751 
752  endInsertRows();
753 
754  const auto subNodes = _layerNodesInSubtree( node, indexFrom, indexTo );
755  for ( QgsLayerTreeLayer *newLayerNode : subNodes )
756  connectToLayer( newLayerNode );
757 }
758 
759 void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
760 {
761  Q_ASSERT( node );
762 
763  beginRemoveRows( node2index( node ), indexFrom, indexTo );
764 
765  // disconnect from layers and remove their legend
766  const auto subNodes = _layerNodesInSubtree( node, indexFrom, indexTo );
767  for ( QgsLayerTreeLayer *nodeLayer : subNodes )
768  disconnectFromLayer( nodeLayer );
769 }
770 
772 {
773  endRemoveRows();
774 }
775 
777 {
778  Q_ASSERT( node );
779 
780  QModelIndex index = node2index( node );
781  emit dataChanged( index, index );
782 }
783 
784 void QgsLayerTreeModel::nodeNameChanged( QgsLayerTreeNode *node, const QString &name )
785 {
786  Q_UNUSED( name )
787  Q_ASSERT( node );
788 
789  QModelIndex index = node2index( node );
790  emit dataChanged( index, index );
791 }
792 
793 
795 {
796  if ( QgsLayerTree::isLayer( node ) && key == QLatin1String( "showFeatureCount" ) )
798 }
799 
800 
802 {
803  QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() );
804  if ( !nodeLayer )
805  return;
806 
807  // deferred connection to the layer
808  connectToLayer( nodeLayer );
809 }
810 
812 {
813  QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() );
814  if ( !nodeLayer )
815  return;
816 
817  disconnectFromLayer( nodeLayer );
818 
819  // wait for the layer to appear again
821 }
822 
824 {
825  if ( !mRootNode )
826  return;
827 
828  if ( !testFlag( ShowLegend ) )
829  return;
830 
831  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
832  if ( !layer )
833  return;
834 
835  QgsLayerTreeLayer *nodeLayer = mRootNode->findLayer( layer->id() );
836  if ( !nodeLayer )
837  return;
838 
839  refreshLayerLegend( nodeLayer );
840 }
841 
843 {
844  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
845  if ( !layer )
846  return;
847 
848  QgsLayerTreeLayer *nodeLayer = mRootNode->findLayer( layer->id() );
849  if ( !nodeLayer )
850  return;
851 
852  QModelIndex index = node2index( nodeLayer );
853  emit dataChanged( index, index );
854 
855  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ) ).toInt() )
856  refreshLayerLegend( nodeLayer );
857 }
858 
859 
861 {
862  QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( sender() );
863  if ( !legendNode )
864  return;
865 
866  QModelIndex index = legendNode2index( legendNode );
867  if ( index.isValid() )
868  emit dataChanged( index, index );
869 }
870 
871 void QgsLayerTreeModel::legendNodeSizeChanged()
872 {
873  QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( sender() );
874  if ( !legendNode )
875  return;
876 
877  QModelIndex index = legendNode2index( legendNode );
878  if ( index.isValid() )
879  emit dataChanged( index, index, QVector<int> { Qt::SizeHintRole } );
880 }
881 
882 
884 {
885  if ( !nodeLayer->layer() )
886  {
887  // in order to connect to layer, we need to have it loaded.
888  // keep an eye on the layer ID: once loaded, we will use it
890  return;
891  }
892 
893  // watch if the layer is getting removed
895 
896  if ( testFlag( ShowLegend ) )
897  {
898  addLegendToLayer( nodeLayer );
899 
900  // automatic collapse of legend nodes - useful if a layer has many legend nodes
901  if ( !mRootNode->customProperty( QStringLiteral( "loading" ) ).toBool() )
902  {
904  nodeLayer->setExpanded( false );
905  }
906  }
907 
908  QgsMapLayer *layer = nodeLayer->layer();
909  connect( layer, &QgsMapLayer::legendChanged, this, &QgsLayerTreeModel::layerLegendChanged, Qt::UniqueConnection );
910 
911  if ( layer->type() == QgsMapLayerType::VectorLayer )
912  {
913  // using unique connection because there may be temporarily more nodes for a layer than just one
914  // which would create multiple connections, however disconnect() would disconnect all multiple connections
915  // even if we wanted to disconnect just one connection in each call.
916  QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer );
917  connect( vl, &QgsVectorLayer::editingStarted, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
918  connect( vl, &QgsVectorLayer::editingStopped, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
919  connect( vl, &QgsVectorLayer::layerModified, this, &QgsLayerTreeModel::layerNeedsUpdate, Qt::UniqueConnection );
920  }
921 }
922 
923 // try to find out if the layer ID is present in the tree multiple times
924 static int _numLayerCount( QgsLayerTreeGroup *group, const QString &layerId )
925 {
926  int count = 0;
927  const auto constChildren = group->children();
928  for ( QgsLayerTreeNode *child : constChildren )
929  {
930  if ( QgsLayerTree::isLayer( child ) )
931  {
932  if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
933  count++;
934  }
935  else if ( QgsLayerTree::isGroup( child ) )
936  {
937  count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
938  }
939  }
940  return count;
941 }
942 
944 {
945  disconnect( nodeLayer, nullptr, this, nullptr ); // disconnect from delayed load of layer
946 
947  if ( !nodeLayer->layer() )
948  return; // we were never connected
949 
950  if ( testFlag( ShowLegend ) )
951  {
952  removeLegendFromLayer( nodeLayer );
953  }
954 
955  if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
956  {
957  // last instance of the layer in the tree: disconnect from all signals from layer!
958  disconnect( nodeLayer->layer(), nullptr, this, nullptr );
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  const auto constChildren = parentGroup->children();
977  for ( QgsLayerTreeNode *node : constChildren )
978  {
979  if ( QgsLayerTree::isGroup( node ) )
981  else if ( QgsLayerTree::isLayer( node ) )
983  }
984 }
985 
987 {
988  Q_ASSERT( mRootNode );
989 
996 
998 
1000 }
1001 
1003 {
1004  disconnect( mRootNode, nullptr, this, nullptr );
1005 
1007 }
1008 
1010 {
1011  QgsLayerTreeNode *node = index2node( idx );
1012  if ( !node )
1013  return;
1014 
1015  int count = node->children().count();
1016  if ( count == 0 )
1017  return;
1018  emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
1019  for ( int i = 0; i < count; ++i )
1020  recursivelyEmitDataChanged( index( i, 0, idx ) );
1021 }
1022 
1023 void QgsLayerTreeModel::refreshScaleBasedLayers( const QModelIndex &idx, double previousScale )
1024 {
1025  QgsLayerTreeNode *node = index2node( idx );
1026  if ( !node )
1027  return;
1028 
1029  if ( node->nodeType() == QgsLayerTreeNode::NodeLayer )
1030  {
1031  const QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
1032  if ( layer && layer->hasScaleBasedVisibility() )
1033  {
1034  if ( layer->isInScaleRange( mLegendMapViewScale ) != layer->isInScaleRange( previousScale ) )
1035  emit dataChanged( idx, idx, QVector<int>() << Qt::FontRole << Qt::ForegroundRole );
1036  }
1037  }
1038  int count = node->children().count();
1039  for ( int i = 0; i < count; ++i )
1040  refreshScaleBasedLayers( index( i, 0, idx ), previousScale );
1041 }
1042 
1044 {
1045  return Qt::CopyAction | Qt::MoveAction;
1046 }
1047 
1048 QStringList QgsLayerTreeModel::mimeTypes() const
1049 {
1050  QStringList types;
1051  types << QStringLiteral( "application/qgis.layertreemodeldata" );
1052  return types;
1053 }
1054 
1055 
1056 QMimeData *QgsLayerTreeModel::mimeData( const QModelIndexList &indexes ) const
1057 {
1058  // Sort the indexes. Depending on how the user selected the items, the indexes may be unsorted.
1059  QModelIndexList sortedIndexes = indexes;
1060  std::sort( sortedIndexes.begin(), sortedIndexes.end(), std::less<QModelIndex>() );
1061 
1062  QList<QgsLayerTreeNode *> nodesFinal = indexes2nodes( sortedIndexes, true );
1063 
1064  if ( nodesFinal.isEmpty() )
1065  return nullptr;
1066 
1067  QMimeData *mimeData = new QMimeData();
1068 
1069  QDomDocument layerTreeDoc;
1070  QDomElement rootLayerTreeElem = layerTreeDoc.createElement( QStringLiteral( "layer_tree_model_data" ) );
1071 
1072  for ( QgsLayerTreeNode *node : qgis::as_const( nodesFinal ) )
1073  {
1074  node->writeXml( rootLayerTreeElem, QgsReadWriteContext() );
1075  }
1076  layerTreeDoc.appendChild( rootLayerTreeElem );
1077 
1078  QString errorMessage;
1079  QgsReadWriteContext readWriteContext;
1080  QDomDocument layerDefinitionsDoc( QStringLiteral( "qgis-layer-definition" ) );
1081  QgsLayerDefinition::exportLayerDefinition( layerDefinitionsDoc, nodesFinal, errorMessage, QgsReadWriteContext() );
1082 
1083  QString txt = layerDefinitionsDoc.toString();
1084 
1085  mimeData->setData( QStringLiteral( "application/qgis.layertreemodeldata" ), layerTreeDoc.toString().toUtf8() );
1086  mimeData->setData( QStringLiteral( "application/qgis.application.pid" ), QString::number( QCoreApplication::applicationPid() ).toUtf8() );
1087  mimeData->setData( QStringLiteral( "application/qgis.layertree.layerdefinitions" ), txt.toUtf8() );
1088  mimeData->setData( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ), QgsMimeDataUtils::layerTreeNodesToUriList( nodesFinal ) );
1089 
1090  return mimeData;
1091 }
1092 
1093 bool QgsLayerTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1094 {
1095  if ( action == Qt::IgnoreAction )
1096  return true;
1097 
1098  if ( !data->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) )
1099  return false;
1100 
1101  if ( column >= columnCount( parent ) )
1102  return false;
1103 
1104  QgsLayerTreeNode *nodeParent = index2node( parent );
1105  if ( !QgsLayerTree::isGroup( nodeParent ) )
1106  return false;
1107 
1108  if ( parent.isValid() && row == -1 )
1109  row = 0; // if dropped directly onto group item, insert at first position
1110 
1111  // if we are coming from another QGIS instance, we need to add the layers too
1112  bool ok = false;
1113  // the application pid is only provided from QGIS 3.14, so do not check to OK before defaulting to moving in the legend
1114  qint64 qgisPid = data->data( QStringLiteral( "application/qgis.application.pid" ) ).toInt( &ok );
1115 
1116  if ( ok && qgisPid != QCoreApplication::applicationPid() )
1117  {
1118  QByteArray encodedLayerDefinitionData = data->data( QStringLiteral( "application/qgis.layertree.layerdefinitions" ) );
1119  QDomDocument layerDefinitionDoc;
1120  if ( !layerDefinitionDoc.setContent( QString::fromUtf8( encodedLayerDefinitionData ) ) )
1121  return false;
1122  QgsReadWriteContext context;
1123  QString errorMessage;
1124  QgsLayerDefinition::loadLayerDefinition( layerDefinitionDoc, QgsProject::instance(), QgsLayerTree::toGroup( nodeParent ), errorMessage, context );
1125  emit messageEmitted( tr( "New layers added from another QGIS instance" ) );
1126  }
1127  else
1128  {
1129  QByteArray encodedLayerTreeData = data->data( QStringLiteral( "application/qgis.layertreemodeldata" ) );
1130 
1131  QDomDocument layerTreeDoc;
1132  if ( !layerTreeDoc.setContent( QString::fromUtf8( encodedLayerTreeData ) ) )
1133  return false;
1134 
1135  QDomElement rootLayerTreeElem = layerTreeDoc.documentElement();
1136  if ( rootLayerTreeElem.tagName() != QLatin1String( "layer_tree_model_data" ) )
1137  return false;
1138 
1139  QList<QgsLayerTreeNode *> nodes;
1140 
1141  QDomElement elem = rootLayerTreeElem.firstChildElement();
1142  while ( !elem.isNull() )
1143  {
1145  if ( node )
1146  nodes << node;
1147 
1148  elem = elem.nextSiblingElement();
1149  }
1150 
1151  if ( nodes.isEmpty() )
1152  return false;
1153 
1154  QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
1155  }
1156  return true;
1157 }
1158 
1159 bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex &parent )
1160 {
1161  QgsLayerTreeNode *parentNode = index2node( parent );
1162  if ( QgsLayerTree::isGroup( parentNode ) )
1163  {
1164  QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
1165  return true;
1166  }
1167  return false;
1168 }
1169 
1170 void QgsLayerTreeModel::setFlags( QgsLayerTreeModel::Flags f )
1171 {
1172  mFlags = f;
1173 }
1174 
1176 {
1177  if ( on )
1178  mFlags |= f;
1179  else
1180  mFlags &= ~f;
1181 }
1182 
1183 QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
1184 {
1185  return mFlags;
1186 }
1187 
1189 {
1190  return mFlags.testFlag( f );
1191 }
1192 
1194 {
1195  return QgsApplication::getThemeIcon( QStringLiteral( "/mActionFolder.svg" ) );
1196 }
1197 
1198 QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::filterLegendNodes( const QList<QgsLayerTreeModelLegendNode *> &nodes )
1199 {
1200  QList<QgsLayerTreeModelLegendNode *> filtered;
1201 
1202  if ( mLegendFilterByScale > 0 )
1203  {
1204  for ( QgsLayerTreeModelLegendNode *node : qgis::as_const( nodes ) )
1205  {
1206  if ( node->isScaleOK( mLegendFilterByScale ) )
1207  filtered << node;
1208  }
1209  }
1210  else if ( mLegendFilterMapSettings )
1211  {
1212  if ( !nodes.isEmpty() && mLegendFilterMapSettings->layers().contains( nodes.at( 0 )->layerNode()->layer() ) )
1213  {
1214  for ( QgsLayerTreeModelLegendNode *node : qgis::as_const( nodes ) )
1215  {
1216  QString ruleKey = node->data( QgsSymbolLegendNode::RuleKeyRole ).toString();
1217  bool checked = mLegendFilterUsesExtent || node->data( Qt::CheckStateRole ).toInt() == Qt::Checked;
1218  if ( checked )
1219  {
1220  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( node->layerNode()->layer() ) )
1221  {
1222  if ( mLegendFilterHitTest->legendKeyVisible( ruleKey, vl ) )
1223  filtered << node;
1224  }
1225  else
1226  {
1227  filtered << node;
1228  }
1229  }
1230  else // unknown node type or unchecked
1231  filtered << node;
1232  }
1233  }
1234  }
1235  else
1236  {
1237  return nodes;
1238  }
1239 
1240  return filtered;
1241 }
1242 
1243 
1244 
1246 // Legend nodes routines - start
1247 
1249 {
1250  const auto constMLegend = mLegend;
1251  for ( const LayerLegendData &data : constMLegend )
1252  {
1253  qDeleteAll( data.originalNodes );
1254  delete data.tree;
1255  }
1256  mLegend.clear();
1257 }
1258 
1259 
1261 {
1262  if ( mLegend.contains( nodeLayer ) )
1263  {
1264  qDeleteAll( mLegend[nodeLayer].originalNodes );
1265  delete mLegend[nodeLayer].tree;
1266  mLegend.remove( nodeLayer );
1267  }
1268 }
1269 
1270 
1272 {
1273  if ( !nodeL || !nodeL->layer() )
1274  return;
1275 
1276  QgsMapLayer *ml = nodeL->layer();
1277 
1278  QgsMapLayerStyleOverride styleOverride( ml );
1279  if ( mLayerStyleOverrides.contains( ml->id() ) )
1280  styleOverride.setOverrideStyle( mLayerStyleOverrides.value( ml->id() ) );
1281 
1282  QgsMapLayerLegend *layerLegend = ml->legend();
1283  if ( !layerLegend )
1284  return;
1285  QList<QgsLayerTreeModelLegendNode *> lstNew = layerLegend->createLayerTreeModelLegendNodes( nodeL );
1286 
1287  // apply filtering defined in layer node's custom properties (reordering, filtering, custom labels)
1289 
1290  if ( testFlag( UseEmbeddedWidgets ) )
1291  {
1292  // generate placeholder legend nodes that will be replaced by widgets in QgsLayerTreeView
1293  int widgetsCount = ml->customProperty( QStringLiteral( "embeddedWidgets/count" ), 0 ).toInt();
1294  while ( widgetsCount > 0 )
1295  {
1296  lstNew.insert( 0, new EmbeddedWidgetLegendNode( nodeL ) );
1297  --widgetsCount;
1298  }
1299  }
1300 
1301  QList<QgsLayerTreeModelLegendNode *> filteredLstNew = filterLegendNodes( lstNew );
1302 
1303  const auto constLstNew = lstNew;
1304  for ( QgsLayerTreeModelLegendNode *n : constLstNew )
1305  {
1306  n->setParent( this );
1308  connect( n, &QgsLayerTreeModelLegendNode::sizeChanged, this, &QgsLayerTreeModel::legendNodeSizeChanged );
1309  }
1310 
1311  // See if we have an embedded node - if we do, we will not use it among active nodes.
1312  // Legend node embedded in parent does not have to be the first one,
1313  // there can be also nodes generated for embedded widgets
1314  QgsLayerTreeModelLegendNode *embeddedNode = nullptr;
1315  const auto constFilteredLstNew = filteredLstNew;
1316  for ( QgsLayerTreeModelLegendNode *legendNode : constFilteredLstNew )
1317  {
1318  if ( legendNode->isEmbeddedInParent() )
1319  {
1320  embeddedNode = legendNode;
1321  filteredLstNew.removeOne( legendNode );
1322  break;
1323  }
1324  }
1325 
1326  LayerLegendTree *legendTree = nullptr;
1327 
1328  // maybe the legend nodes form a tree - try to create a tree structure from the list
1329  if ( testFlag( ShowLegendAsTree ) )
1330  legendTree = tryBuildLegendTree( filteredLstNew );
1331 
1332  int count = legendTree ? legendTree->children[nullptr].count() : filteredLstNew.count();
1333 
1334  if ( !filteredLstNew.isEmpty() )
1335  beginInsertRows( node2index( nodeL ), 0, count - 1 );
1336 
1338  data.originalNodes = lstNew;
1339  data.activeNodes = filteredLstNew;
1340  data.embeddedNodeInParent = embeddedNode;
1341  data.tree = legendTree;
1342 
1343  mLegend[nodeL] = data;
1344 
1345  if ( !filteredLstNew.isEmpty() )
1346  endInsertRows();
1347 
1348  // invalidate map based data even if the data is not map-based to make sure
1349  // the symbol sizes are computed at least once
1350  mInvalidatedNodes.insert( nodeL );
1352 }
1353 
1354 
1355 QgsLayerTreeModel::LayerLegendTree *QgsLayerTreeModel::tryBuildLegendTree( const QList<QgsLayerTreeModelLegendNode *> &nodes )
1356 {
1357  // first check whether there are any legend nodes that are not top-level
1358  bool hasParentKeys = false;
1359  for ( QgsLayerTreeModelLegendNode *n : nodes )
1360  {
1361  if ( !n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString().isEmpty() )
1362  {
1363  hasParentKeys = true;
1364  break;
1365  }
1366  }
1367  if ( !hasParentKeys )
1368  return nullptr; // all legend nodes are top-level => stick with list representation
1369 
1370  // make mapping from rules to nodes and do some sanity checks
1371  QHash<QString, QgsLayerTreeModelLegendNode *> rule2node;
1372  rule2node[QString()] = nullptr;
1373  for ( QgsLayerTreeModelLegendNode *n : nodes )
1374  {
1375  QString ruleKey = n->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
1376  if ( ruleKey.isEmpty() ) // in tree all nodes must have key
1377  return nullptr;
1378  if ( rule2node.contains( ruleKey ) ) // and they must be unique
1379  return nullptr;
1380  rule2node[ruleKey] = n;
1381  }
1382 
1383  // create the tree structure
1384  LayerLegendTree *tree = new LayerLegendTree;
1385  for ( QgsLayerTreeModelLegendNode *n : nodes )
1386  {
1387  QString parentRuleKey = n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString();
1388  QgsLayerTreeModelLegendNode *parent = rule2node.value( parentRuleKey, nullptr );
1389  tree->parents[n] = parent;
1390  tree->children[parent] << n;
1391  }
1392  return tree;
1393 }
1394 
1395 QgsRenderContext *QgsLayerTreeModel::createTemporaryRenderContext() const
1396 {
1397  double scale = 0.0;
1398  double mupp = 0.0;
1399  int dpi = 0;
1400  legendMapViewData( &mupp, &dpi, &scale );
1401  bool validData = !qgsDoubleNear( mupp, 0.0 ) && dpi != 0 && !qgsDoubleNear( scale, 0.0 );
1402 
1403  // setup temporary render context
1404  std::unique_ptr<QgsRenderContext> context( new QgsRenderContext );
1405  context->setScaleFactor( dpi / 25.4 );
1406  context->setRendererScale( scale );
1407  context->setMapToPixel( QgsMapToPixel( mupp ) );
1408  context->setFlag( QgsRenderContext::RenderSymbolPreview );
1409  return validData ? context.release() : nullptr;
1410 }
1411 
1412 
1414 {
1415  return qobject_cast<QgsLayerTreeModelLegendNode *>( reinterpret_cast<QObject *>( index.internalPointer() ) );
1416 }
1417 
1418 
1420 {
1422  if ( data.tree )
1423  {
1424  if ( QgsLayerTreeModelLegendNode *parentLegendNode = data.tree->parents[legendNode] )
1425  {
1426  QModelIndex parentIndex = legendNode2index( parentLegendNode );
1427  int row = data.tree->children[parentLegendNode].indexOf( legendNode );
1428  return index( row, 0, parentIndex );
1429  }
1430  else
1431  {
1432  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1433  int row = data.tree->children[nullptr].indexOf( legendNode );
1434  return index( row, 0, parentIndex );
1435  }
1436  }
1437 
1438  QModelIndex parentIndex = node2index( legendNode->layerNode() );
1439  Q_ASSERT( parentIndex.isValid() );
1440  int row = data.activeNodes.indexOf( legendNode );
1441  if ( row < 0 ) // legend node may be filtered (exists within the list of original nodes, but not in active nodes)
1442  return QModelIndex();
1443 
1444  return index( row, 0, parentIndex );
1445 }
1446 
1447 
1449 {
1450  const LayerLegendData &data = mLegend[node->layerNode()];
1451  if ( data.tree )
1452  return data.tree->children[node].count();
1453 
1454  return 0; // they are leaves
1455 }
1456 
1457 
1459 {
1460  if ( !mLegend.contains( nL ) )
1461  return 0;
1462 
1463  const LayerLegendData &data = mLegend[nL];
1464  if ( data.tree )
1465  return data.tree->children[nullptr].count();
1466 
1467  int count = data.activeNodes.count();
1468  return count;
1469 }
1470 
1471 
1472 QModelIndex QgsLayerTreeModel::legendRootIndex( int row, int column, QgsLayerTreeLayer *nL ) const
1473 {
1474  Q_ASSERT( mLegend.contains( nL ) );
1475  const LayerLegendData &data = mLegend[nL];
1476  if ( data.tree )
1477  return createIndex( row, column, static_cast<QObject *>( data.tree->children[nullptr].at( row ) ) );
1478 
1479  return createIndex( row, column, static_cast<QObject *>( data.activeNodes.at( row ) ) );
1480 }
1481 
1482 
1483 QModelIndex QgsLayerTreeModel::legendNodeIndex( int row, int column, QgsLayerTreeModelLegendNode *node ) const
1484 {
1485  const LayerLegendData &data = mLegend[node->layerNode()];
1486  if ( data.tree )
1487  return createIndex( row, column, static_cast<QObject *>( data.tree->children[node].at( row ) ) );
1488 
1489  return QModelIndex(); // have no children
1490 }
1491 
1492 
1494 {
1495  QgsLayerTreeLayer *layerNode = legendNode->layerNode();
1496  const LayerLegendData &data = mLegend[layerNode];
1497  if ( data.tree )
1498  {
1499  if ( QgsLayerTreeModelLegendNode *parentNode = data.tree->parents[legendNode] )
1500  {
1501  QgsLayerTreeModelLegendNode *grandParentNode = data.tree->parents[parentNode]; // may be null (not a problem)
1502  int row = data.tree->children[grandParentNode].indexOf( parentNode );
1503  return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
1504  }
1505  else
1506  return indexOfParentLayerTreeNode( layerNode );
1507  }
1508 
1509  return indexOfParentLayerTreeNode( layerNode );
1510 }
1511 
1512 
1514 {
1515  if ( role == Qt::CheckStateRole && !testFlag( AllowLegendChangeState ) )
1516  return QVariant();
1517  return node->data( role );
1518 }
1519 
1520 
1522 {
1523  Qt::ItemFlags f = node->flags();
1524  if ( !testFlag( AllowLegendChangeState ) )
1525  f &= ~Qt::ItemIsUserCheckable;
1526  return f;
1527 }
1528 
1529 
1531 {
1532  return static_cast< bool >( mLegend[nodeLayer].embeddedNodeInParent );
1533 }
1534 
1536 {
1537  return mLegend[nodeLayer].embeddedNodeInParent;
1538 }
1539 
1540 
1542 {
1543  QgsLayerTreeModelLegendNode *legendNode = mLegend[nodeLayer].embeddedNodeInParent;
1544  if ( !legendNode )
1545  return QIcon();
1546  return QIcon( qvariant_cast<QPixmap>( legendNode->data( Qt::DecorationRole ) ) );
1547 }
1548 
1549 
1550 QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent )
1551 {
1552  if ( !mLegend.contains( nodeLayer ) )
1553  return QList<QgsLayerTreeModelLegendNode *>();
1554 
1555  const LayerLegendData &data = mLegend[nodeLayer];
1556  QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
1557  if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
1558  lst.prepend( data.embeddedNodeInParent );
1559  return lst;
1560 }
1561 
1562 QList<QgsLayerTreeModelLegendNode *> QgsLayerTreeModel::layerOriginalLegendNodes( QgsLayerTreeLayer *nodeLayer )
1563 {
1564  return mLegend.value( nodeLayer ).originalNodes;
1565 }
1566 
1567 QgsLayerTreeModelLegendNode *QgsLayerTreeModel::findLegendNode( const QString &layerId, const QString &ruleKey ) const
1568 {
1569  for ( auto it = mLegend.constBegin(); it != mLegend.constEnd(); ++it )
1570  {
1571  QgsLayerTreeLayer *layer = it.key();
1572  if ( layer->layerId() == layerId )
1573  {
1574  const auto activeNodes = mLegend.value( layer ).activeNodes;
1575  for ( QgsLayerTreeModelLegendNode *legendNode : activeNodes )
1576  {
1577  if ( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() == ruleKey )
1578  {
1579  //found it!
1580  return legendNode;
1581  }
1582  }
1583  }
1584  }
1585 
1586  return nullptr;
1587 }
1588 
1590 {
1593  else
1594  mDeferLegendInvalidationTimer.start( 10 );
1595 }
1596 
1598 {
1599  // we have varying icon sizes, and we want icon to be centered and
1600  // text to be left aligned, so we have to compute the max width of icons
1601  //
1602  // we do that for nodes which share a common parent
1603  //
1604  // we do that here because for symbols with size defined in map units
1605  // the symbol sizes changes depends on the zoom level
1606 
1607  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
1608 
1609  for ( QgsLayerTreeLayer *layerNode : qgis::as_const( mInvalidatedNodes ) )
1610  {
1611  const LayerLegendData &data = mLegend.value( layerNode );
1612 
1613  QList<QgsSymbolLegendNode *> symbolNodes;
1614  QMap<QString, int> widthMax;
1615  for ( QgsLayerTreeModelLegendNode *legendNode : qgis::as_const( data.originalNodes ) )
1616  {
1617  QgsSymbolLegendNode *n = qobject_cast<QgsSymbolLegendNode *>( legendNode );
1618  if ( n )
1619  {
1620  const QSize sz( n->minimumIconSize( context.get() ) );
1621  const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() );
1622  widthMax[parentKey] = std::max( sz.width(), widthMax.contains( parentKey ) ? widthMax[parentKey] : 0 );
1623  n->setIconSize( sz );
1624  symbolNodes.append( n );
1625  }
1626  }
1627  for ( QgsSymbolLegendNode *n : qgis::as_const( symbolNodes ) )
1628  {
1629  const QString parentKey( n->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString() );
1630  Q_ASSERT( widthMax[parentKey] > 0 );
1631  const int twiceMarginWidth = 2; // a one pixel margin avoids hugly rendering of icon
1632  n->setIconSize( QSize( widthMax[parentKey] + twiceMarginWidth, n->iconSize().rheight() + twiceMarginWidth ) );
1633  }
1634  for ( QgsLayerTreeModelLegendNode *legendNode : qgis::as_const( data.originalNodes ) )
1636  }
1637 
1638  mInvalidatedNodes.clear();
1639 }
1640 
1641 // 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:717
QgsLayerTreeModel::columnCount
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgslayertreemodel.cpp:93
QgsLayerTreeModel::mFontGroup
QFont mFontGroup
Definition: qgslayertreemodel.h:445
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:59
QgsLayerTreeGroup::findLayers
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Definition: qgslayertreegroup.cpp:223
QgsLayerTreeModel::nodeLayerLoaded
void nodeLayerLoaded()
Definition: qgslayertreemodel.cpp:801
QgsLayerTreeModel::nodeWillRemoveChildren
void nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Definition: qgslayertreemodel.cpp:759
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:1002
QgsLayerTreeNode
This class is a base class for nodes in a layer tree.
Definition: qgslayertreenode.h:75
QgsLayerTreeModel::currentIndex
QModelIndex currentIndex() const
Gets index of the item marked as current. Item marked as current is underlined.
Definition: qgslayertreemodel.cpp:562
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:1521
QgsWkbTypes::displayString
static QString displayString(Type type) SIP_HOLDGIL
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
Definition: qgswkbtypes.cpp:145
QgsLayerTreeModel::nodeLayerWillBeUnloaded
void nodeLayerWillBeUnloaded()
Definition: qgslayertreemodel.cpp:811
QgsLayerTreeModel::addLegendToLayer
void addLegendToLayer(QgsLayerTreeLayer *nodeL)
Definition: qgslayertreemodel.cpp:1271
QgsLayerTreeModel::tryBuildLegendTree
LayerLegendTree * tryBuildLegendTree(const QList< QgsLayerTreeModelLegendNode * > &nodes)
Definition: qgslayertreemodel.cpp:1355
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
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
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsLayerTreeModelLegendNode::invalidateMapBasedData
virtual void invalidateMapBasedData()
Notification from model that information from associated map view has changed.
Definition: qgslayertreemodellegendnode.h:134
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:146
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:1198
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:1567
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:1009
QgsLayerTreeModel::mLegendMapViewMupp
double mLegendMapViewMupp
Definition: qgslayertreemodel.h:456
QgsLayerItem::iconDefault
static QIcon iconDefault()
Definition: qgsdataitem.cpp:89
QgsGeometry::isNull
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QgsMimeDataUtils::layerTreeNodesToUriList
static QByteArray layerTreeNodesToUriList(const QList< QgsLayerTreeNode * > &nodes)
Returns encoded URI list from a list of layer tree nodes.
Definition: qgsmimedatautils.cpp:249
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:604
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:1056
QgsLayerTreeModel::legendEmbeddedInParent
bool legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Definition: qgslayertreemodel.cpp:1530
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:74
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:366
QgsLayerTreeModel::nodeWillAddChildren
void nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Definition: qgslayertreemodel.cpp:727
QgsMapLayerLegend
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer.
Definition: qgsmaplayerlegend.h:46
QgsLayerTreeModel::mFlags
Flags mFlags
Sets of flags for the model.
Definition: qgslayertreemodel.h:368
QgsLayerTreeModel::mLegendFilterHitTest
std::unique_ptr< QgsMapHitTest > mLegendFilterHitTest
Definition: qgslayertreemodel.h:451
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
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:1260
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsLayerTreeModel::setFlags
void setFlags(QgsLayerTreeModel::Flags f)
Sets OR-ed combination of model flags.
Definition: qgslayertreemodel.cpp:1170
QgsLayerTreeModel::testFlag
bool testFlag(Flag f) const
Check whether a flag is enabled.
Definition: qgslayertreemodel.cpp:1188
QgsLayerTreeModel::mLegendFilterMapSettings
std::unique_ptr< QgsMapSettings > mLegendFilterMapSettings
Definition: qgslayertreemodel.h:450
QgsLayerTreeModel::mFontLayer
QFont mFontLayer
Definition: qgslayertreemodel.h:444
QgsLayerTreeModel::mLegendFilterUsesExtent
bool mLegendFilterUsesExtent
whether to use map filtering
Definition: qgslayertreemodel.h:454
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:75
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:1535
QgsLayerTreeModel::nodeCustomPropertyChanged
void nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Definition: qgslayertreemodel.cpp:794
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:1513
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:1801
QgsLayerTreeModel::layerLegendChanged
void layerLegendChanged()
Definition: qgslayertreemodel.cpp:823
QgsLayerTreeModel::disconnectFromLayer
void disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)
Definition: qgslayertreemodel.cpp:943
QgsMapLayerStyleOverride
Restore overridden layer style on destruction.
Definition: qgsmaplayerstyle.h:82
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:144
QgsVectorLayer::isEditable
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Definition: qgsvectorlayer.cpp:3594
QgsLayerTree::toGroup
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
QgsLayerTreeModel::AllowNodeRename
@ AllowNodeRename
Allow renaming of groups and layers.
Definition: qgslayertreemodel.h:104
QgsLayerTreeModel::disconnectFromLayers
void disconnectFromLayers(QgsLayerTreeGroup *parentGroup)
Definition: qgslayertreemodel.cpp:974
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:250
QgsApplication::getThemePixmap
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
Definition: qgsapplication.cpp:721
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
QgsLayerTreeModelLegendNode::sizeChanged
void sizeChanged()
Emitted when the size of this node changes.
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:722
QgsLayerTreeModel::legendNodeDataChanged
void legendNodeDataChanged()
Definition: qgslayertreemodel.cpp:860
QgsLayerTreeModel::dropMimeData
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Definition: qgslayertreemodel.cpp:1093
QgsLayerTreeModel::layerNeedsUpdate
void layerNeedsUpdate()
Definition: qgslayertreemodel.cpp:842
QgsLayerTreeModel::removeRows
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Definition: qgslayertreemodel.cpp:1159
QgsMapHitTest
Class that runs a hit test with given map settings.
Definition: qgsmaphittest.h:38
QgsLayerTreeModel::legendNode2index
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Returns index for a given legend node.
Definition: qgslayertreemodel.cpp:1419
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:456
QgsMapLayer::isInScaleRange
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
Definition: qgsmaplayer.cpp:671
QgsLayerTreeModel::index2legendNode
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Returns legend node for given index.
Definition: qgslayertreemodel.cpp:1413
QgsVectorLayer::editingStarted
void editingStarted()
Emitted when editing on this layer has started.
QgsLayerTree
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:33
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:579
QgsLayerTreeModel::nodeAddedChildren
void nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
Definition: qgslayertreemodel.cpp:748
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:712
QgsLayerItem::iconPoint
static QIcon iconPoint()
Definition: qgsdataitem.cpp:54
QgsLayerTreeModel::Flag
Flag
Definition: qgslayertreemodel.h:94
QgsLayerTreeModel::mCurrentIndex
QPersistentModelIndex mCurrentIndex
Current index - will be underlined.
Definition: qgslayertreemodel.h:370
QgsLayerTreeModel::connectToLayers
void connectToLayers(QgsLayerTreeGroup *parentGroup)
Definition: qgslayertreemodel.cpp:962
QgsLayerTreeModel::legendParent
QModelIndex legendParent(QgsLayerTreeModelLegendNode *legendNode) const
Definition: qgslayertreemodel.cpp:1493
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:617
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:459
QgsLayerTreeModel::refreshLayerLegend
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
Definition: qgslayertreemodel.cpp:539
QgsLayerTreeModel::legendNodeIndex
QModelIndex legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const
Definition: qgslayertreemodel.cpp:1483
QgsLayerItem::iconVectorTile
static QIcon iconVectorTile()
Returns icon for vector tile layer.
Definition: qgsdataitem.cpp:84
QgsLayerTreeLayer
Layer tree node points to a map layer.
Definition: qgslayertreelayer.h:44
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:326
QgsLayerTreeModel::LayerLegendData
Structure that stores all data associated with one map layer.
Definition: qgslayertreemodel.h:400
QgsLayerTreeModel::mLegendFilterByScale
double mLegendFilterByScale
scale denominator for filtering of legend nodes (<= 0 means no filtering)
Definition: qgslayertreemodel.h:448
QgsLayerTreeGroup
Layer tree group node serves as a container for layers and further groups.
Definition: qgslayertreegroup.h:35
QgsLayerTreeModel::setLegendFilterByMap
void setLegendFilterByMap(const QgsMapSettings *settings)
Force only display of legend nodes which are valid for given map settings.
Definition: qgslayertreemodel.cpp:628
QgsLayerTreeModel::LayerLegendTree
Structure that stores tree representation of map layer's legend.
Definition: qgslayertreemodel.h:386
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
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:293
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
QgsLayerTreeModelLegendNode::ParentRuleKeyRole
@ ParentRuleKeyRole
Rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2....
Definition: qgslayertreemodellegendnode.h:66
QgsLayerTreeModel::refreshScaleBasedLayers
void refreshScaleBasedLayers(const QModelIndex &index=QModelIndex(), double previousScale=0.0)
Updates layer data for scale dependent layers, should be called when map scale changes.
Definition: qgslayertreemodel.cpp:1023
QgsMapLayer::hasScaleBasedVisibility
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
Definition: qgsmaplayer.cpp:678
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:1043
QgsLayerTreeModel::setRootGroup
void setRootGroup(QgsLayerTree *newRootGroup)
Reset the model and use a new root group node.
Definition: qgslayertreemodel.cpp:524
QgsLayerTreeModel::legendIconEmbeddedInParent
QIcon legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Definition: qgslayertreemodel.cpp:1541
QgsLayerItem::iconTable
static QIcon iconTable()
Definition: qgsdataitem.cpp:69
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:64
QgsLayerTreeModel::rootGroup
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non nullptr value.
Definition: qgslayertreemodel.cpp:519
QgsWms::legendNode
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)
Definition: qgswmsgetlegendgraphics.cpp:345
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:705
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:1448
QgsLayerTree::isLayer
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
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:1723
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:79
QgsLayerTreeModel::mimeTypes
QStringList mimeTypes() const override
Definition: qgslayertreemodel.cpp:1048
QgsLayerTreeModel::mLegendMapViewScale
double mLegendMapViewScale
Definition: qgslayertreemodel.h:458
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsLayerTreeModel::setFlag
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
Definition: qgslayertreemodel.cpp:1175
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsLayerTreeModel::legendRootIndex
QModelIndex legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const
Definition: qgslayertreemodel.cpp:1472
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:1183
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsApplication::scaleIconSize
static int scaleIconSize(int standardSize, bool applyDevicePixelRatio=false)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Definition: qgsapplication.cpp:1826
QgsLayerTreeModel::mLegendMapViewDpi
int mLegendMapViewDpi
Definition: qgslayertreemodel.h:457
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:1248
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:633
QgsSymbolLegendNode::data
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
Definition: qgslayertreemodellegendnode.cpp:437
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:688
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:1193
QgsVectorLayer::isModified
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
Definition: qgsvectorlayer.cpp:3621
qgslayertreemodel.h
QgsLayerTreeModel::setData
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Definition: qgslayertreemodel.cpp:392
QgsRenderContext::RenderSymbolPreview
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
Definition: qgsrendercontext.h:83
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:771
QgsLayerTreeModel::invalidateLegendMapBasedData
void invalidateLegendMapBasedData()
Definition: qgslayertreemodel.cpp:1597
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:269
QgsLayerTreeModel::connectToRootNode
void connectToRootNode()
Definition: qgslayertreemodel.cpp:986
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:1745
QgsLayerTreeModel::nodeVisibilityChanged
void nodeVisibilityChanged(QgsLayerTreeNode *node)
Definition: qgslayertreemodel.cpp:776
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:1550
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
The QgsMapSettings class contains configuration for rendering of the map.
Definition: qgsmapsettings.h:88
QgsLayerTreeModel::nodeNameChanged
void nodeNameChanged(QgsLayerTreeNode *node, const QString &name)
Updates model when node's name has changed.
Definition: qgslayertreemodel.cpp:784
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
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
Definition: qgslayertreemodellegendnode.h:292
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:1458
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
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:43
QgsLayerTreeModel::legendInvalidateMapBasedData
void legendInvalidateMapBasedData()
Definition: qgslayertreemodel.cpp:1589
QgsLayerTreeModel::connectToLayer
void connectToLayer(QgsLayerTreeLayer *nodeLayer)
Definition: qgslayertreemodel.cpp:883
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::mInvalidatedNodes
QSet< QgsLayerTreeLayer * > mInvalidatedNodes
Keep track of layer nodes for which the legend size needs to be recalculated.
Definition: qgslayertreemodel.h:442
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:567
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:492
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:1562
QgsMapLayer::type
QgsMapLayerType type
Definition: qgsmaplayer.h:90
QgsLayerTreeModelLegendNode
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
Definition: qgslayertreemodellegendnode.h:51