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