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